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 PortStream = require('./lib/port-stream.js')
const ObjectMultiplex = require('./lib/obj-multiplex')
// inject in-page script
@ -15,13 +17,22 @@ var pageStream = new LocalMessageDuplexStream({
name: 'contentscript',
target: 'inpage',
})
pageStream.on('error', console.error.bind(console))
var pluginPort = chrome.runtime.connect({name: 'contentscript'})
var pluginStream = new PortStream(pluginPort)
pluginStream.on('error', console.error.bind(console))
// forward communication across
pageStream.pipe(pluginStream)
pluginStream.pipe(pageStream)
// forward communication plugin->inpage
pageStream.pipe(pluginStream).pipe(pageStream)
// log errors
pageStream.on('error', console.error.bind(console))
pluginStream.on('error', console.error.bind(console))
// 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 RemoteStore = require('./lib/remote-store.js').RemoteStore
const Web3 = require('web3')
const once = require('once')
restoreContextAfterImports()
// rename on window
@ -24,32 +25,61 @@ var pluginStream = new LocalMessageDuplexStream({
target: 'contentscript',
})
var mx = setupMultiplex(pluginStream)
// connect features
// connect to provider
var remoteProvider = new StreamProvider()
remoteProvider.pipe(mx.createStream('provider')).pipe(remoteProvider)
remoteProvider.on('error', console.error.bind(console))
// subscribe to metamask public config
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){
localStorage['MetaMask-Config'] = JSON.stringify(state)
})
//
// global web3
// setup web3
//
var web3 = new Web3(remoteProvider)
window.web3 = web3
web3.setProvider = function(){
console.log('MetaMask - overrode web3.setProvider')
}
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
@ -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
// and that we dont affect the app with our namespace
// mostly a fix for web3's BigNumber if AMD's "define" is defined...
@ -116,4 +174,4 @@ function cleanContextForImports(){
function restoreContextAfterImports(){
global.define = __define
}
}

View File

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

View File

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

View File

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

View File

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