|
@@ -3,46 +3,185 @@ var ZeroTierNode = React.createClass({
|
|
return {
|
|
return {
|
|
address: '----------',
|
|
address: '----------',
|
|
online: false,
|
|
online: false,
|
|
- version: '_._._'
|
|
|
|
|
|
+ version: '_._._',
|
|
|
|
+ _networks: [],
|
|
|
|
+ _peers: []
|
|
};
|
|
};
|
|
},
|
|
},
|
|
|
|
|
|
|
|
+ ago: function(ms) {
|
|
|
|
+ if (ms > 0) {
|
|
|
|
+ var tmp = Math.round((Date.now() - ms) / 1000);
|
|
|
|
+ return ((tmp > 0) ? tmp : 0);
|
|
|
|
+ } else return 0;
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ updatePeers: function() {
|
|
|
|
+ Ajax.call({
|
|
|
|
+ url: 'peer?auth='+this.props.authToken,
|
|
|
|
+ cache: false,
|
|
|
|
+ type: 'GET',
|
|
|
|
+ success: function(data) {
|
|
|
|
+ if (data) {
|
|
|
|
+ var pl = JSON.parse(data);
|
|
|
|
+ if (Array.isArray(pl)) {
|
|
|
|
+ this.setState({_peers: pl});
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }.bind(this),
|
|
|
|
+ error: function() {
|
|
|
|
+ }.bind(this)
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ updateNetworks: function() {
|
|
|
|
+ Ajax.call({
|
|
|
|
+ url: 'network?auth='+this.props.authToken,
|
|
|
|
+ cache: false,
|
|
|
|
+ type: 'GET',
|
|
|
|
+ success: function(data) {
|
|
|
|
+ if (data) {
|
|
|
|
+ var nwl = JSON.parse(data);
|
|
|
|
+ if (Array.isArray(nwl)) {
|
|
|
|
+ this.setState({_networks: nwl});
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }.bind(this),
|
|
|
|
+ error: function() {
|
|
|
|
+ }.bind(this)
|
|
|
|
+ });
|
|
|
|
+ },
|
|
updateAll: function() {
|
|
updateAll: function() {
|
|
Ajax.call({
|
|
Ajax.call({
|
|
url: 'status?auth='+this.props.authToken,
|
|
url: 'status?auth='+this.props.authToken,
|
|
cache: false,
|
|
cache: false,
|
|
type: 'GET',
|
|
type: 'GET',
|
|
success: function(data) {
|
|
success: function(data) {
|
|
- if (data)
|
|
|
|
- this.setState(JSON.parse(data));
|
|
|
|
|
|
+ if (data) {
|
|
|
|
+ var status = JSON.parse(data);
|
|
|
|
+ this.setState(status);
|
|
|
|
+ document.title = 'ZeroTier One [' + status.address + ']';
|
|
|
|
+ }
|
|
|
|
+ this.updateNetworks();
|
|
|
|
+ this.updatePeers();
|
|
}.bind(this),
|
|
}.bind(this),
|
|
error: function() {
|
|
error: function() {
|
|
- this.setState(this.getInitialState());
|
|
|
|
|
|
+ this.setState({online: false});
|
|
}.bind(this)
|
|
}.bind(this)
|
|
- })
|
|
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ joinNetwork: function(event) {
|
|
|
|
+ event.preventDefault();
|
|
|
|
+ if ((this.networkToJoin)&&(this.networkToJoin.length === 16)) {
|
|
|
|
+ Ajax.call({
|
|
|
|
+ url: 'network/'+this.networkToJoin+'?auth='+this.props.authToken,
|
|
|
|
+ cache: false,
|
|
|
|
+ type: 'POST',
|
|
|
|
+ success: function(data) {
|
|
|
|
+ }.bind(this),
|
|
|
|
+ error: function() {
|
|
|
|
+ }.bind(this)
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ handleNetworkIdEntry: function(event) {
|
|
|
|
+ var nid = event.target.value;
|
|
|
|
+ if (nid) {
|
|
|
|
+ nid = nid.toLowerCase();
|
|
|
|
+ var nnid = '';
|
|
|
|
+ for(var i=0;((i<nid.length)&&(i<16));++i) {
|
|
|
|
+ if ("0123456789abcdef".indexOf(nid.charAt(i)) >= 0)
|
|
|
|
+ nnid += nid.charAt(i);
|
|
|
|
+ }
|
|
|
|
+ this.networkToJoin = nnid;
|
|
|
|
+ event.target.value = nnid;
|
|
|
|
+ } else {
|
|
|
|
+ this.networkToJoin = '';
|
|
|
|
+ event.target.value = '';
|
|
|
|
+ }
|
|
},
|
|
},
|
|
|
|
|
|
componentDidMount: function() {
|
|
componentDidMount: function() {
|
|
|
|
+ this.tabIndex = 0;
|
|
this.updateAll();
|
|
this.updateAll();
|
|
-// this.updateIntervalId = setInterval(this.updateAll,2500);
|
|
|
|
|
|
+ this.updateIntervalId = setInterval(this.updateAll,2500);
|
|
},
|
|
},
|
|
componentWillUnmount: function() {
|
|
componentWillUnmount: function() {
|
|
-// clearInterval(this.updateIntervalId);
|
|
|
|
|
|
+ clearInterval(this.updateIntervalId);
|
|
},
|
|
},
|
|
render: function() {
|
|
render: function() {
|
|
return (
|
|
return (
|
|
- <div className="container-fluid zeroTierNode">
|
|
|
|
- <div className="row">
|
|
|
|
|
|
+ <div className="zeroTierNode">
|
|
|
|
+ <div className="top">
|
|
|
|
+ <button disabled={this.tabIndex === 0} onClick={function() {this.tabIndex = 0; this.forceUpdate();}.bind(this)}>Networks</button>
|
|
|
|
+ <button disabled={this.tabIndex === 1} onClick={function() {this.tabIndex = 1; this.forceUpdate();}.bind(this)}>Peers</button>
|
|
|
|
+ </div>
|
|
|
|
+ <div className="middle">
|
|
|
|
+ <div className="middleScroll">
|
|
|
|
+ {
|
|
|
|
+ (this.tabIndex === 1) ? (
|
|
|
|
+ <div className="peers">
|
|
|
|
+ <div className="peerHeader">
|
|
|
|
+ <div className="f">Address</div>
|
|
|
|
+ <div className="f">Version</div>
|
|
|
|
+ <div className="f">Latency</div>
|
|
|
|
+ <div className="f">Direct Paths</div>
|
|
|
|
+ <div className="f">Role</div>
|
|
|
|
+ </div>
|
|
|
|
+ {
|
|
|
|
+ this.state._peers.map(function(peer) {
|
|
|
|
+ return (
|
|
|
|
+ <div className="peer">
|
|
|
|
+ <div className="f zeroTierAddress">{peer['address']}</div>
|
|
|
|
+ <div className="f">{(peer['version'] === '-1.-1.-1') ? '-' : peer['version']}</div>
|
|
|
|
+ <div className="f">{peer['latency']}</div>
|
|
|
|
+ <div className="f">
|
|
|
|
+ {
|
|
|
|
+ (peer['paths'].length === 0) ? (
|
|
|
|
+ <div className="peerPath"><i>(none)</i></div>
|
|
|
|
+ ) : (
|
|
|
|
+ <div>
|
|
|
|
+ {
|
|
|
|
+ peer['paths'].map(function(path) {
|
|
|
|
+ if ((path.active)||(path.fixed)) {
|
|
|
|
+ return (
|
|
|
|
+ <div className="peerPath">{path.address} {this.ago(path.lastSend)} {this.ago(path.lastReceive)}{path.preferred ? ' *' : ''}</div>
|
|
|
|
+ );
|
|
|
|
+ } else {
|
|
|
|
+ return (
|
|
|
|
+ <div className="peerPathInactive">{path.address} {this.ago(path.lastSend)} {this.ago(path.lastReceive)}</div>
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+ }.bind(this))
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
|
|
+ )
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
|
|
+ <div className="f">{peer['role']}</div>
|
|
|
|
+ </div>
|
|
|
|
+ );
|
|
|
|
+ }.bind(this))
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
|
|
+ ) : (
|
|
|
|
+ <div className="networks">
|
|
|
|
+ {
|
|
|
|
+ this.state._networks.map(function(network) {
|
|
|
|
+ network['authToken'] = this.props.authToken;
|
|
|
|
+ return React.createElement('div',{className: 'network'},React.createElement(ZeroTierNetwork,network));
|
|
|
|
+ }.bind(this))
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
|
|
+ )
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
</div>
|
|
</div>
|
|
- <div className="row">
|
|
|
|
- <div className="col-xs-8">
|
|
|
|
- <span className="zerotier-address">{this.state.address}</span>
|
|
|
|
- <span className="zerotier-node-statusline">{this.state.online ? 'ONLINE' : 'OFFLINE'} {this.state.version}</span>
|
|
|
|
|
|
+ <div className="bottom">
|
|
|
|
+ <div className="left">
|
|
|
|
+ <span className="statusLine"><span className="zeroTierAddress">{this.state.address}</span> {this.state.online ? 'ONLINE' : 'OFFLINE'} {this.state.version}</span>
|
|
</div>
|
|
</div>
|
|
- <div className="col-xs-4">
|
|
|
|
- <form>
|
|
|
|
- <input type="text"/>
|
|
|
|
- </form>
|
|
|
|
|
|
+ <div className="right">
|
|
|
|
+ <form onSubmit={this.joinNetwork}><input type="text" placeholder="################" onChange={this.handleNetworkIdEntry} size="16"/><button type="submit">Join</button></form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|