Finished implementation

This commit is contained in:
Daniel Gonzalez
2021-09-11 20:32:12 -04:00
parent cf809b3374
commit c3d6f2d748
4 changed files with 390 additions and 125 deletions
+18 -18
View File
@@ -6925,9 +6925,9 @@
}
},
"caniuse-lite": {
"version": "1.0.30001255",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001255.tgz",
"integrity": "sha512-F+A3N9jTZL882f/fg/WWVnKSu6IOo3ueLz4zwaOPbPYHNmM/ZaDUyzyJwS1mZhX7Ex5jqTyW599Gdelh5PDYLQ=="
"version": "1.0.30001256",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001256.tgz",
"integrity": "sha512-QirrvMLmB4txNnxiaG/xbm6FSzv9LqOZ3Jp9VtCYb3oPIfCHpr/oGn38pFq0udwlkctvXQgPthaXqJ76DaYGnA=="
},
"canvas-renderer": {
"version": "2.1.1",
@@ -7770,9 +7770,9 @@
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
},
"contentful-management": {
"version": "7.36.2",
"resolved": "https://registry.npmjs.org/contentful-management/-/contentful-management-7.36.2.tgz",
"integrity": "sha512-pOyHyIuOygqQPDfF9C1MQKTAKAJcounClp4R5afhKkXDdh8jUPc34Ej9BACCtseo99Q9BftLQn49nmk9xJHylQ==",
"version": "7.37.0",
"resolved": "https://registry.npmjs.org/contentful-management/-/contentful-management-7.37.0.tgz",
"integrity": "sha512-5JkDlVttnv1xpNT9Bx+WmiKuTBEo15cUQAd2QNVNZmEbGUyE3P3Q70p7TD5Ef+eOVn00dJtqB/TQ1NyPjbA6kw==",
"requires": {
"@types/json-patch": "0.0.30",
"axios": "^0.21.0",
@@ -9850,9 +9850,9 @@
}
},
"electron-to-chromium": {
"version": "1.3.834",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.834.tgz",
"integrity": "sha512-9hnYJOlj2zbVn59Oy1R2mW/jntsRG7Gy56/aAOq8s29DzDYW/kOrq/ryJXGAQRRMg4MreHjI63XavGZTsnPubg=="
"version": "1.3.836",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.836.tgz",
"integrity": "sha512-Ney3pHOJBWkG/AqYjrW0hr2AUCsao+2uvq9HUlRP8OlpSdk/zOHOUJP7eu0icDvePC9DlgffuelP4TnOJmMRUg=="
},
"electron-webrtc": {
"version": "0.3.0",
@@ -11474,9 +11474,9 @@
"integrity": "sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw=="
},
"fastq": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.12.0.tgz",
"integrity": "sha512-VNX0QkHK3RsXVKr9KrlUv/FoTa0NdbYoHHl7uXHv2rzyHSlxjdNAKug2twd9luJxpcyNeAgf5iPPMutJO67Dfg==",
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
"integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
"requires": {
"reusify": "^1.0.4"
}
@@ -36450,9 +36450,9 @@
}
},
"semver-regex": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.2.tgz",
"integrity": "sha512-bXWyL6EAKOJa81XG1OZ/Yyuq+oT0b2YLlxx7c+mrdYPaPbnj6WgVULXhinMIeZGufuUBu/eVRqXEhiv4imfwxA==",
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.3.tgz",
"integrity": "sha512-Aqi54Mk9uYTjVexLnR67rTyBusmwd04cLkHy9hNvk3+G3nT2Oyg7E0l4XVbOaNwIvQ3hHeYxGcyEy+mKreyBFQ==",
"dev": true
},
"send": {
@@ -39677,9 +39677,9 @@
"optional": true
},
"webpack": {
"version": "5.52.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.52.0.tgz",
"integrity": "sha512-yRZOat8jWGwBwHpco3uKQhVU7HYaNunZiJ4AkAVQkPCUGoZk/tiIXiwG+8HIy/F+qsiZvSOa+GLQOj3q5RKRYg==",
"version": "5.52.1",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.52.1.tgz",
"integrity": "sha512-wkGb0hLfrS7ML3n2xIKfUIwHbjB6gxwQHyLmVHoAqEQBw+nWo+G6LoHL098FEXqahqximsntjBLuewStrnJk0g==",
"requires": {
"@types/eslint-scope": "^3.7.0",
"@types/estree": "^0.0.50",
@@ -1,11 +1,11 @@
import React from 'react'
import { Content, Row, Col, Inputs, Box } from 'adminlte-2-react'
import IPFSTabs from './ipfs-tabs'
import IpfsControl from '../lib/ipfs-control'
import IPFSTabs from './ipfs-tabs'
import CommandRouter from '../lib/commands'
import './ipfs.css'
// const BchWallet = typeof window !== 'undefined' ? window.SlpWallet : null
const { Checkbox } = Inputs
@@ -15,13 +15,21 @@ class IPFS extends React.Component {
constructor (props) {
super(props)
this.state = {
ipfsConnection: false
isStarted: false,
ipfsConnection: false,
appStatusOutput: '',
statusOutput: '',
commandOutput: "Enter 'help' to see available commands.",
commandInput: '',
peers: [],
chatOutputs: {
All: {
output: '',
nickname: ''
}
}
}
_this = this
// Starts ipfs control if there is a wallet registered already
// console.log('props', props)
this.initIPFSControl()
}
@@ -30,36 +38,114 @@ class IPFS extends React.Component {
return (
<Content>
<Row>
<Col sm={2} />
<Col sm={8}>
<Box className='text-center'>
<Col sm={12}>
<Box className="text-center ipfs-checkbox-container">
<Checkbox
id="ipfs-checkbox"
className="ipfs-checkbox"
value={ipfsConnection} // mark as checked
text='Connect to wallet services over IPFS'
labelPosition='none'
text="Connect to wallet services over IPFS"
labelPosition="none"
labelXs={0}
name='ipfsConnection'
name="ipfsConnection"
onChange={this.handleIpfs}
/>
</Box>
</Col>
<Col sm={2} />
</Row>
{ipfsConnection && <IPFSTabs />}
{ipfsConnection && (
<IPFSTabs
ipfsControl={_this.ipfsControl}
handleCommandLog={_this.onCommandLog}
commandOutput={_this.state.commandOutput}
statusOutput={_this.state.statusOutput}
appStatusOutput={_this.state.appStatusOutput}
/>
)}
</Content>
)
}
async componentDidMount () {
await this.ipfsControl.startIpfs()
const nodeInfo = this.ipfsControl.getNodeInfo()
console.log('nodeInfo', nodeInfo)
async handleIpfs () {
const connect = !_this.state.ipfsConnection
const { isStarted } = _this.state
_this.setState(prevState => ({
ipfsConnection: connect
}))
// Save checkbox state into localstorage
const { walletInfo } = _this.props
walletInfo.ipfsService = connect
_this.props.setWalletInfo(walletInfo)
if (!isStarted && connect) {
try {
await _this.ipfsControl.startIpfs()
const nodeInfo = _this.ipfsControl.getNodeInfo()
console.log('nodeInfo', nodeInfo)
_this.setState({
isStarted: true
})
} catch (error) {
console.warn(error.message)
}
}
}
handleIpfs () {
_this.setState(prevState => ({
ipfsConnection: !_this.state.ipfsConnection
}))
async componentDidMount () {
await _this.getLastIpfsCoordInstance()
}
async componentWillUnmount () {
try {
const data = {
ipfsInfo: {
ipfsIsStarted: true,
savedState: _this.state,
ipfsControl: _this.ipfsControl
}
}
// Save the current state
_this.props.setMenuNavigation({ data })
} catch (error) {
console.warn(error)
}
}
async getLastIpfsCoordInstance () {
try {
const { menuNavigation, walletInfo } = _this.props
const data = menuNavigation.data
// console.log('menuNavigation', menuNavigation)
// console.log('walletInfo', walletInfo)
// console.log('data', data)
// Get local info and
// Verify if checkbox has been marked
// Return for unmarked checkbox
if (!walletInfo.ipfsService) return
_this.setState(prevState => ({
ipfsConnection: true
}))
// Don't start ipfs if it has started already
if (!data || !data.ipfsInfo.ipfsIsStarted) {
await this.ipfsControl.startIpfs()
_this.setState({
isStarted: true
})
}
// Loads the previous information and states
if (data && data.ipfsInfo) {
const { savedState } = data.ipfsInfo
_this.setState(savedState)
}
} catch (error) {
console.warn(error)
}
}
initIPFSControl (bchWallet) {
@@ -76,35 +162,19 @@ class IPFS extends React.Component {
if (
menuNavigation &&
menuNavigation.data &&
menuNavigation.data.chatInfo.ipfsControl
menuNavigation.data.ipfsInfo.ipfsControl
) {
this.ipfsControl = menuNavigation.data.chatInfo.ipfsControl
this.ipfsControl = menuNavigation.data.ipfsInfo.ipfsControl
} else {
// Instantiate a new ipfs control
this.ipfsControl = new IpfsControl(ipfsConfig)
}
this.commandRouter = new CommandRouter({ ipfsControl: this.ipfsControl })
} catch (err) {
console.error(err)
}
}
// Adds a line to the Command terminal
onCommandLog (msg) {
try {
let commandOutput
if (!msg) {
commandOutput = ''
} else {
commandOutput = _this.state.commandOutput + ' ' + msg + '\n'
}
_this.setState({
commandOutput
})
} catch (error) {
console.warn(error)
}
}
// Adds a line to the Status terminal
onStatusLog (str) {
try {
@@ -123,27 +193,6 @@ class IPFS extends React.Component {
}
}
// Handle decrypted, private messages and send them to the right terminal.
privLogChat (str, from) {
try {
// console.log(`privLogChat str: ${str}`)
// console.log(`privLogChat from: ${from}`)
const { chatOutputs } = _this.state
const terminalOut = `peer: ${str}`
// Asigns the output to the corresponding peer
chatOutputs[from].output = chatOutputs[from].output + terminalOut + '\n'
_this.setState({
chatOutputs
})
} catch (err) {
console.warn('Error in privLogChat():', err)
}
}
// Handle chat messages coming in from the IPFS network.
incommingChat (str) {
try {
@@ -173,6 +222,93 @@ class IPFS extends React.Component {
// Don't throw an error as this is a top-level handler.
}
}
// Handle decrypted, private messages and send them to the right terminal.
privLogChat (str, from) {
try {
// console.log(`privLogChat str: ${str}`)
// console.log(`privLogChat from: ${from}`)
const { chatOutputs } = _this.state
const terminalOut = `peer: ${str}`
// Asigns the output to the corresponding peer
chatOutputs[from].output = chatOutputs[from].output + terminalOut + '\n'
_this.setState({
chatOutputs
})
} catch (err) {
console.warn('Error in privLogChat():', err)
}
}
// This function is triggered when a new peer is detected.
handleNewPeer (ipfsId) {
try {
console.log(`New IPFS peer discovered. ID: ${ipfsId}`)
// Use the peer IPFS ID to identify the peers state.
const { peers, chatOutputs } = _this.state
// Add the new peer to the peers array.
peers.push(ipfsId)
// Add a chatOutput entry for the new peer.
const obj = {
output: '',
nickname: ''
}
// chatOutputs[shortIpfsId] = obj
chatOutputs[ipfsId] = obj
_this.setState({
peers,
chatOutputs
})
} catch (err) {
console.warn('Error in handleNewPeer(): ', err)
}
}
// Adds a line to the Command terminal
onCommandLog (msg) {
try {
let commandOutput
if (!msg) {
commandOutput = ''
} else {
commandOutput = _this.state.commandOutput + ' ' + msg + '\n'
}
_this.setState({
commandOutput
})
} catch (error) {
console.warn(error)
}
}
onAppStatus (msg) {
try {
let output
if (!msg) {
output = ''
} else {
output = _this.state.appStatusOutput + ' ' + msg + '\n'
}
_this.setState({
appStatusOutput: output
})
} catch (error) {
console.warn(error)
// Don't throw an error as this is a top-level handler.
}
}
sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
}
IPFS.propTypes = {}
@@ -1,65 +1,180 @@
import React from 'react'
import { Tabs, Row, Col, TabContent } from 'adminlte-2-react'
import { Row, Col, Inputs } from 'adminlte-2-react'
import { Tabs, Tab } from 'react-bootstrap'
import PropTypes from 'prop-types'
import CommandRouter from '../lib/commands'
import 'adminlte-2-react/src/adminlte/css/AdminLTE.css'
const { Text } = Inputs
let _this
class IPFSTabs extends React.Component {
constructor (props) {
super(props)
this.state = {}
this.state = {
commandOutput: "Enter 'help' to see available commands."
}
_this = this
// Starts ipfs control if there is a wallet registered already
// console.log('props', props)
if (props && props.ipfsControl) {
this.ipfsControl = props.ipfsControl
this.commandRouter = new CommandRouter({ ipfsControl: this.ipfsControl })
// console.log('this.commandRouter: ', this.commandRouter)
}
}
render () {
const { commandOutput } = _this.state
const { statusOutput, appStatusOutput } = _this.props
return (
<Row>
<Col md={12}>
<Tabs defaultActiveKey='tab_1' activeKey='tab_2'>
<TabContent title='Tab 1' eventKey='tab_1'>
<b>How to use:</b>
<p>
Exactly like the original bootstrap tabs except you should use
the custom wrapper <code>.nav-tabs-custom</code> to achieve this
style.
</p>
A wonderful serenity has taken possession of my entire soul, like
these sweet mornings of spring which I enjoy with my whole heart.
I am alone, and feel the charm of existence in this spot, which
was created for the bliss of souls like mine. I am so happy, my
dear friend, so absorbed in the exquisite sense of mere tranquil
existence, that I neglect my talents. I should be incapable of
drawing a single stroke at the present moment; and yet I feel that
I never was a greater artist than now.
</TabContent>
<TabContent title='Tab 2' eventKey='tab_2'>
The European languages are members of the same family. Their
separate existence is a myth. For science, music, sport, etc,
Europe uses the same vocabulary. The languages only differ in
their grammar, their pronunciation and their most common words.
Everyone realizes why a new common language would be desirable:
one could refuse to pay expensive translators. To achieve this, it
would be necessary to have uniform grammar, pronunciation and more
common words. If several languages coalesce, the grammar of the
resulting language is more simple and regular than that of the
individual languages.
</TabContent>
<TabContent title='Tab 3' eventKey='tab_3'>
Lorem Ipsum is simply dummy text of the printing and typesetting
industry. Lorem Ipsum has been the industry&quot;s standard dummy
text ever since the 1500s, when an unknown printer took a galley
of type and scrambled it to make a type specimen book. It has
survived not only five centuries, but also the leap into
electronic typesetting, remaining essentially unchanged. It was
popularised in the 1960s with the release of Letraset sheets
containing Lorem Ipsum passages, and more recently with desktop
publishing software like Aldus PageMaker including versions of
Lorem Ipsum.
</TabContent>
<Tabs
defaultActiveKey="status"
id="ipfs-coord-tabs"
className="mb-3 nav-tabs-custom"
>
<Tab eventKey="status" title="Status">
<Text
id="statusLog"
name="statusLog"
inputType="textarea"
labelPosition="none"
rows={20}
readOnly
value={appStatusOutput}
onChange={() => {
// Prevents DOM error
}}
/>
</Tab>
<Tab eventKey="ipfs-coord" title="IPFS Coord">
<Text
id="ipfsCoordLog"
name="ipfsCoordLog"
inputType="textarea"
labelPosition="none"
rows={20}
readOnly
value={statusOutput}
onChange={() => {
// Prevents DOM error
}}
/>
</Tab>
<Tab eventKey="command" title="Command">
<Text
id="commandLog"
name="commandLog"
inputType="textarea"
labelPosition="none"
rows={20}
readOnly
value={`${commandOutput ? `${commandOutput}>` : '>'}`}
onChange={() => {
// Prevents DOM error
}}
/>
<Text
id="commandInput"
name="commandInput"
inputType="tex"
labelPosition="none"
value={this.state.commandInput}
onChange={this.handleTextInput}
onKeyDown={_this.handleCommandKeyDown}
/>
</Tab>
</Tabs>
</Col>
</Row>
)
}
// Handles text typed into the input box.
handleTextInput (event) {
event.preventDefault()
const target = event.target
const value = target.value
const name = target.name
// console.log('value: ', value)
_this.setState({
[name]: value
})
}
componentDidUpdate () {
if (_this.state.commandOutput !== _this.props.commandOutput) {
_this.setState({
commandOutput: _this.props.commandOutput
})
}
}
/* START command handling functions */
// Handles when the Enter key is pressed while in the chat input box.
async handleCommandKeyDown (e) {
if (e.key === 'Enter') {
// _this.submitMsg()
// console.log("Enter key");
// Send a chat message to the chat pubsub room.
// const now = new Date();
// const msg = `Message from BROWSER at ${now.toLocaleString()}`
const msg = _this.state.commandInput
// console.log(`Sending this message: ${msg}`);
// _this.handleCommandLog(`me: ${msg}`);
// console.log('_this.commandRouter: ', _this.commandRouter)
const outMsg = await _this.commandRouter.route(msg, _this.ipfsControl)
if (outMsg === 'clear') {
_this.props.handleCommandLog('')
} else {
_this.handleCommandLog(`\n${outMsg}`)
}
// Clear the input text box.
_this.setState({
commandInput: ''
})
}
}
// Adds a line to the terminal
async handleCommandLog (msg) {
try {
// console.log("msg: ", msg);
_this.props.handleCommandLog(msg)
// Add a slight delay, to give the browser time to render the DOM.
await this.sleep(250)
// _this.keepScrolled();
// _this.keepCommandScrolled()
} catch (error) {
console.warn(error)
}
}
sleep (ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
}
IPFSTabs.propTypes = {}
IPFSTabs.propTypes = {
handleCommandLog: PropTypes.func,
commandOutput: PropTypes.string,
statusOutput: PropTypes.string,
appStatusOutput: PropTypes.string
}
export default IPFSTabs
@@ -0,0 +1,14 @@
.ipfs-checkbox-container > div > div > div >input{
height: 1em;
width: 1em;
cursor: pointer;
margin-right: 5px;
}
.ipfs-checkbox-container > div > div > div {
display: flex;
justify-content: center;
align-items: center;
}