2019-07-24 17:10:44 +00:00
|
|
|
import React from 'react';
|
|
|
|
import { Client } from 'rpc-websockets'
|
2019-07-24 18:42:02 +00:00
|
|
|
import Cristal from 'react-cristal'
|
2019-07-25 17:06:10 +00:00
|
|
|
import { BlockLinks } from "./BlockLink";
|
2019-07-30 23:18:21 +00:00
|
|
|
import StorageNodeInit from "./StorageNodeInit";
|
2019-07-24 17:10:44 +00:00
|
|
|
|
|
|
|
const stateConnected = 'connected'
|
|
|
|
const stateConnecting = 'connecting'
|
|
|
|
const stateGettingToken = 'getting-token'
|
|
|
|
|
2019-07-25 14:57:30 +00:00
|
|
|
async function awaitListReducer(prev, c) {
|
|
|
|
return [...await prev, await c]
|
|
|
|
}
|
|
|
|
|
2019-07-25 15:13:45 +00:00
|
|
|
function truncAddr(addr) {
|
|
|
|
if (addr.length > 41) {
|
|
|
|
return <abbr title={addr}>{addr.substr(0, 38) + '...'}</abbr>
|
|
|
|
}
|
|
|
|
return addr
|
|
|
|
}
|
|
|
|
|
2019-07-24 17:10:44 +00:00
|
|
|
class FullNode extends React.Component {
|
|
|
|
constructor(props) {
|
|
|
|
super(props)
|
|
|
|
|
|
|
|
this.state = {
|
2019-07-24 18:42:02 +00:00
|
|
|
state: stateGettingToken,
|
2019-07-24 22:30:17 +00:00
|
|
|
id: "~",
|
|
|
|
|
|
|
|
mining: false,
|
2019-07-24 17:10:44 +00:00
|
|
|
}
|
|
|
|
|
2019-07-24 22:30:17 +00:00
|
|
|
this.loadInfo = this.loadInfo.bind(this)
|
|
|
|
this.startMining = this.startMining.bind(this)
|
2019-07-30 23:18:21 +00:00
|
|
|
this.newScepAddr = this.newScepAddr.bind(this)
|
|
|
|
this.startStorageMiner = this.startStorageMiner.bind(this)
|
2019-07-24 17:10:44 +00:00
|
|
|
|
|
|
|
this.connect()
|
|
|
|
}
|
|
|
|
|
|
|
|
async connect() {
|
|
|
|
console.log("gettok")
|
|
|
|
|
|
|
|
const token = await this.props.pondClient.call('Pond.TokenFor', [this.props.node.ID])
|
|
|
|
|
|
|
|
this.setState(() => ({
|
|
|
|
state: stateConnecting,
|
|
|
|
token: token,
|
|
|
|
}))
|
|
|
|
|
2019-07-24 21:28:51 +00:00
|
|
|
const client = new Client(`ws://127.0.0.1:${this.props.node.ApiPort}/rpc/v0?token=${token}`)
|
2019-07-25 00:55:19 +00:00
|
|
|
client.on('open', async () => {
|
2019-07-24 17:10:44 +00:00
|
|
|
this.setState(() => ({
|
|
|
|
state: stateConnected,
|
|
|
|
client: client,
|
|
|
|
|
|
|
|
version: {Version: "~version~"},
|
|
|
|
id: "~peerid~",
|
2019-07-25 14:57:30 +00:00
|
|
|
peers: -1,
|
|
|
|
balances: []
|
2019-07-24 17:10:44 +00:00
|
|
|
}))
|
|
|
|
|
2019-07-25 00:55:19 +00:00
|
|
|
const id = await this.state.client.call("Filecoin.ID", [])
|
|
|
|
this.setState(() => ({id: id}))
|
|
|
|
|
|
|
|
this.props.onConnect(client, id)
|
2019-07-24 20:00:11 +00:00
|
|
|
|
2019-07-24 17:10:44 +00:00
|
|
|
this.loadInfo()
|
2019-07-25 14:57:30 +00:00
|
|
|
setInterval(this.loadInfo, 2050)
|
2019-07-24 17:10:44 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
console.log(token) // todo: use
|
|
|
|
}
|
|
|
|
|
|
|
|
async loadInfo() {
|
|
|
|
const version = await this.state.client.call("Filecoin.Version", [])
|
|
|
|
this.setState(() => ({version: version}))
|
|
|
|
|
|
|
|
const peers = await this.state.client.call("Filecoin.NetPeers", [])
|
|
|
|
this.setState(() => ({peers: peers.length}))
|
2019-07-24 22:14:09 +00:00
|
|
|
|
|
|
|
const tipset = await this.state.client.call("Filecoin.ChainHead", [])
|
|
|
|
this.setState(() => ({tipset: tipset}))
|
2019-07-25 14:57:30 +00:00
|
|
|
|
|
|
|
const addrss = await this.state.client.call('Filecoin.WalletList', [])
|
2019-07-25 23:26:40 +00:00
|
|
|
let defaultAddr = ""
|
|
|
|
if (addrss.length > 0) {
|
|
|
|
defaultAddr = await this.state.client.call('Filecoin.WalletDefaultAddress', [])
|
|
|
|
}
|
2019-07-25 14:57:30 +00:00
|
|
|
|
|
|
|
const balances = await addrss.map(async addr => {
|
2019-07-25 15:13:45 +00:00
|
|
|
let balance = 0
|
|
|
|
try {
|
|
|
|
balance = await this.state.client.call('Filecoin.WalletBalance', [addr])
|
|
|
|
} catch {
|
|
|
|
balance = -1
|
|
|
|
}
|
2019-07-25 14:57:30 +00:00
|
|
|
return [addr, balance]
|
|
|
|
}).reduce(awaitListReducer, Promise.resolve([]))
|
|
|
|
|
2019-07-25 15:13:45 +00:00
|
|
|
this.setState(() => ({balances: balances, defaultAddr: defaultAddr}))
|
2019-07-24 17:10:44 +00:00
|
|
|
}
|
|
|
|
|
2019-07-24 22:30:17 +00:00
|
|
|
async startMining() {
|
|
|
|
// TODO: Use actual miner address
|
|
|
|
// see cli/miner.go
|
2019-07-30 23:18:21 +00:00
|
|
|
this.setState({mining: true})
|
2019-07-26 16:14:01 +00:00
|
|
|
let addr = "t0523423423" // in case we have no wallets
|
|
|
|
if (this.state.defaultAddr) {
|
|
|
|
addr = this.state.defaultAddr
|
|
|
|
}
|
|
|
|
|
2019-07-24 22:30:17 +00:00
|
|
|
this.setState({mining: true})
|
2019-07-26 16:14:01 +00:00
|
|
|
await this.state.client.call("Filecoin.MinerStart", [addr])
|
2019-07-24 22:30:17 +00:00
|
|
|
}
|
|
|
|
|
2019-07-30 23:18:21 +00:00
|
|
|
async newScepAddr() {
|
|
|
|
const t = "secp256k1"
|
|
|
|
await this.state.client.call("Filecoin.WalletNew", [t])
|
|
|
|
this.loadInfo()
|
|
|
|
}
|
|
|
|
|
|
|
|
async startStorageMiner() {
|
|
|
|
this.props.mountWindow((onClose) => <StorageNodeInit fullRepo={this.props.node.Repo} fullConn={this.props.conn} pondClient={this.props.pondClient} onClose={onClose} mountWindow={this.props.mountWindow}/>)
|
|
|
|
}
|
|
|
|
|
2019-07-24 17:10:44 +00:00
|
|
|
render() {
|
|
|
|
let runtime = <div></div>
|
|
|
|
if (this.state.state === stateConnected) {
|
2019-07-24 22:14:09 +00:00
|
|
|
let chainInfo = <div></div>
|
|
|
|
if (this.state.tipset !== undefined) {
|
|
|
|
chainInfo = (
|
2019-07-25 16:13:46 +00:00
|
|
|
<div>
|
|
|
|
Head: {
|
2019-07-25 17:06:10 +00:00
|
|
|
<BlockLinks cids={this.state.tipset.Cids} conn={this.state.client} mountWindow={this.props.mountWindow} />
|
2019-07-25 16:13:46 +00:00
|
|
|
} H:{this.state.tipset.Height}
|
|
|
|
</div>
|
2019-07-24 22:14:09 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-07-25 16:13:46 +00:00
|
|
|
let mine = <a href="#" disabled={this.state.mining} onClick={this.startMining}>[Mine]</a>
|
2019-07-24 23:46:48 +00:00
|
|
|
if (this.state.mining) {
|
2019-07-25 16:13:46 +00:00
|
|
|
mine = "[Mining]"
|
2019-07-24 23:46:48 +00:00
|
|
|
}
|
|
|
|
|
2019-07-30 23:18:21 +00:00
|
|
|
let storageMine = <a href="#" onClick={this.startStorageMiner}>[Spawn Storage Miner]</a>
|
|
|
|
|
2019-07-25 15:13:45 +00:00
|
|
|
let balances = this.state.balances.map(([addr, balance]) => {
|
|
|
|
let line = <span>{truncAddr(addr)}: {balance} (ActTyp)</span>
|
|
|
|
if (this.state.defaultAddr === addr) {
|
|
|
|
line = <b>{line}</b>
|
|
|
|
}
|
|
|
|
return <div>{line}</div>
|
|
|
|
})
|
2019-07-25 14:57:30 +00:00
|
|
|
|
2019-07-24 17:10:44 +00:00
|
|
|
runtime = (
|
|
|
|
<div>
|
2019-07-25 16:13:46 +00:00
|
|
|
<div>v{this.state.version.Version}, <abbr title={this.state.id}>{this.state.id.substr(-8)}</abbr>, {this.state.peers} peers</div>
|
2019-07-24 22:14:09 +00:00
|
|
|
<div>Repo: LOTUS_PATH={this.props.node.Repo}</div>
|
|
|
|
{chainInfo}
|
2019-07-25 14:57:30 +00:00
|
|
|
<div>
|
2019-07-30 23:18:21 +00:00
|
|
|
{mine} {storageMine}
|
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
<div>Balances: [New <a href="#" onClick={this.newScepAddr}>[Secp256k1]</a>]</div>
|
2019-07-25 14:57:30 +00:00
|
|
|
<div>{balances}</div>
|
|
|
|
</div>
|
2019-07-24 22:14:09 +00:00
|
|
|
|
2019-07-24 17:10:44 +00:00
|
|
|
</div>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
2019-07-24 18:42:02 +00:00
|
|
|
<Cristal
|
|
|
|
title={"Node " + this.props.node.ID}
|
|
|
|
initialPosition={{x: this.props.node.ID*30, y: this.props.node.ID * 30}} >
|
2019-07-25 14:57:30 +00:00
|
|
|
<div className="CristalScroll">
|
|
|
|
<div className="FullNode">
|
|
|
|
<div>{this.props.node.ID} - {this.state.state}</div>
|
|
|
|
{runtime}
|
|
|
|
</div>
|
2019-07-24 18:42:02 +00:00
|
|
|
</div>
|
|
|
|
</Cristal>
|
2019-07-24 17:10:44 +00:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default FullNode
|