diff --git a/js/src/redux/actions.js b/js/src/redux/actions.js index 58e9c2a36..bb5f42a33 100644 --- a/js/src/redux/actions.js +++ b/js/src/redux/actions.js @@ -16,7 +16,7 @@ import { newError } from '../ui/Errors/actions'; import { setAddressImage } from './providers/imagesActions'; -import { clearStatusLogs, toggleStatusLogs } from './providers/statusActions'; +import { clearStatusLogs, toggleStatusLogs, toggleStatusRefresh } from './providers/statusActions'; import { toggleView } from '../views/Settings'; export { @@ -24,5 +24,6 @@ export { clearStatusLogs, setAddressImage, toggleStatusLogs, + toggleStatusRefresh, toggleView }; diff --git a/js/src/redux/providers/status.js b/js/src/redux/providers/status.js index 9a7410e2f..4ef8d3de6 100644 --- a/js/src/redux/providers/status.js +++ b/js/src/redux/providers/status.js @@ -25,31 +25,19 @@ export default class Status { this._pingable = false; this._apiStatus = {}; this._status = {}; + this._longStatus = {}; + this._minerSettings = {}; this._pollPingTimeoutId = null; + this._longStatusTimeoutId = null; } start () { this._subscribeBlockNumber(); this._pollPing(); this._pollStatus(); + this._pollLongStatus(); this._pollLogs(); - this._fetchEnode(); - } - - _fetchEnode () { - this._api.parity - .enode() - .then((enode) => { - if (this._store.state.nodeStatus.enode !== enode) { - this._store.dispatch(statusCollection({ enode })); - } - }) - .catch(() => { - window.setTimeout(() => { - this._fetchEnode(); - }, 1000); - }); } _subscribeBlockNumber () { @@ -121,12 +109,12 @@ export default class Status { } _pollStatus = () => { - const { isConnected, isConnecting, needsToken, secureToken } = this._api; - const nextTimeout = (timeout = 1000) => { setTimeout(this._pollStatus, timeout); }; + const { isConnected, isConnecting, needsToken, secureToken } = this._api; + const apiStatus = { isConnected, isConnecting, @@ -134,6 +122,12 @@ export default class Status { secureToken }; + const gotReconnected = !this._apiStatus.isConnected && apiStatus.isConnected; + + if (gotReconnected) { + this._pollLongStatus(); + } + if (!isEqual(apiStatus, this._apiStatus)) { this._store.dispatch(statusCollection(apiStatus)); this._apiStatus = apiStatus; @@ -147,57 +141,130 @@ export default class Status { } if (!isConnected) { - nextTimeout(250); - return; + return nextTimeout(250); + } + + const { refreshStatus } = this._store.getState().nodeStatus; + + const statusPromises = [ this._api.eth.syncing() ]; + + if (refreshStatus) { + statusPromises.push(this._api.eth.hashrate()); + statusPromises.push(this._api.parity.netPeers()); } Promise - .all([ - this._api.web3.clientVersion(), - this._api.eth.coinbase(), - this._api.parity.defaultExtraData(), - this._api.parity.extraData(), - this._api.parity.gasFloorTarget(), - this._api.eth.hashrate(), - this._api.parity.minGasPrice(), - this._api.parity.netChain(), - this._api.parity.netPeers(), - this._api.parity.netPort(), - this._api.parity.nodeName(), - this._api.parity.rpcSettings(), - this._api.eth.syncing() - ]) - .then(([clientVersion, coinbase, defaultExtraData, extraData, gasFloorTarget, hashrate, minGasPrice, netChain, netPeers, netPort, nodeName, rpcSettings, syncing, traceMode]) => { - const isTest = netChain === 'morden' || netChain === 'testnet'; - - const status = { - clientVersion, - coinbase, - defaultExtraData, - extraData, - gasFloorTarget, - hashrate, - minGasPrice, - netChain, - netPeers, - netPort, - nodeName, - rpcSettings, - syncing, - isTest, - traceMode - }; + .all(statusPromises) + .then((statusResults) => { + const status = statusResults.length === 1 + ? { + syncing: statusResults[0] + } + : { + syncing: statusResults[0], + hashrate: statusResults[1], + netPeers: statusResults[2] + }; if (!isEqual(status, this._status)) { this._store.dispatch(statusCollection(status)); this._status = status; } + + nextTimeout(); }) .catch((error) => { console.error('_pollStatus', error); + nextTimeout(250); }); + } - nextTimeout(); + /** + * Miner settings should never changes unless + * Parity is restarted, or if the values are changed + * from the UI + */ + _pollMinerSettings = () => { + Promise + .all([ + this._api.eth.coinbase(), + this._api.parity.extraData(), + this._api.parity.minGasPrice(), + this._api.parity.gasFloorTarget() + ]) + .then(([ + coinbase, extraData, minGasPrice, gasFloorTarget + ]) => { + const minerSettings = { + coinbase, + extraData, + minGasPrice, + gasFloorTarget + }; + + if (!isEqual(minerSettings, this._minerSettings)) { + this._store.dispatch(statusCollection(minerSettings)); + this._minerSettings = minerSettings; + } + }) + .catch((error) => { + console.error('_pollMinerSettings', error); + }); + } + + /** + * The data fetched here should not change + * unless Parity is restarted. They are thus + * fetched every 30s just in case, and whenever + * the client got reconnected. + */ + _pollLongStatus = () => { + const nextTimeout = (timeout = 30000) => { + if (this._longStatusTimeoutId) { + clearTimeout(this._longStatusTimeoutId); + } + + this._longStatusTimeoutId = setTimeout(this._pollLongStatus, timeout); + }; + + // Poll Miner settings just in case + this._pollMinerSettings(); + + Promise + .all([ + this._api.web3.clientVersion(), + this._api.parity.defaultExtraData(), + this._api.parity.netChain(), + this._api.parity.netPort(), + this._api.parity.rpcSettings(), + this._api.parity.enode() + ]) + .then(([ + clientVersion, defaultExtraData, netChain, netPort, rpcSettings, enode + ]) => { + const isTest = netChain === 'morden' || netChain === 'testnet'; + + const longStatus = { + clientVersion, + defaultExtraData, + netChain, + netPort, + rpcSettings, + enode, + isTest + }; + + if (!isEqual(longStatus, this._longStatus)) { + this._store.dispatch(statusCollection(longStatus)); + this._longStatus = longStatus; + } + + nextTimeout(); + }) + .catch((error) => { + console.error('_pollLongStatus', error); + nextTimeout(250); + }); } _pollLogs = () => { diff --git a/js/src/redux/providers/statusActions.js b/js/src/redux/providers/statusActions.js index 142cdabdc..1c175c29d 100644 --- a/js/src/redux/providers/statusActions.js +++ b/js/src/redux/providers/statusActions.js @@ -47,3 +47,10 @@ export function clearStatusLogs () { type: 'clearStatusLogs' }; } + +export function toggleStatusRefresh (refreshStatus) { + return { + type: 'toggleStatusRefresh', + refreshStatus + }; +} diff --git a/js/src/redux/providers/statusReducer.js b/js/src/redux/providers/statusReducer.js index 98bb536ae..b0450083a 100644 --- a/js/src/redux/providers/statusReducer.js +++ b/js/src/redux/providers/statusReducer.js @@ -37,12 +37,13 @@ const initialState = { max: new BigNumber(0) }, netPort: new BigNumber(0), - nodeName: '', rpcSettings: {}, syncing: false, - isApiConnected: true, - isPingConnected: true, + isConnected: false, + isConnecting: false, + isPingable: false, isTest: false, + refreshStatus: false, traceMode: undefined }; @@ -73,5 +74,10 @@ export default handleActions({ clearStatusLogs (state, action) { return Object.assign({}, state, { devLogs: [] }); + }, + + toggleStatusRefresh (state, action) { + const { refreshStatus } = action; + return Object.assign({}, state, { refreshStatus }); } }, initialState); diff --git a/js/src/views/Status/containers/StatusPage/StatusPage.js b/js/src/views/Status/containers/StatusPage/StatusPage.js index afc7d60f7..617a6486a 100644 --- a/js/src/views/Status/containers/StatusPage/StatusPage.js +++ b/js/src/views/Status/containers/StatusPage/StatusPage.js @@ -18,7 +18,7 @@ import React, { Component, PropTypes } from 'react'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; -import { clearStatusLogs, toggleStatusLogs } from '../../../../redux/actions'; +import { clearStatusLogs, toggleStatusLogs, toggleStatusRefresh } from '../../../../redux/actions'; import Debug from '../../components/Debug'; import Status from '../../components/Status'; @@ -31,6 +31,14 @@ class StatusPage extends Component { actions: PropTypes.object.isRequired } + componentWillMount () { + this.props.actions.toggleStatusRefresh(true); + } + + componentWillUnmount () { + this.props.actions.toggleStatusRefresh(false); + } + render () { return (