pond: Allow to stop full nodes
This commit is contained in:
parent
fc5c455cf7
commit
76177907f2
@ -17,9 +17,17 @@ import (
|
|||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type NodeState int
|
||||||
|
|
||||||
|
const (
|
||||||
|
NodeUnknown = iota
|
||||||
|
NodeRunning
|
||||||
|
NodeStopped
|
||||||
|
)
|
||||||
|
|
||||||
type api struct {
|
type api struct {
|
||||||
cmds int32
|
cmds int32
|
||||||
running map[int32]runningNode
|
running map[int32]*runningNode
|
||||||
runningLk sync.Mutex
|
runningLk sync.Mutex
|
||||||
genesis string
|
genesis string
|
||||||
}
|
}
|
||||||
@ -28,6 +36,7 @@ type nodeInfo struct {
|
|||||||
Repo string
|
Repo string
|
||||||
ID int32
|
ID int32
|
||||||
ApiPort int32
|
ApiPort int32
|
||||||
|
State NodeState
|
||||||
|
|
||||||
FullNode string // only for storage nodes
|
FullNode string // only for storage nodes
|
||||||
Storage bool
|
Storage bool
|
||||||
@ -80,18 +89,27 @@ func (api *api) Spawn() (nodeInfo, error) {
|
|||||||
Repo: dir,
|
Repo: dir,
|
||||||
ID: id,
|
ID: id,
|
||||||
ApiPort: 2500 + id,
|
ApiPort: 2500 + id,
|
||||||
|
State: NodeRunning,
|
||||||
}
|
}
|
||||||
|
|
||||||
api.runningLk.Lock()
|
api.runningLk.Lock()
|
||||||
api.running[id] = runningNode{
|
api.running[id] = &runningNode{
|
||||||
cmd: cmd,
|
cmd: cmd,
|
||||||
meta: info,
|
meta: info,
|
||||||
|
|
||||||
mux: mux,
|
mux: mux,
|
||||||
stop: func() {
|
stop: func() {
|
||||||
defer close(mux.stop)
|
cmd.Process.Signal(os.Interrupt)
|
||||||
defer errlogfile.Close()
|
cmd.Process.Wait()
|
||||||
defer logfile.Close()
|
|
||||||
|
api.runningLk.Lock()
|
||||||
|
api.running[id].meta.State = NodeStopped
|
||||||
|
api.runningLk.Unlock()
|
||||||
|
|
||||||
|
logfile.Close()
|
||||||
|
errlogfile.Close()
|
||||||
|
|
||||||
|
close(mux.stop)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
api.runningLk.Unlock()
|
api.runningLk.Unlock()
|
||||||
@ -180,21 +198,30 @@ func (api *api) SpawnStorage(fullNodeRepo string) (nodeInfo, error) {
|
|||||||
Repo: dir,
|
Repo: dir,
|
||||||
ID: id,
|
ID: id,
|
||||||
ApiPort: 2500 + id,
|
ApiPort: 2500 + id,
|
||||||
|
State: NodeRunning,
|
||||||
|
|
||||||
FullNode: fullNodeRepo,
|
FullNode: fullNodeRepo,
|
||||||
Storage: true,
|
Storage: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
api.runningLk.Lock()
|
api.runningLk.Lock()
|
||||||
api.running[id] = runningNode{
|
api.running[id] = &runningNode{
|
||||||
cmd: cmd,
|
cmd: cmd,
|
||||||
meta: info,
|
meta: info,
|
||||||
|
|
||||||
mux: mux,
|
mux: mux,
|
||||||
stop: func() {
|
stop: func() {
|
||||||
defer close(mux.stop)
|
cmd.Process.Signal(os.Interrupt)
|
||||||
defer errlogfile.Close()
|
cmd.Process.Wait()
|
||||||
defer logfile.Close()
|
|
||||||
|
api.runningLk.Lock()
|
||||||
|
api.running[id].meta.State = NodeStopped
|
||||||
|
api.runningLk.Unlock()
|
||||||
|
|
||||||
|
logfile.Close()
|
||||||
|
errlogfile.Close()
|
||||||
|
|
||||||
|
close(mux.stop)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
api.runningLk.Unlock()
|
api.runningLk.Unlock()
|
||||||
@ -243,6 +270,19 @@ func (api *api) CreateRandomFile(size int64) (string, error) {
|
|||||||
return tf.Name(), nil
|
return tf.Name(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (api *api) Stop(node int32) error {
|
||||||
|
api.runningLk.Lock()
|
||||||
|
nd, ok := api.running[node]
|
||||||
|
api.runningLk.Unlock()
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
nd.stop()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type client struct {
|
type client struct {
|
||||||
Nodes func() []nodeInfo
|
Nodes func() []nodeInfo
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,10 @@ class Address extends React.Component {
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.refresh()
|
this.refresh()
|
||||||
if(!this.props.ts)
|
if(!this.props.ts) {
|
||||||
setInterval(this.refresh, 2050)
|
let updates = setInterval(this.refresh, 2050)
|
||||||
|
this.props.client.on('close', () => clearInterval(updates))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async refresh() {
|
async refresh() {
|
||||||
|
@ -19,9 +19,11 @@ class FullNode extends React.Component {
|
|||||||
this.add1k = this.add1k.bind(this)
|
this.add1k = this.add1k.bind(this)
|
||||||
this.explorer = this.explorer.bind(this)
|
this.explorer = this.explorer.bind(this)
|
||||||
this.client = this.client.bind(this)
|
this.client = this.client.bind(this)
|
||||||
|
this.stop = this.stop.bind(this)
|
||||||
|
|
||||||
this.loadInfo()
|
this.loadInfo()
|
||||||
setInterval(this.loadInfo, 2050)
|
let updates = setInterval(this.loadInfo, 2050)
|
||||||
|
this.props.client.on('close', () => clearInterval(updates))
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadInfo() {
|
async loadInfo() {
|
||||||
@ -95,6 +97,10 @@ class FullNode extends React.Component {
|
|||||||
this.props.mountWindow((onClose) => <Client onClose={onClose} node={this.props.node} client={this.props.client} pondClient={this.props.pondClient} mountWindow={this.props.mountWindow}/>)
|
this.props.mountWindow((onClose) => <Client onClose={onClose} node={this.props.node} client={this.props.client} pondClient={this.props.pondClient} mountWindow={this.props.mountWindow}/>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async stop() {
|
||||||
|
await this.props.stop()
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let runtime = <div></div>
|
let runtime = <div></div>
|
||||||
|
|
||||||
@ -165,7 +171,8 @@ class FullNode extends React.Component {
|
|||||||
<Cristal
|
<Cristal
|
||||||
title={"Node " + this.props.node.ID}
|
title={"Node " + this.props.node.ID}
|
||||||
initialPosition={{x: this.props.node.ID*30, y: this.props.node.ID * 30}}
|
initialPosition={{x: this.props.node.ID*30, y: this.props.node.ID * 30}}
|
||||||
initialSize={{width: 690, height: 300}} >
|
initialSize={{width: 690, height: 300}}
|
||||||
|
onClose={this.stop} >
|
||||||
<div className="CristalScroll">
|
<div className="CristalScroll">
|
||||||
<div className="FullNode">
|
<div className="FullNode">
|
||||||
{runtime}
|
{runtime}
|
||||||
|
@ -9,6 +9,8 @@ import pushMessage from "./chain/send";
|
|||||||
import Logs from "./Logs";
|
import Logs from "./Logs";
|
||||||
import StorageNodeInit from "./StorageNodeInit";
|
import StorageNodeInit from "./StorageNodeInit";
|
||||||
|
|
||||||
|
const [NodeUnknown, NodeRunning, NodeStopped] = [0, 1, 2]
|
||||||
|
|
||||||
class NodeList extends React.Component {
|
class NodeList extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
@ -53,6 +55,7 @@ class NodeList extends React.Component {
|
|||||||
give1k={this.transfer1kFrom1}
|
give1k={this.transfer1kFrom1}
|
||||||
mountWindow={this.props.mountWindow}
|
mountWindow={this.props.mountWindow}
|
||||||
spawnStorageNode={this.spawnStorageNode}
|
spawnStorageNode={this.spawnStorageNode}
|
||||||
|
stop={this.stopNode(node.ID, onClose)}
|
||||||
/>)
|
/>)
|
||||||
} else {
|
} else {
|
||||||
const fullId = await this.props.client.call('Pond.FullID', [node.ID])
|
const fullId = await this.props.client.call('Pond.FullID', [node.ID])
|
||||||
@ -72,7 +75,7 @@ class NodeList extends React.Component {
|
|||||||
const nodes = nds.reduce((o, i) => {o[i.ID] = i; return o}, {})
|
const nodes = nds.reduce((o, i) => {o[i.ID] = i; return o}, {})
|
||||||
console.log('nds', nodes)
|
console.log('nds', nodes)
|
||||||
|
|
||||||
Object.keys(nodes).map(n => nodes[n]).forEach(n => this.mountNode(n))
|
Object.keys(nodes).map(n => nodes[n]).filter(n => n.State === NodeRunning).forEach(n => this.mountNode(n))
|
||||||
|
|
||||||
this.setState({existingLoaded: true, nodes: nodes})
|
this.setState({existingLoaded: true, nodes: nodes})
|
||||||
}
|
}
|
||||||
@ -114,6 +117,22 @@ class NodeList extends React.Component {
|
|||||||
//this.setState(state => ({nodes: {...state.nodes, [node.ID]: node}}))
|
//this.setState(state => ({nodes: {...state.nodes, [node.ID]: node}}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 () => {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
connMgr() {
|
connMgr() {
|
||||||
this.setState({showConnMgr: true})
|
this.setState({showConnMgr: true})
|
||||||
}
|
}
|
||||||
@ -155,6 +174,9 @@ class NodeList extends React.Component {
|
|||||||
info = <span>{nd.peerid}</span>
|
info = <span>{nd.peerid}</span>
|
||||||
logs = <a href='#' onClick={() => this.props.mountWindow(cl => <Logs node={nd.ID} onClose={cl}/>)}>[logs]</a>
|
logs = <a href='#' onClick={() => this.props.mountWindow(cl => <Logs node={nd.ID} onClose={cl}/>)}>[logs]</a>
|
||||||
}
|
}
|
||||||
|
if (nd.State === NodeStopped) {
|
||||||
|
info = <span>[stopped] <a href="#" onClick={this.startNode(n)}>[START]</a></span>
|
||||||
|
}
|
||||||
|
|
||||||
return <div key={n}>
|
return <div key={n}>
|
||||||
{n} {type} {logs} {info}
|
{n} {type} {logs} {info}
|
||||||
|
@ -130,7 +130,7 @@ var runCmd = &cli.Command{
|
|||||||
Usage: "run lotuspond daemon",
|
Usage: "run lotuspond daemon",
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
rpcServer := jsonrpc.NewServer()
|
rpcServer := jsonrpc.NewServer()
|
||||||
a := &api{running: map[int32]runningNode{}}
|
a := &api{running: map[int32]*runningNode{}}
|
||||||
rpcServer.Register("Pond", a)
|
rpcServer.Register("Pond", a)
|
||||||
|
|
||||||
http.Handle("/", http.FileServer(http.Dir("lotuspond/front/build")))
|
http.Handle("/", http.FileServer(http.Dir("lotuspond/front/build")))
|
||||||
|
Loading…
Reference in New Issue
Block a user