Skip to content

Commit

Permalink
Web3 1.0 "subscription" support
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewlilley committed Apr 18, 2018
1 parent 1c89267 commit 65d907f
Show file tree
Hide file tree
Showing 7 changed files with 1,008 additions and 13,914 deletions.
14 changes: 14 additions & 0 deletions app/scripts/inpage.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,20 @@ inpageProvider.publicConfigStore.subscribe(function (state) {
web3.eth.defaultAccount = state.selectedAddress
})

// clear subscriptions
function clearSubscriptions () {
if (inpageProvider.subscriptions) {

This comment has been minimized.

Copy link
@ryan-rowland

ryan-rowland Apr 19, 2018

Contributor

nit: Can we de-nest by bailing early? eg

function clearSubscriptions() {
  if (!inpageProvider.subscriptions) { return }

  inpageProvider.sendAsync(...)
}
inpageProvider.sendAsync({
jsonrpc: '2.0',
method: 'eth_unsubscribe',
params: inpageProvider.subscriptions,
}, () => {
console.log('cleared subscriptions')
})
}
}
window.onbeforeunload = clearSubscriptions

//
// util
//
Expand Down
59 changes: 53 additions & 6 deletions app/scripts/lib/inpage-provider.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
const pump = require('pump')
const RpcEngine = require('json-rpc-engine')
const asStream = require('obs-store/lib/asStream')
const createIdRemapMiddleware = require('json-rpc-engine/src/idRemapMiddleware')
const createStreamMiddleware = require('json-rpc-middleware-stream')
const EventEmitter = require('events')
const { inherits } = require('util')
const LocalStorageStore = require('obs-store')
const asStream = require('obs-store/lib/asStream')
const ObjectMultiplex = require('obj-multiplex')
const pump = require('pump')
const RpcEngine = require('json-rpc-engine')
const { noop, override } = require('./util')

module.exports = MetamaskInpageProvider

inherits(MetamaskInpageProvider, EventEmitter)

function MetamaskInpageProvider (connectionStream) {
const self = this
EventEmitter.call(self)

// setup connectionStream multiplexing
const mux = self.mux = new ObjectMultiplex()
Expand All @@ -34,6 +40,22 @@ function MetamaskInpageProvider (connectionStream) {

// connect to async provider
const streamMiddleware = createStreamMiddleware()
override(streamMiddleware.stream, 'write', function (original) {
return function (res, encoding, cb) {
// eth_subscription's do not have an id, therfore cannot be remapped
// responses should be emitted onto the web3 current provider
if (res.method === 'eth_subscription') {
// if has subscription registered on inpage provider, emit subscription
// data onto the current provider
if (self.subscriptions.indexOf(res.params.subscription) > -1) {
self.emit('data', res)
}
} else {
// call original funtion
original.apply(this, arguments)
}
}
})
pump(
streamMiddleware.stream,
mux.createStream('provider'),
Expand All @@ -46,16 +68,41 @@ function MetamaskInpageProvider (connectionStream) {
rpcEngine.push(createIdRemapMiddleware())
rpcEngine.push(streamMiddleware)
self.rpcEngine = rpcEngine

// subscription ids
self.subscriptions = []

This comment has been minimized.

Copy link
@ryan-rowland

ryan-rowland Apr 19, 2018

Contributor

I still think self.subscriptionIds would be more accurate here.

}

MetamaskInpageProvider.prototype._handleSubscriptionRequest = function (payload, cb) {
const self = this
self.rpcEngine.handle(payload, (error, response) => {
if (error) {
cb(error, null)
} else {
payload.method === 'eth_subscribe' ?
self.subscriptions.push(response.result) :
payload.params.forEach(p => {
self.subscriptions = self.subscriptions.filter(s => s !== p)
})
cb(null, response)
}
})
}

MetamaskInpageProvider.prototype._handleRequest = function (payload, cb) {
const self = this
isSubscriptionRequest(payload) ?
self._handleSubscriptionRequest(payload, cb) :
self.rpcEngine.handle(payload, cb)
}

// handle sendAsync requests via asyncProvider
// also remap ids inbound and outbound
MetamaskInpageProvider.prototype.sendAsync = function (payload, cb) {
const self = this
self.rpcEngine.handle(payload, cb)
self._handleRequest(payload, cb)
}


MetamaskInpageProvider.prototype.send = function (payload) {
const self = this

Expand Down Expand Up @@ -115,4 +162,4 @@ function logStreamDisconnectWarning (remoteLabel, err) {
console.warn(warningMsg)
}

function noop () {}
function isSubscriptionRequest (request) { return request.method === 'eth_subscribe' || request.method === 'eth_unsubscribe' }
8 changes: 8 additions & 0 deletions app/scripts/lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,19 @@ function BnMultiplyByFraction (targetBN, numerator, denominator) {
return targetBN.mul(numBN).div(denomBN)
}

function override (object, methodName, callback) {
object[methodName] = callback(object[methodName])
}

function noop () {}

module.exports = {
getStack,
getEnvironmentType,
sufficientBalance,
hexToBn,
bnToHex,
BnMultiplyByFraction,
override,
noop,
}
10 changes: 5 additions & 5 deletions app/scripts/metamask-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ module.exports = class MetamaskController extends EventEmitter {

/**
* @constructor
* @param {Object} opts
* @param {Object} opts
*/
constructor (opts) {
super()
Expand Down Expand Up @@ -398,8 +398,6 @@ module.exports = class MetamaskController extends EventEmitter {
}
}



//=============================================================================
// VAULT / KEYRING RELATED METHODS
//=============================================================================
Expand Down Expand Up @@ -832,13 +830,13 @@ module.exports = class MetamaskController extends EventEmitter {
cb(null, this.getState())
}

markPasswordForgotten(cb) {
markPasswordForgotten (cb) {
this.configManager.setPasswordForgotten(true)
this.sendUpdate()
cb()
}

unMarkPasswordForgotten(cb) {
unMarkPasswordForgotten (cb) {
this.configManager.setPasswordForgotten(false)
this.sendUpdate()
cb()
Expand Down Expand Up @@ -912,6 +910,8 @@ module.exports = class MetamaskController extends EventEmitter {

// setup connection
const providerStream = createEngineStream({ engine })
// data event listener
this.provider.on('data', (err, data) => !err ? providerStream.emit('data', data) : log.error(err))
pump(
outStream,
providerStream,
Expand Down
Loading

0 comments on commit 65d907f

Please sign in to comment.