parent
27790b38a9
commit
00e9f3c6ae
@ -0,0 +1,37 @@ |
||||
const once = require('once') |
||||
const ensnare = require('./ensnare.js') |
||||
|
||||
module.exports = setupDappAutoReload |
||||
|
||||
|
||||
function setupDappAutoReload(web3, controlStream){ |
||||
|
||||
// export web3 as a global, checking for usage
|
||||
var pageIsUsingWeb3 = false |
||||
var resetWasRequested = false |
||||
global.web3 = ensnare(web3, once(function(){ |
||||
// if web3 usage happened after a reset request, trigger reset late
|
||||
if (resetWasRequested) return triggerReset() |
||||
// mark web3 as used
|
||||
pageIsUsingWeb3 = true |
||||
// reset web3 reference
|
||||
global.web3 = web3 |
||||
})) |
||||
|
||||
// listen for reset requests from metamask
|
||||
controlStream.once('data', function(){ |
||||
resetWasRequested = true |
||||
// ignore if web3 was not used
|
||||
if (!pageIsUsingWeb3) return |
||||
// reload after short timeout
|
||||
triggerReset() |
||||
}) |
||||
|
||||
// reload the page
|
||||
function triggerReset(){ |
||||
setTimeout(function(){ |
||||
global.location.reload() |
||||
}, 500) |
||||
} |
||||
|
||||
} |
@ -0,0 +1,24 @@ |
||||
module.exports = ensnare |
||||
|
||||
// creates a proxy object that calls cb everytime the obj's properties/fns are accessed
|
||||
function ensnare(obj, cb){ |
||||
var proxy = {} |
||||
Object.keys(obj).forEach(function(key){ |
||||
var val = obj[key] |
||||
switch (typeof val) { |
||||
case 'function': |
||||
proxy[key] = function(){ |
||||
cb() |
||||
val.apply(obj, arguments) |
||||
} |
||||
return |
||||
default: |
||||
Object.defineProperty(proxy, key, { |
||||
get: function(){ cb(); return obj[key] }, |
||||
set: function(val){ cb(); return obj[key] = val }, |
||||
}) |
||||
return |
||||
} |
||||
}) |
||||
return proxy |
||||
} |
@ -0,0 +1,123 @@ |
||||
const HttpProvider = require('web3/lib/web3/httpprovider') |
||||
const Streams = require('mississippi') |
||||
const ObjectMultiplex = require('./obj-multiplex') |
||||
const StreamProvider = require('./stream-provider.js') |
||||
const RemoteStore = require('./remote-store.js').RemoteStore |
||||
const MetamaskConfig = require('../config.js') |
||||
|
||||
module.exports = MetamaskInpageProvider |
||||
|
||||
|
||||
function MetamaskInpageProvider(connectionStream){ |
||||
const self = this |
||||
|
||||
// setup connectionStream multiplexing
|
||||
var multiStream = ObjectMultiplex() |
||||
Streams.pipe(connectionStream, multiStream, connectionStream, function(err){ |
||||
console.warn('MetamaskInpageProvider - lost connection to MetaMask') |
||||
if (err) throw err |
||||
}) |
||||
self.multiStream = multiStream |
||||
|
||||
// subscribe to metamask public config
|
||||
var publicConfigStore = remoteStoreWithLocalStorageCache('MetaMask-Config') |
||||
var storeStream = publicConfigStore.createStream() |
||||
Streams.pipe(storeStream, multiStream.createStream('publicConfig'), storeStream, function(err){ |
||||
console.warn('MetamaskInpageProvider - lost connection to MetaMask publicConfig') |
||||
if (err) throw err |
||||
}) |
||||
self.publicConfigStore = publicConfigStore |
||||
|
||||
// connect to sync provider
|
||||
self.syncProvider = createSyncProvider(publicConfigStore.get('provider')) |
||||
// subscribe to publicConfig to update the syncProvider on change
|
||||
publicConfigStore.subscribe(function(state){ |
||||
self.syncProvider = createSyncProvider(state.provider) |
||||
}) |
||||
|
||||
// connect to async provider
|
||||
var asyncProvider = new StreamProvider() |
||||
Streams.pipe(asyncProvider, multiStream.createStream('provider'), asyncProvider, function(err){ |
||||
console.warn('MetamaskInpageProvider - lost connection to MetaMask provider') |
||||
if (err) throw err |
||||
}) |
||||
asyncProvider.on('error', console.error.bind(console)) |
||||
self.asyncProvider = asyncProvider |
||||
// overwrite own sendAsync method
|
||||
self.sendAsync = asyncProvider.sendAsync.bind(asyncProvider) |
||||
} |
||||
|
||||
MetamaskInpageProvider.prototype.send = function(payload){ |
||||
const self = this |
||||
|
||||
var result = null |
||||
switch (payload.method) { |
||||
|
||||
case 'eth_accounts': |
||||
// read from localStorage
|
||||
var selectedAddress = self.publicConfigStore.get('selectedAddress') |
||||
result = selectedAddress ? [selectedAddress] : [] |
||||
break |
||||
|
||||
case 'eth_coinbase': |
||||
// read from localStorage
|
||||
var selectedAddress = self.publicConfigStore.get('selectedAddress') |
||||
result = selectedAddress || '0x0000000000000000000000000000000000000000' |
||||
break |
||||
|
||||
// fallback to normal rpc
|
||||
default: |
||||
return self.syncProvider.send(payload) |
||||
|
||||
} |
||||
|
||||
// return the result
|
||||
return { |
||||
id: payload.id, |
||||
jsonrpc: payload.jsonrpc, |
||||
result: result, |
||||
} |
||||
} |
||||
|
||||
MetamaskInpageProvider.prototype.sendAsync = function(){ |
||||
throw new Error('MetamaskInpageProvider - sendAsync not overwritten') |
||||
} |
||||
|
||||
MetamaskInpageProvider.prototype.isConnected = function(){ |
||||
return true |
||||
} |
||||
|
||||
// util
|
||||
|
||||
function createSyncProvider(providerConfig){ |
||||
providerConfig = providerConfig || {} |
||||
var syncProviderUrl = undefined |
||||
|
||||
if (providerConfig.rpcTarget) { |
||||
syncProviderUrl = providerConfig.rpcTarget |
||||
} else { |
||||
switch(providerConfig.type) { |
||||
case 'testnet': |
||||
syncProviderUrl = MetamaskConfig.network.testnet |
||||
break |
||||
case 'mainnet': |
||||
syncProviderUrl = MetamaskConfig.network.mainnet |
||||
break |
||||
default: |
||||
syncProviderUrl = MetamaskConfig.network.default |
||||
} |
||||
} |
||||
return new HttpProvider(syncProviderUrl) |
||||
} |
||||
|
||||
function remoteStoreWithLocalStorageCache(storageKey){ |
||||
// read local cache
|
||||
var initState = JSON.parse(localStorage[storageKey] || '{}') |
||||
var store = new RemoteStore(initState) |
||||
// cache the latest state locally
|
||||
store.subscribe(function(state){ |
||||
localStorage[storageKey] = JSON.stringify(state) |
||||
}) |
||||
|
||||
return store |
||||
} |
Loading…
Reference in new issue