diff --git a/app/scripts/background.js b/app/scripts/background.js index 0bd7031d8..db4927083 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -71,13 +71,6 @@ provider.on('block', function(block){ var ethStore = new EthStore(provider) idStore.setStore(ethStore) -// copy idStore substate into public store -var publicConfigStore = new HostStore() -idStore.on('update', function(state){ - publicConfigStore.set('selectedAddress', state.selectedAddress) -}) - - function getState(){ var state = extend( ethStore.getState(), @@ -87,6 +80,47 @@ function getState(){ return state } +// +// public store +// + +// get init state +var initPublicState = extend( + idStoreToPublic(idStore.getState()), + configToPublic(configManager.getConfig()) +) + +var publicConfigStore = new HostStore(initPublicState) + +// subscribe to changes +configManager.subscribe(function(state){ + storeSetFromObj(publicConfigStore, configToPublic(state)) +}) +idStore.on('update', function(state){ + storeSetFromObj(publicConfigStore, idStoreToPublic(state)) +}) + +// idStore substate +function idStoreToPublic(state){ + return { + selectedAddress: state.selectedAddress, + } +} +// config substate +function configToPublic(state){ + return { + provider: state.provider, + } +} +// dump obj into store +function storeSetFromObj(store, obj){ + Object.keys(obj).forEach(function(key){ + store.set(key, obj[key]) + }) +} + + + // handle rpc requests function onRpcRequest(remoteStream, payload){ // console.log('MetaMaskPlugin - incoming payload:', payload) diff --git a/app/scripts/inpage.js b/app/scripts/inpage.js index b59cf1b0c..e6684cbd4 100644 --- a/app/scripts/inpage.js +++ b/app/scripts/inpage.js @@ -9,7 +9,7 @@ const Web3 = require('web3') delete window.Web3 window.MetamaskWeb3 = Web3 -const RPC_URL = 'https://testrpc.metamask.io/' +const DEFAULT_RPC_URL = 'https://rpc.metamask.io/' // @@ -27,12 +27,13 @@ var remoteProvider = new StreamProvider() remoteProvider.pipe(mx.createStream('provider')).pipe(remoteProvider) remoteProvider.on('error', console.error.bind(console)) -var publicConfigStore = new RemoteStore() +var initState = JSON.parse(localStorage['MetaMask-Config'] || '{}') +var publicConfigStore = new RemoteStore(initState) var storeStream = publicConfigStore.createStream() storeStream.pipe(mx.createStream('publicConfig')).pipe(storeStream) publicConfigStore.subscribe(function(state){ - console.log('store updated:', state) + localStorage['MetaMask-Config'] = JSON.stringify(state) }) @@ -52,42 +53,39 @@ console.log('MetaMask - injected web3') // handle synchronous requests // -// handle accounts cache -var accountsCache = JSON.parse(localStorage['MetaMask-Accounts'] || '[]') -web3.eth.defaultAccount = accountsCache[0] +global.publicConfigStore = publicConfigStore -setInterval(populateAccountsCache, 4000) -function populateAccountsCache(){ - remoteProvider.sendAsync(createPayload({ - method: 'eth_accounts', - params: [], - isMetamaskInternal: true, - }), function(err, response){ - if (err) return console.error('MetaMask - Error polling accounts') - // update localStorage - var accounts = response.result - if (accounts.toString() !== accountsCache.toString()) { - accountsCache = accounts - web3.eth.defaultAccount = accountsCache[0] - localStorage['MetaMask-Accounts'] = JSON.stringify(accounts) - } - }) -} +// set web3 defaultAcount +publicConfigStore.subscribe(function(state){ + web3.eth.defaultAccount = state.selectedAddress +}) -// handle synchronous methods via standard http provider -var syncProvider = new Web3.providers.HttpProvider(RPC_URL) +// setup sync http provider +var providerConfig = publicConfigStore.get('provider') || {} +var providerUrl = providerConfig.rpcTarget ? providerConfig.rpcTarget : DEFAULT_RPC_URL +var syncProvider = new Web3.providers.HttpProvider(providerUrl) +publicConfigStore.subscribe(function(state){ + if (!state.provider) return + if (!state.provider.rpcTarget || state.provider.rpcTarget === providerUrl) return + providerUrl = state.provider.rpcTarget + syncProvider = new Web3.providers.HttpProvider(providerUrl) +}) + +// handle sync methods remoteProvider.send = function(payload){ var result = null switch (payload.method) { case 'eth_accounts': // read from localStorage - result = accountsCache + var selectedAddress = publicConfigStore.get('selectedAddress') + result = selectedAddress ? [selectedAddress] : [] break case 'eth_coinbase': // read from localStorage - result = accountsCache[0] || '0x0000000000000000000000000000000000000000' + var selectedAddress = publicConfigStore.get('selectedAddress') + result = selectedAddress || '0x0000000000000000000000000000000000000000' break // fallback to normal rpc diff --git a/app/scripts/lib/config-manager.js b/app/scripts/lib/config-manager.js index c557891fe..f024729cc 100644 --- a/app/scripts/lib/config-manager.js +++ b/app/scripts/lib/config-manager.js @@ -15,6 +15,8 @@ const migrations = require('./migrations') */ module.exports = ConfigManager function ConfigManager() { + // ConfigManager is observable and will emit updates + this._subs = [] /* The migrator exported on the config-manager * has two methods the user should be concerned with: @@ -47,6 +49,7 @@ ConfigManager.prototype.setConfig = function(config) { var data = this.migrator.getData() data.config = config this.setData(data) + this._emitUpdates(config) } ConfigManager.prototype.getConfig = function() { @@ -127,6 +130,30 @@ ConfigManager.prototype.clearWallet = function() { this.setData(data) } +ConfigManager.prototype.setData = function(data) { + this.migrator.saveData(data) +} + +// observable + +ConfigManager.prototype.subscribe = function(fn){ + this._subs.push(fn) + var unsubscribe = this.unsubscribe.bind(this, fn) + return unsubscribe +} + +ConfigManager.prototype.unsubscribe = function(fn){ + var index = this._subs.indexOf(fn) + if (index !== -1) this._subs.splice(index, 1) +} + +ConfigManager.prototype._emitUpdates = function(state){ + this._subs.forEach(function(handler){ + handler(state) + }) +} + + function loadData() { var oldData = getOldStyleData()