1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

inpage - automatic dapp reload

This commit is contained in:
kumavis 2016-05-05 16:04:43 -07:00
parent b863fe16e8
commit aa2816010d
6 changed files with 92 additions and 17 deletions

View File

@ -1,5 +1,7 @@
const LocalMessageDuplexStream = require('./lib/local-message-stream.js') const LocalMessageDuplexStream = require('./lib/local-message-stream.js')
const PortStream = require('./lib/port-stream.js') const PortStream = require('./lib/port-stream.js')
const ObjectMultiplex = require('./lib/obj-multiplex')
// inject in-page script // inject in-page script
@ -15,13 +17,22 @@ var pageStream = new LocalMessageDuplexStream({
name: 'contentscript', name: 'contentscript',
target: 'inpage', target: 'inpage',
}) })
pageStream.on('error', console.error.bind(console))
var pluginPort = chrome.runtime.connect({name: 'contentscript'}) var pluginPort = chrome.runtime.connect({name: 'contentscript'})
var pluginStream = new PortStream(pluginPort) var pluginStream = new PortStream(pluginPort)
// forward communication across
pageStream.pipe(pluginStream)
pluginStream.pipe(pageStream)
// log errors
pageStream.on('error', console.error.bind(console))
pluginStream.on('error', console.error.bind(console)) pluginStream.on('error', console.error.bind(console))
// forward communication plugin->inpage
pageStream.pipe(pluginStream).pipe(pageStream)
// connect contentscript->inpage control stream
var mx = ObjectMultiplex()
mx.on('error', console.error.bind(console))
mx.pipe(pageStream)
var controlStream = mx.createStream('control')
controlStream.on('error', console.error.bind(console))
// if we lose connection with the plugin, trigger tab refresh
pluginStream.on('close', function(){
controlStream.write({ method: 'reset' })
})

View File

@ -5,6 +5,7 @@ const LocalMessageDuplexStream = require('./lib/local-message-stream.js')
const setupMultiplex = require('./lib/stream-utils.js').setupMultiplex const setupMultiplex = require('./lib/stream-utils.js').setupMultiplex
const RemoteStore = require('./lib/remote-store.js').RemoteStore const RemoteStore = require('./lib/remote-store.js').RemoteStore
const Web3 = require('web3') const Web3 = require('web3')
const once = require('once')
restoreContextAfterImports() restoreContextAfterImports()
// rename on window // rename on window
@ -24,32 +25,61 @@ var pluginStream = new LocalMessageDuplexStream({
target: 'contentscript', target: 'contentscript',
}) })
var mx = setupMultiplex(pluginStream) var mx = setupMultiplex(pluginStream)
// connect features
// connect to provider
var remoteProvider = new StreamProvider() var remoteProvider = new StreamProvider()
remoteProvider.pipe(mx.createStream('provider')).pipe(remoteProvider) remoteProvider.pipe(mx.createStream('provider')).pipe(remoteProvider)
remoteProvider.on('error', console.error.bind(console)) remoteProvider.on('error', console.error.bind(console))
// subscribe to metamask public config
var initState = JSON.parse(localStorage['MetaMask-Config'] || '{}') var initState = JSON.parse(localStorage['MetaMask-Config'] || '{}')
var publicConfigStore = new RemoteStore(initState) var publicConfigStore = new RemoteStore(initState)
var storeStream = publicConfigStore.createStream() var storeStream = publicConfigStore.createStream()
storeStream.pipe(mx.createStream('publicConfig')).pipe(storeStream) storeStream.pipe(mx.createStream('publicConfig')).pipe(storeStream)
publicConfigStore.subscribe(function(state){ publicConfigStore.subscribe(function(state){
localStorage['MetaMask-Config'] = JSON.stringify(state) localStorage['MetaMask-Config'] = JSON.stringify(state)
}) })
// //
// global web3 // setup web3
// //
var web3 = new Web3(remoteProvider) var web3 = new Web3(remoteProvider)
window.web3 = web3
web3.setProvider = function(){ web3.setProvider = function(){
console.log('MetaMask - overrode web3.setProvider') console.log('MetaMask - overrode web3.setProvider')
} }
console.log('MetaMask - injected web3') console.log('MetaMask - injected web3')
//
// automatic dapp reset
//
// export web3 as a global, checking for usage
var pageIsUsingWeb3 = false
var resetWasRequested = false
window.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
window.web3 = web3
}))
// listen for reset requests
mx.createStream('control').once('data', function(){
resetWasRequested = true
// ignore if web3 was not used
if (!pageIsUsingWeb3) return
// reload after short timeout
triggerReset()
})
function triggerReset(){
setTimeout(function(){
window.location.reload()
}, 500)
}
// //
// handle synchronous requests // handle synchronous requests
@ -104,6 +134,34 @@ remoteProvider.send = function(payload){
} }
} }
//
// util
//
// 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
}
// need to make sure we aren't affected by overlapping namespaces // need to make sure we aren't affected by overlapping namespaces
// and that we dont affect the app with our namespace // and that we dont affect the app with our namespace
// mostly a fix for web3's BigNumber if AMD's "define" is defined... // mostly a fix for web3's BigNumber if AMD's "define" is defined...

View File

@ -23,7 +23,7 @@ function LocalMessageDuplexStream(opts){
LocalMessageDuplexStream.prototype._onMessage = function(event){ LocalMessageDuplexStream.prototype._onMessage = function(event){
var msg = event.data var msg = event.data
// console.log('LocalMessageDuplexStream ('+this._name+') - heard message...') // console.log('LocalMessageDuplexStream ('+this._name+') - heard message...', event)
// validate message // validate message
if (event.origin !== location.origin) return //console.log('LocalMessageDuplexStream ('+this._name+') - rejected - (event.origin !== location.origin) ') if (event.origin !== location.origin) return //console.log('LocalMessageDuplexStream ('+this._name+') - rejected - (event.origin !== location.origin) ')
if (typeof msg !== 'object') return //console.log('LocalMessageDuplexStream ('+this._name+') - rejected - (typeof msg !== "object") ') if (typeof msg !== 'object') return //console.log('LocalMessageDuplexStream ('+this._name+') - rejected - (typeof msg !== "object") ')
@ -31,7 +31,11 @@ LocalMessageDuplexStream.prototype._onMessage = function(event){
if (!msg.data) return //console.log('LocalMessageDuplexStream ('+this._name+') - rejected - (!msg.data) ') if (!msg.data) return //console.log('LocalMessageDuplexStream ('+this._name+') - rejected - (!msg.data) ')
// console.log('LocalMessageDuplexStream ('+this._name+') - accepted', msg.data) // console.log('LocalMessageDuplexStream ('+this._name+') - accepted', msg.data)
// forward message // forward message
this.push(msg.data) try {
this.push(msg.data)
} catch(err) {
this.emit('error', err)
}
} }
// stream plumbing // stream plumbing

View File

@ -31,7 +31,8 @@ PortDuplexStream.prototype._onMessage = function(msg){
PortDuplexStream.prototype._onDisconnect = function(){ PortDuplexStream.prototype._onDisconnect = function(){
try { try {
this.end() // this.end()
this.emit('close')
} catch(err){ } catch(err){
this.emit('error', err) this.emit('error', err)
} }
@ -54,6 +55,7 @@ PortDuplexStream.prototype._write = function(msg, encoding, cb){
} }
cb() cb()
} catch(err){ } catch(err){
console.error(err)
// this.emit('error', err) // this.emit('error', err)
cb(new Error('PortDuplexStream - disconnected')) cb(new Error('PortDuplexStream - disconnected'))
} }

View File

@ -27,7 +27,6 @@ function setupMultiplex(connectionStream){
connectionStream.pipe(mx).pipe(connectionStream) connectionStream.pipe(mx).pipe(connectionStream)
mx.on('error', function(err) { mx.on('error', function(err) {
console.error(err) console.error(err)
// connectionStream.destroy()
}) })
connectionStream.on('error', function(err) { connectionStream.on('error', function(err) {
console.error(err) console.error(err)

View File

@ -38,6 +38,7 @@
"inject-css": "^0.1.1", "inject-css": "^0.1.1",
"metamask-logo": "^1.1.5", "metamask-logo": "^1.1.5",
"multiplex": "^6.7.0", "multiplex": "^6.7.0",
"once": "^1.3.3",
"pojo-migrator": "^2.1.0", "pojo-migrator": "^2.1.0",
"polyfill-crypto.getrandomvalues": "^1.0.0", "polyfill-crypto.getrandomvalues": "^1.0.0",
"pumpify": "^1.3.4", "pumpify": "^1.3.4",
@ -46,7 +47,7 @@
"react-dom": "^0.14.3", "react-dom": "^0.14.3",
"react-hyperscript": "^2.2.2", "react-hyperscript": "^2.2.2",
"react-redux": "^4.0.3", "react-redux": "^4.0.3",
"readable-stream": "^2.0.5", "readable-stream": "^2.1.2",
"redux": "^3.0.5", "redux": "^3.0.5",
"redux-logger": "^2.3.1", "redux-logger": "^2.3.1",
"redux-thunk": "^1.0.2", "redux-thunk": "^1.0.2",