2019-07-24 17:10:44 +00:00
|
|
|
import React from 'react';
|
|
|
|
import FullNode from "./FullNode";
|
2019-07-24 18:42:02 +00:00
|
|
|
import ConnMgr from "./ConnMgr";
|
2019-07-25 16:13:46 +00:00
|
|
|
import Consensus from "./Consensus";
|
2019-07-30 23:39:30 +00:00
|
|
|
import StorageNode from "./StorageNode";
|
2019-08-09 15:59:12 +00:00
|
|
|
import {Client} from "rpc-websockets";
|
|
|
|
import pushMessage from "./chain/send";
|
2019-08-19 21:30:46 +00:00
|
|
|
import Logs from "./Logs";
|
2019-09-09 16:01:53 +00:00
|
|
|
import StorageNodeInit from "./StorageNodeInit";
|
2019-09-19 14:27:01 +00:00
|
|
|
import Window from "./Window";
|
2019-07-24 17:10:44 +00:00
|
|
|
|
2019-09-17 12:03:28 +00:00
|
|
|
const [NodeUnknown, NodeRunning, NodeStopped] = [0, 1, 2]
|
|
|
|
|
2019-07-24 17:10:44 +00:00
|
|
|
class NodeList extends React.Component {
|
|
|
|
constructor(props) {
|
2019-07-24 18:42:02 +00:00
|
|
|
super(props)
|
2019-07-24 17:10:44 +00:00
|
|
|
this.state = {
|
|
|
|
existingLoaded: false,
|
2019-07-24 20:00:11 +00:00
|
|
|
nodes: {},
|
2019-07-24 18:42:02 +00:00
|
|
|
|
|
|
|
showConnMgr: false,
|
2019-07-25 16:13:46 +00:00
|
|
|
showConsensus: false,
|
2019-07-24 18:42:02 +00:00
|
|
|
}
|
2019-07-24 17:10:44 +00:00
|
|
|
|
|
|
|
// This binding is necessary to make `this` work in the callback
|
2019-07-24 18:42:02 +00:00
|
|
|
this.spawnNode = this.spawnNode.bind(this)
|
2019-09-09 16:01:53 +00:00
|
|
|
this.spawnStorageNode = this.spawnStorageNode.bind(this)
|
2019-07-24 18:42:02 +00:00
|
|
|
this.connMgr = this.connMgr.bind(this)
|
2019-07-25 16:13:46 +00:00
|
|
|
this.consensus = this.consensus.bind(this)
|
2019-09-24 10:30:48 +00:00
|
|
|
this.transferNFrom1 = this.transferNFrom1.bind(this)
|
2019-07-24 17:10:44 +00:00
|
|
|
|
2019-07-24 20:00:11 +00:00
|
|
|
this.getNodes()
|
|
|
|
}
|
|
|
|
|
2019-08-09 15:59:12 +00:00
|
|
|
async mountNode(node) {
|
|
|
|
const token = await this.props.client.call('Pond.TokenFor', [node.ID])
|
|
|
|
|
|
|
|
const client = new Client(`ws://127.0.0.1:${node.ApiPort}/rpc/v0?token=${token}`)
|
|
|
|
client.on('open', async () => {
|
|
|
|
const id = await client.call("Filecoin.ID", [])
|
|
|
|
|
|
|
|
this.setState(prev => ({
|
|
|
|
nodes: {
|
|
|
|
...prev.nodes,
|
|
|
|
[node.ID]: {...node, conn: client, peerid: id}
|
|
|
|
}
|
|
|
|
}))
|
|
|
|
|
|
|
|
if (!node.Storage) {
|
|
|
|
this.props.mountWindow((onClose) =>
|
|
|
|
<FullNode key={node.ID}
|
|
|
|
node={{...node}}
|
|
|
|
client={client}
|
|
|
|
pondClient={this.props.client}
|
2019-09-24 10:30:48 +00:00
|
|
|
giveN={this.transferNFrom1}
|
2019-09-09 16:01:53 +00:00
|
|
|
mountWindow={this.props.mountWindow}
|
|
|
|
spawnStorageNode={this.spawnStorageNode}
|
2019-09-17 12:03:28 +00:00
|
|
|
stop={this.stopNode(node.ID, onClose)}
|
2019-09-09 16:01:53 +00:00
|
|
|
/>)
|
2019-08-09 15:59:12 +00:00
|
|
|
} else {
|
2019-09-09 16:01:53 +00:00
|
|
|
const fullId = await this.props.client.call('Pond.FullID', [node.ID])
|
|
|
|
|
2019-08-09 15:59:12 +00:00
|
|
|
this.props.mountWindow((onClose) =>
|
|
|
|
<StorageNode node={{...node}}
|
|
|
|
pondClient={this.props.client}
|
2019-09-09 16:01:53 +00:00
|
|
|
fullConn={this.state.nodes[fullId].conn}
|
|
|
|
mountWindow={this.props.mountWindow}
|
2019-09-17 12:53:43 +00:00
|
|
|
stop={this.stopNode(node.ID, onClose)}
|
2019-09-09 16:01:53 +00:00
|
|
|
/>)
|
2019-08-09 15:59:12 +00:00
|
|
|
}
|
|
|
|
})
|
2019-07-30 23:39:30 +00:00
|
|
|
}
|
|
|
|
|
2019-07-24 20:00:11 +00:00
|
|
|
async getNodes() {
|
|
|
|
const nds = await this.props.client.call('Pond.Nodes')
|
|
|
|
const nodes = nds.reduce((o, i) => {o[i.ID] = i; return o}, {})
|
|
|
|
console.log('nds', nodes)
|
2019-07-30 23:39:30 +00:00
|
|
|
|
2019-09-17 12:03:28 +00:00
|
|
|
Object.keys(nodes).map(n => nodes[n]).filter(n => n.State === NodeRunning).forEach(n => this.mountNode(n))
|
2019-07-30 23:39:30 +00:00
|
|
|
|
2019-07-24 20:00:11 +00:00
|
|
|
this.setState({existingLoaded: true, nodes: nodes})
|
2019-07-24 17:10:44 +00:00
|
|
|
}
|
|
|
|
|
2019-09-24 10:30:48 +00:00
|
|
|
async transferNFrom1(to, n) {
|
2019-08-09 15:59:12 +00:00
|
|
|
const addrss = await this.state.nodes[1].conn.call('Filecoin.WalletList', [])
|
|
|
|
const [bestaddr, bal] = await addrss.map(async addr => {
|
|
|
|
let balance = 0
|
|
|
|
try {
|
|
|
|
balance = await this.state.nodes[1].conn.call('Filecoin.WalletBalance', [addr])
|
|
|
|
} catch {
|
|
|
|
balance = -1
|
|
|
|
}
|
|
|
|
return [addr, balance]
|
|
|
|
}).reduce(async (c, n) => (await c)[1] > (await n)[1] ? await c : await n, Promise.resolve(['', -2]))
|
|
|
|
|
2019-09-06 22:35:31 +00:00
|
|
|
await pushMessage(this.state.nodes[1].conn, bestaddr, {
|
2019-08-09 15:59:12 +00:00
|
|
|
To: to,
|
|
|
|
From: bestaddr,
|
2019-09-24 10:30:48 +00:00
|
|
|
Value: String(n),
|
2019-08-09 15:59:12 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-07-24 17:10:44 +00:00
|
|
|
async spawnNode() {
|
|
|
|
const node = await this.props.client.call('Pond.Spawn')
|
|
|
|
console.log(node)
|
2019-08-09 15:59:12 +00:00
|
|
|
await this.mountNode(node)
|
2019-07-30 23:25:31 +00:00
|
|
|
|
2019-07-24 20:00:11 +00:00
|
|
|
this.setState(state => ({nodes: {...state.nodes, [node.ID]: node}}))
|
2019-07-24 17:10:44 +00:00
|
|
|
}
|
|
|
|
|
2019-09-09 16:01:53 +00:00
|
|
|
async spawnStorageNode(fullRepo, fullConn) {
|
|
|
|
let nodePromise = this.props.client.call('Pond.SpawnStorage', [fullRepo])
|
|
|
|
|
|
|
|
this.props.mountWindow((onClose) => <StorageNodeInit node={nodePromise} fullRepo={fullRepo} fullConn={fullConn} pondClient={this.props.client} onClose={onClose} mountWindow={this.props.mountWindow}/>)
|
|
|
|
let node = await nodePromise
|
|
|
|
await this.mountNode(node)
|
|
|
|
|
|
|
|
//this.setState(state => ({nodes: {...state.nodes, [node.ID]: node}}))
|
|
|
|
}
|
|
|
|
|
2019-09-17 12:03:28 +00:00
|
|
|
stopNode = (id, closeWindow) => async () => {
|
|
|
|
this.state.nodes[id].conn.close()
|
|
|
|
await this.props.client.call('Pond.Stop', [id])
|
|
|
|
closeWindow()
|
|
|
|
this.setState(prev => ({
|
|
|
|
nodes: {
|
|
|
|
...prev.nodes,
|
|
|
|
[id]: {...(prev.nodes[id]), State: NodeStopped, conn: undefined}
|
|
|
|
}
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
|
|
|
startNode = (id) => async () => {
|
2019-09-17 12:36:17 +00:00
|
|
|
let node = await this.props.client.call('Pond.RestartNode', [Number(id)])
|
|
|
|
await this.mountNode(node)
|
2019-09-17 12:03:28 +00:00
|
|
|
}
|
|
|
|
|
2019-07-24 18:42:02 +00:00
|
|
|
connMgr() {
|
|
|
|
this.setState({showConnMgr: true})
|
|
|
|
}
|
|
|
|
|
2019-07-25 16:13:46 +00:00
|
|
|
consensus() {
|
|
|
|
this.setState({showConsensus: true})
|
|
|
|
}
|
|
|
|
|
2019-07-24 17:10:44 +00:00
|
|
|
render() {
|
2019-07-24 18:42:02 +00:00
|
|
|
let connMgr
|
|
|
|
if (this.state.showConnMgr) {
|
|
|
|
connMgr = (<ConnMgr nodes={this.state.nodes}/>)
|
|
|
|
}
|
|
|
|
|
2019-07-25 16:13:46 +00:00
|
|
|
let consensus
|
|
|
|
if (this.state.showConsensus) {
|
2019-07-30 23:21:57 +00:00
|
|
|
consensus = (<Consensus nodes={this.state.nodes} mountWindow={this.props.mountWindow}/>)
|
2019-07-25 16:13:46 +00:00
|
|
|
}
|
|
|
|
|
2019-07-24 17:10:44 +00:00
|
|
|
return (
|
2019-09-19 14:27:01 +00:00
|
|
|
<Window title={"Node List"} initialPosition="bottom-left">
|
2019-07-30 23:53:24 +00:00
|
|
|
<div className={'NodeList'}>
|
|
|
|
<div>
|
|
|
|
<button onClick={this.spawnNode} disabled={!this.state.existingLoaded}>Spawn Node</button>
|
|
|
|
<button onClick={this.connMgr} disabled={!this.state.existingLoaded && !this.state.showConnMgr}>Connections</button>
|
|
|
|
<button onClick={this.consensus} disabled={!this.state.existingLoaded && !this.state.showConsensus}>Consensus</button>
|
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
{Object.keys(this.state.nodes).map(n => {
|
|
|
|
const nd = this.state.nodes[n]
|
|
|
|
let type = "FULL"
|
|
|
|
if (nd.Storage) {
|
|
|
|
type = "STOR"
|
|
|
|
}
|
|
|
|
|
2019-08-19 21:30:46 +00:00
|
|
|
let logs = "[logs]"
|
2019-07-30 23:53:24 +00:00
|
|
|
let info = "[CONNECTING..]"
|
|
|
|
if (nd.conn) {
|
|
|
|
info = <span>{nd.peerid}</span>
|
2019-08-19 21:30:46 +00:00
|
|
|
logs = <a href='#' onClick={() => this.props.mountWindow(cl => <Logs node={nd.ID} onClose={cl}/>)}>[logs]</a>
|
2019-07-30 23:53:24 +00:00
|
|
|
}
|
2019-09-17 12:03:28 +00:00
|
|
|
if (nd.State === NodeStopped) {
|
|
|
|
info = <span>[stopped] <a href="#" onClick={this.startNode(n)}>[START]</a></span>
|
|
|
|
}
|
2019-07-30 23:53:24 +00:00
|
|
|
|
|
|
|
return <div key={n}>
|
2019-08-19 21:30:46 +00:00
|
|
|
{n} {type} {logs} {info}
|
2019-07-30 23:53:24 +00:00
|
|
|
</div>
|
|
|
|
})}
|
|
|
|
</div>
|
2019-07-30 23:39:30 +00:00
|
|
|
</div>
|
2019-07-24 17:10:44 +00:00
|
|
|
<div>
|
2019-07-24 18:42:02 +00:00
|
|
|
{connMgr}
|
2019-07-25 16:13:46 +00:00
|
|
|
{consensus}
|
2019-07-24 17:10:44 +00:00
|
|
|
</div>
|
2019-09-19 14:27:01 +00:00
|
|
|
</Window>
|
2019-07-24 17:10:44 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default NodeList
|