2017-01-24 19:47:00 -08:00
const pipe = require ( 'pump' )
2016-05-22 18:02:27 -07:00
const StreamProvider = require ( 'web3-stream-provider' )
2017-01-24 19:47:00 -08:00
const LocalStorageStore = require ( 'obs-store' )
2016-10-12 12:35:55 -07:00
const ObjectMultiplex = require ( './obj-multiplex' )
2016-11-17 13:49:46 -08:00
const createRandomId = require ( './random-id' )
2016-05-22 15:23:16 -07:00
module . exports = MetamaskInpageProvider
2016-06-21 13:18:32 -07:00
function MetamaskInpageProvider ( connectionStream ) {
2016-05-22 15:23:16 -07:00
const self = this
2016-06-21 13:18:32 -07:00
// setup connectionStream multiplexing
2017-01-24 19:47:00 -08:00
var multiStream = self . multiStream = ObjectMultiplex ( )
pipe (
connectionStream ,
multiStream ,
connectionStream ,
( err ) => logStreamDisconnectWarning ( 'MetaMask' , err )
)
// subscribe to metamask public config (one-way)
self . publicConfigStore = new LocalStorageStore ( { storageKey : 'MetaMask-Config' } )
pipe (
multiStream . createStream ( 'publicConfig' ) ,
self . publicConfigStore ,
( err ) => logStreamDisconnectWarning ( 'MetaMask PublicConfigStore' , err )
)
2016-05-22 15:23:16 -07:00
// connect to async provider
2017-01-24 19:47:00 -08:00
const asyncProvider = self . asyncProvider = new StreamProvider ( )
pipe (
asyncProvider ,
multiStream . createStream ( 'provider' ) ,
asyncProvider ,
( err ) => logStreamDisconnectWarning ( 'MetaMask RpcProvider' , err )
)
2016-10-05 11:10:39 -07:00
2016-08-31 15:40:05 -07:00
self . idMap = { }
2016-08-22 18:59:15 -07:00
// handle sendAsync requests via asyncProvider
2016-11-11 10:26:12 -08:00
self . sendAsync = function ( payload , cb ) {
2016-08-22 18:59:15 -07:00
// rewrite request ids
2016-08-31 15:40:05 -07:00
var request = eachJsonMessage ( payload , ( message ) => {
var newId = createRandomId ( )
self . idMap [ newId ] = message . id
message . id = newId
2016-08-22 18:59:15 -07:00
return message
} )
// forward to asyncProvider
2016-11-11 10:26:12 -08:00
asyncProvider . sendAsync ( request , function ( err , res ) {
2016-08-31 15:40:05 -07:00
if ( err ) return cb ( err )
// transform messages to original ids
eachJsonMessage ( res , ( message ) => {
var oldId = self . idMap [ message . id ]
delete self . idMap [ message . id ]
message . id = oldId
return message
} )
cb ( null , res )
} )
2016-08-22 18:59:15 -07:00
}
2016-05-22 15:23:16 -07:00
}
2016-06-21 13:18:32 -07:00
MetamaskInpageProvider . prototype . send = function ( payload ) {
2016-05-22 15:23:16 -07:00
const self = this
2016-10-05 11:10:39 -07:00
2017-01-30 15:25:12 -08:00
let selectedAddress
2016-08-11 13:31:00 -07:00
let result = null
2016-05-22 15:23:16 -07:00
switch ( payload . method ) {
case 'eth_accounts' :
// read from localStorage
2017-01-30 15:25:12 -08:00
selectedAddress = self . publicConfigStore . getState ( ) . selectedAddress
result = selectedAddress ? [ selectedAddress ] : [ ]
2016-05-22 15:23:16 -07:00
break
case 'eth_coinbase' :
// read from localStorage
2017-01-30 15:25:12 -08:00
selectedAddress = self . publicConfigStore . getState ( ) . selectedAddress
result = selectedAddress
2016-05-22 15:23:16 -07:00
break
2016-11-23 10:48:20 -08:00
case 'eth_uninstallFilter' :
self . sendAsync ( payload , noop )
result = true
break
2017-02-08 15:51:22 -08:00
case 'net_version' :
let networkVersion = self . publicConfigStore . getState ( ) . networkVersion
result = networkVersion
break
2016-08-11 13:23:49 -07:00
// throw not-supported Error
2016-05-22 15:23:16 -07:00
default :
2016-10-05 11:10:39 -07:00
var link = 'https://github.com/MetaMask/faq/blob/master/DEVELOPERS.md#dizzy-all-async---think-of-metamask-as-a-light-client'
2016-10-19 15:16:27 -07:00
var message = ` The MetaMask Web3 object does not support synchronous methods like ${ payload . method } without a callback parameter. See ${ link } for details. `
2016-08-11 13:23:49 -07:00
throw new Error ( message )
2016-05-22 15:23:16 -07:00
}
// return the result
return {
id : payload . id ,
jsonrpc : payload . jsonrpc ,
result : result ,
}
}
2016-06-21 13:18:32 -07:00
MetamaskInpageProvider . prototype . sendAsync = function ( ) {
2016-05-22 15:23:16 -07:00
throw new Error ( 'MetamaskInpageProvider - sendAsync not overwritten' )
}
2016-06-21 13:18:32 -07:00
MetamaskInpageProvider . prototype . isConnected = function ( ) {
2016-05-22 15:23:16 -07:00
return true
}
2017-01-02 12:20:09 -08:00
MetamaskInpageProvider . prototype . isMetaMask = true
2016-05-22 15:23:16 -07:00
// util
2016-11-18 16:27:26 -08:00
function eachJsonMessage ( payload , transformFn ) {
2016-08-22 18:59:15 -07:00
if ( Array . isArray ( payload ) ) {
return payload . map ( transformFn )
} else {
return transformFn ( payload )
}
2016-09-05 20:20:22 -07:00
}
2016-11-23 10:48:20 -08:00
2017-01-24 19:47:00 -08:00
function logStreamDisconnectWarning ( remoteLabel , err ) {
let warningMsg = ` MetamaskInpageProvider - lost connection to ${ remoteLabel } `
if ( err ) warningMsg += '\n' + err . stack
console . warn ( warningMsg )
}
2016-11-23 10:48:20 -08:00
function noop ( ) { }