From f87ea49b5ac2d66d8f281f08f42e8cfd2d701ba7 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Thu, 18 May 2017 23:54:02 +0200 Subject: Create a network controller to manage switcing networks an updating the provider --- app/scripts/controllers/network.js | 152 +++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 app/scripts/controllers/network.js (limited to 'app/scripts/controllers/network.js') diff --git a/app/scripts/controllers/network.js b/app/scripts/controllers/network.js new file mode 100644 index 000000000..82eabb573 --- /dev/null +++ b/app/scripts/controllers/network.js @@ -0,0 +1,152 @@ +const EventEmitter = require('events') +const MetaMaskProvider = require('web3-provider-engine/zero.js') +const ObservableStore = require('obs-store') +const extend = require('xtend') +const EthQuery = require('eth-query') +const MetamaskConfig = require('../config.js') + +const TESTNET_RPC = MetamaskConfig.network.testnet +const MAINNET_RPC = MetamaskConfig.network.mainnet +const MORDEN_RPC = MetamaskConfig.network.morden +const KOVAN_RPC = MetamaskConfig.network.kovan +const RINKEBY_RPC = MetamaskConfig.network.rinkeby + +module.exports = class NetworkController extends EventEmitter { + constructor (providerOpts) { + super() + this.networkStore = new ObservableStore({ network: 'loading' }) + providerOpts.provider.rpcTarget = this.getRpcAddressForType(providerOpts.provider.type) + this.providerStore = new ObservableStore(providerOpts) + this._claimed = 0 + } + + getState () { + return extend({}, + this.networkStore.getState(), + this.providerStore.getState() + ) + } + + initializeProvider (opts) { + this.providerConfig = opts + this.provider = MetaMaskProvider(opts) + this.ethQuery = new EthQuery(this.provider) + this.lookupNetwork() + return Promise.resolve(this.provider) + } + switchNetwork (providerConfig) { + delete this.provider + delete this.ethQuery + const newConfig = extend(this.providerConfig, providerConfig) + this.providerConfig = newConfig + this.provider = MetaMaskProvider(newConfig) + this.ethQuery = new EthQuery(this.provider) + this.emit('networkSwitch', { + provider: this.provider, + ethQuery: this.ethQuery, + }, this.claim.bind(this)) + } + + subscribe (cb) { + this.networkStore.subscribe(cb) + this.providerStore.subscribe(cb) + } + + verifyNetwork () { + // Check network when restoring connectivity: + if (this.isNetworkLoading()) this.lookupNetwork() + } + + getNetworkState () { + return this.networkStore.getState().network + } + + setNetworkState (network) { + return this.networkStore.updateState({ network }) + } + + isNetworkLoading () { + return this.getNetworkState() === 'loading' + } + + lookupNetwork (err) { + if (err) this.setNetworkState('loading') + + this.ethQuery.sendAsync({ method: 'net_version' }, (err, network) => { + if (err) return this.setNetworkState('loading') + + log.info('web3.getNetwork returned ' + network) + this.setNetworkState(network) + }) + } + + setRpcTarget (rpcUrl) { + this.providerStore.updateState({ + provider: { + type: 'rpc', + rpcTarget: rpcUrl, + }, + }) + } + + getCurrentRpcAddress () { + var provider = this.getProvider() + if (!provider) return null + return this.getRpcAddressForType(provider.type) + } + + setProviderType (type) { + if (type === this.getProvider().type) return + const rpcTarget = this.getRpcAddressForType(type) + this.networkStore.updateState({network: 'loading'}) + this.switchNetwork({ + rpcUrl: rpcTarget, + }) + this.once('claimed', () => { + this.providerStore.updateState({provider: {type, rpcTarget}}) + console.log('CLAIMED') + this.lookupNetwork() + }) + + } + + useEtherscanProvider () { + this.setProviderType('etherscan') + } + + getProvider () { + return this.providerStore.getState().provider + } + + getRpcAddressForType (type) { + const provider = this.getProvider() + switch (type) { + + case 'mainnet': + return MAINNET_RPC + + case 'testnet': + return TESTNET_RPC + + case 'morden': + return MORDEN_RPC + + case 'kovan': + return KOVAN_RPC + + case 'rinkeby': + return RINKEBY_RPC + + default: + return provider && provider.rpcTarget ? provider.rpcTarget : TESTNET_RPC + } + } + + claim () { + this._claimed += 1 + if (this._claimed === this.listenerCount('networkSwitch')) { + this.emit('claimed') + this._claimed = 0 + } + } +} -- cgit From 529304c005318852b60bb93846a58d6eb3da2066 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Tue, 23 May 2017 01:56:10 -0400 Subject: Wrap the provider in a proxy --- app/scripts/controllers/network.js | 110 +++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 60 deletions(-) (limited to 'app/scripts/controllers/network.js') diff --git a/app/scripts/controllers/network.js b/app/scripts/controllers/network.js index 82eabb573..97c2ccbc2 100644 --- a/app/scripts/controllers/network.js +++ b/app/scripts/controllers/network.js @@ -3,21 +3,29 @@ const MetaMaskProvider = require('web3-provider-engine/zero.js') const ObservableStore = require('obs-store') const extend = require('xtend') const EthQuery = require('eth-query') -const MetamaskConfig = require('../config.js') - -const TESTNET_RPC = MetamaskConfig.network.testnet -const MAINNET_RPC = MetamaskConfig.network.mainnet -const MORDEN_RPC = MetamaskConfig.network.morden -const KOVAN_RPC = MetamaskConfig.network.kovan -const RINKEBY_RPC = MetamaskConfig.network.rinkeby +const RPC_ADDRESS_LIST = require('../config.js').network module.exports = class NetworkController extends EventEmitter { constructor (providerOpts) { super() this.networkStore = new ObservableStore({ network: 'loading' }) - providerOpts.provider.rpcTarget = this.getRpcAddressForType(providerOpts.provider.type) + providerOpts.provider.rpcTarget = this.getRpcAddressForType(providerOpts.provider.type, providerOpts.provider) this.providerStore = new ObservableStore(providerOpts) - this._claimed = 0 + this.store = new ObservableStore(extend(this.networkStore.getState(), this.providerStore.getState())) + + this._providerListners = {} + + this.networkStore.subscribe((state) => this.store.updateState(state)) + this.providerStore.subscribe((state) => this.store.updateState(state)) + this.on('networkSwitch', this.lookupNetwork) + } + + get provider () { + return this._proxy + } + + set provider (provider) { + this._provider = provider } getState () { @@ -29,28 +37,35 @@ module.exports = class NetworkController extends EventEmitter { initializeProvider (opts) { this.providerConfig = opts - this.provider = MetaMaskProvider(opts) + this._provider = MetaMaskProvider(opts) + this._proxy = new Proxy(this._provider, { + get: (obj, name) => { + if (name === 'on') return this._on.bind(this) + return this._provider[name] + }, + set: (obj, name, value) => { + this._provider[name] = value + }, + }) + this.provider.on('block', this._logBlock.bind(this)) + this.provider.on('error', this.verifyNetwork.bind(this)) this.ethQuery = new EthQuery(this.provider) this.lookupNetwork() - return Promise.resolve(this.provider) + return this.provider } + switchNetwork (providerConfig) { - delete this.provider - delete this.ethQuery const newConfig = extend(this.providerConfig, providerConfig) this.providerConfig = newConfig + this.provider = MetaMaskProvider(newConfig) - this.ethQuery = new EthQuery(this.provider) - this.emit('networkSwitch', { - provider: this.provider, - ethQuery: this.ethQuery, - }, this.claim.bind(this)) + // apply the listners created by other controllers + Object.keys(this._providerListners).forEach((key) => { + this._providerListners[key].forEach((handler) => this._provider.addListener(key, handler)) + }) + this.emit('networkSwitch', this.provider) } - subscribe (cb) { - this.networkStore.subscribe(cb) - this.providerStore.subscribe(cb) - } verifyNetwork () { // Check network when restoring connectivity: @@ -74,7 +89,6 @@ module.exports = class NetworkController extends EventEmitter { this.ethQuery.sendAsync({ method: 'net_version' }, (err, network) => { if (err) return this.setNetworkState('loading') - log.info('web3.getNetwork returned ' + network) this.setNetworkState(network) }) @@ -102,51 +116,27 @@ module.exports = class NetworkController extends EventEmitter { this.switchNetwork({ rpcUrl: rpcTarget, }) - this.once('claimed', () => { - this.providerStore.updateState({provider: {type, rpcTarget}}) - console.log('CLAIMED') - this.lookupNetwork() - }) - - } - - useEtherscanProvider () { - this.setProviderType('etherscan') + this.providerStore.updateState({provider: {type, rpcTarget}}) } getProvider () { return this.providerStore.getState().provider } - getRpcAddressForType (type) { - const provider = this.getProvider() - switch (type) { - - case 'mainnet': - return MAINNET_RPC - - case 'testnet': - return TESTNET_RPC - - case 'morden': - return MORDEN_RPC - - case 'kovan': - return KOVAN_RPC - - case 'rinkeby': - return RINKEBY_RPC + getRpcAddressForType (type, provider = this.getProvider()) { + console.log(`#getRpcAddressForType: ${type}`) + if (type in RPC_ADDRESS_LIST) return RPC_ADDRESS_LIST[type] + return provider && provider.rpcTarget ? provider.rpcTarget : RPC_ADDRESS_LIST['rinkeby'] + } - default: - return provider && provider.rpcTarget ? provider.rpcTarget : TESTNET_RPC - } + _logBlock (block) { + log.info(`BLOCK CHANGED: #${block.number.toString('hex')} 0x${block.hash.toString('hex')}`) + this.verifyNetwork() } - claim () { - this._claimed += 1 - if (this._claimed === this.listenerCount('networkSwitch')) { - this.emit('claimed') - this._claimed = 0 - } + _on (event, handler) { + if (!this._providerListners[event]) this._providerListners[event] = [] + this._providerListners[event].push(handler) + this._provider.on(event, handler) } } -- cgit From 243eeff7cb0d4c5d613a9250d234f81fdccbbf15 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Tue, 23 May 2017 02:12:28 -0400 Subject: Fix for tests --- app/scripts/controllers/network.js | 84 ++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 49 deletions(-) (limited to 'app/scripts/controllers/network.js') diff --git a/app/scripts/controllers/network.js b/app/scripts/controllers/network.js index 97c2ccbc2..4fdd92921 100644 --- a/app/scripts/controllers/network.js +++ b/app/scripts/controllers/network.js @@ -1,23 +1,23 @@ const EventEmitter = require('events') const MetaMaskProvider = require('web3-provider-engine/zero.js') const ObservableStore = require('obs-store') +const ComposedStore = require('obs-store/lib/composed') const extend = require('xtend') const EthQuery = require('eth-query') const RPC_ADDRESS_LIST = require('../config.js').network +const DEFAULT_RPC = RPC_ADDRESS_LIST['rinkeby'] module.exports = class NetworkController extends EventEmitter { - constructor (providerOpts) { + constructor (config) { super() - this.networkStore = new ObservableStore({ network: 'loading' }) - providerOpts.provider.rpcTarget = this.getRpcAddressForType(providerOpts.provider.type, providerOpts.provider) - this.providerStore = new ObservableStore(providerOpts) - this.store = new ObservableStore(extend(this.networkStore.getState(), this.providerStore.getState())) + this.networkStore = new ObservableStore('loading') + config.provider.rpcTarget = this.getRpcAddressForType(config.provider.type, config.provider) + this.providerStore = new ObservableStore(config.provider) + this.store = new ComposedStore({ provider: this.providerStore, network: this.networkStore }) + this._providerListeners = {} - this._providerListners = {} - - this.networkStore.subscribe((state) => this.store.updateState(state)) - this.providerStore.subscribe((state) => this.store.updateState(state)) - this.on('networkSwitch', this.lookupNetwork) + this.on('networkDidChange', this.lookupNetwork) + this.providerStore.subscribe((state) => this.switchNetwork({rpcUrl: state.rpcTarget})) } get provider () { @@ -28,15 +28,8 @@ module.exports = class NetworkController extends EventEmitter { this._provider = provider } - getState () { - return extend({}, - this.networkStore.getState(), - this.providerStore.getState() - ) - } - initializeProvider (opts) { - this.providerConfig = opts + this.providerInit = opts this._provider = MetaMaskProvider(opts) this._proxy = new Proxy(this._provider, { get: (obj, name) => { @@ -54,16 +47,18 @@ module.exports = class NetworkController extends EventEmitter { return this.provider } - switchNetwork (providerConfig) { - const newConfig = extend(this.providerConfig, providerConfig) - this.providerConfig = newConfig + switchNetwork (providerInit) { + this.setNetworkState('loading') + const newInit = extend(this.providerInit, providerInit) + this.providerInit = newInit - this.provider = MetaMaskProvider(newConfig) + this._provider.removeAllListeners() + this.provider = MetaMaskProvider(newInit) // apply the listners created by other controllers - Object.keys(this._providerListners).forEach((key) => { - this._providerListners[key].forEach((handler) => this._provider.addListener(key, handler)) + Object.keys(this._providerListeners).forEach((key) => { + this._providerListeners[key].forEach((handler) => this._provider.addListener(key, handler)) }) - this.emit('networkSwitch', this.provider) + this.emit('networkDidChange') } @@ -73,20 +68,18 @@ module.exports = class NetworkController extends EventEmitter { } getNetworkState () { - return this.networkStore.getState().network + return this.networkStore.getState() } setNetworkState (network) { - return this.networkStore.updateState({ network }) + return this.networkStore.putState(network) } isNetworkLoading () { return this.getNetworkState() === 'loading' } - lookupNetwork (err) { - if (err) this.setNetworkState('loading') - + lookupNetwork () { this.ethQuery.sendAsync({ method: 'net_version' }, (err, network) => { if (err) return this.setNetworkState('loading') log.info('web3.getNetwork returned ' + network) @@ -96,37 +89,30 @@ module.exports = class NetworkController extends EventEmitter { setRpcTarget (rpcUrl) { this.providerStore.updateState({ - provider: { - type: 'rpc', - rpcTarget: rpcUrl, - }, + type: 'rpc', + rpcTarget: rpcUrl, }) } getCurrentRpcAddress () { - var provider = this.getProvider() + const provider = this.getProviderConfig() if (!provider) return null return this.getRpcAddressForType(provider.type) } setProviderType (type) { - if (type === this.getProvider().type) return + if (type === this.getProviderConfig().type) return const rpcTarget = this.getRpcAddressForType(type) - this.networkStore.updateState({network: 'loading'}) - this.switchNetwork({ - rpcUrl: rpcTarget, - }) - this.providerStore.updateState({provider: {type, rpcTarget}}) + this.providerStore.updateState({type, rpcTarget}) } - getProvider () { - return this.providerStore.getState().provider + getProviderConfig () { + return this.providerStore.getState() } - getRpcAddressForType (type, provider = this.getProvider()) { - console.log(`#getRpcAddressForType: ${type}`) - if (type in RPC_ADDRESS_LIST) return RPC_ADDRESS_LIST[type] - return provider && provider.rpcTarget ? provider.rpcTarget : RPC_ADDRESS_LIST['rinkeby'] + getRpcAddressForType (type, provider = this.getProviderConfig()) { + if (RPC_ADDRESS_LIST[type]) return RPC_ADDRESS_LIST[type] + return provider && provider.rpcTarget ? provider.rpcTarget : DEFAULT_RPC } _logBlock (block) { @@ -135,8 +121,8 @@ module.exports = class NetworkController extends EventEmitter { } _on (event, handler) { - if (!this._providerListners[event]) this._providerListners[event] = [] - this._providerListners[event].push(handler) + if (!this._providerListeners[event]) this._providerListeners[event] = [] + this._providerListeners[event].push(handler) this._provider.on(event, handler) } } -- cgit From db982cf795d30dd32b4722249daea9296430b5b9 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Wed, 24 May 2017 11:52:18 -0400 Subject: stop polling when switching networks --- app/scripts/controllers/network.js | 1 + 1 file changed, 1 insertion(+) (limited to 'app/scripts/controllers/network.js') diff --git a/app/scripts/controllers/network.js b/app/scripts/controllers/network.js index 4fdd92921..c07f13b8d 100644 --- a/app/scripts/controllers/network.js +++ b/app/scripts/controllers/network.js @@ -53,6 +53,7 @@ module.exports = class NetworkController extends EventEmitter { this.providerInit = newInit this._provider.removeAllListeners() + this._provider.stop() this.provider = MetaMaskProvider(newInit) // apply the listners created by other controllers Object.keys(this._providerListeners).forEach((key) => { -- cgit