zoukankan      html  css  js  c++  java
  • MetaMask/metamask-inpage-provider

    https://github.com/MetaMask/metamask-inpage-provider

    Used to initialize the inpage ethereum provider injected by MetaMask.

    Installation

    npm install metamask-inpage-provider -S

     

    metamask-inpage-provider/createErrorMiddleware.js

    处理JSON-RPC调用是出现的错误,并将错误记录到日志中

    loglevel是JavaScript的最小轻量级日志记录,它没有控制台的缺点,替代了console.log()并且对于基于级别的日志和过滤是十分友好的,本博客loglevel-metamask

    const log = require('loglevel')
    
    /**
     * JSON-RPC error object
     *
     * @typedef {Object} RpcError
     * @property {number} code - Indicates the error type that occurred
     * @property {Object} [data] - Contains additional information about the error
     * @property {string} [message] - Short description of the error
     */
    
    /**
     * Middleware configuration object
     *
     * @typedef {Object} MiddlewareConfig
     * @property {boolean} [override] - Use RPC_ERRORS message in place of provider message
     */
    
    /**
     * Map of standard and non-standard RPC error codes to messages
     */
    const RPC_ERRORS = {
      1: 'An unauthorized action was attempted.',
      2: 'A disallowed action was attempted.',
      3: 'An execution error occurred.',
      [-32600]: 'The JSON sent is not a valid Request object.',
      [-32601]: 'The method does not exist / is not available.',
      [-32602]: 'Invalid method parameter(s).',
      [-32603]: 'Internal JSON-RPC error.',
      [-32700]: 'Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.',
      internal: 'Internal server error.',
      unknown: 'Unknown JSON-RPC error.',
    }
    
    /**
     * Modifies a JSON-RPC error object in-place to add a human-readable message,
     * optionally overriding any provider-supplied message
     *
     * @param {RpcError} error - JSON-RPC error object
     * @param {boolean} override - Use RPC_ERRORS message in place of provider message
     */
    function sanitizeRPCError (error, override) {
      if (error.message && !override) { return error }
      const message = error.code > -31099 && error.code < -32100 ? RPC_ERRORS.internal : RPC_ERRORS[error.code]//判断错误类型并获得错误message
      error.message = message || RPC_ERRORS.unknown
    }
    
    /**
     * json-rpc-engine middleware that both logs standard and non-standard error
     * messages and ends middleware stack traversal if an error is encountered
     *
     * @param {MiddlewareConfig} [config={override:true}] - Middleware configuration
     * @returns {Function} json-rpc-engine middleware function
     */
    function createErrorMiddleware ({ override = true } = {}) {
      return (req, res, next) => {
        next(done => {
          const { error } = res
          if (!error) { return done() }
          sanitizeRPCError(error)
          log.error(`MetaMask - RPC Error: ${error.message}`, error)
          done()
        })
      }
    }
    
    module.exports = createErrorMiddleware

    metamask-inpage-provider/index.js

    这个库的作用有设置浏览器本地信息存储publicConfig流、构建RpcProvider双向传送json rpc及其结果流,以及对从浏览器中得到的json rpc进行处理,send/sendsync的处理是不同的,然后将他们根据得到的特殊id存储到数组中,等待传送到区块链进行处理

    const pump = require('pump')//看本博客pump模块的学习-metamask
    const RpcEngine = require('json-rpc-engine')//看本博客MetaMask/json-rpc-engine
    const createErrorMiddleware = require('./createErrorMiddleware')//检查json rpc产生的错误
    const createIdRemapMiddleware = require('json-rpc-engine/src/idRemapMiddleware')创建一个独特的id来标识json rpc,不然它的id很多都是相同的1,2等,看本博客MetaMask/json-rpc-engine
    const createJsonRpcStream = require('json-rpc-middleware-stream')//看本博客的MetaMask/json-rpc-middleware-stream
    const LocalStorageStore = require('obs-store')//看本博客MetaMask/obs-store
    const asStream = require('obs-store/lib/asStream')//看本博客MetaMask/obs-store
    const ObjectMultiplex = require('obj-multiplex')//看博客kumavis/obj-multiplex
    const util = require('util')
    const SafeEventEmitter = require('safe-event-emitter')//看博客MetaMask/safe-event-emitter
    
    module.exports = MetamaskInpageProvider
    
    util.inherits(MetamaskInpageProvider, SafeEventEmitter)
    
    function MetamaskInpageProvider (connectionStream) {
      const self = this
    
      // super constructor
      SafeEventEmitter.call(self)
    
      // setup connectionStream multiplexing
      const mux = self.mux = new ObjectMultiplex()
      pump(
        connectionStream,
        mux,
        connectionStream,
        logStreamDisconnectWarning.bind(this, 'MetaMask')
      )
    
      // subscribe to metamask public config (one-way)
      self.publicConfigStore = new LocalStorageStore({ storageKey: 'MetaMask-Config' })//定义了一个在浏览器中storageKey为'MetaMask-Config'的本地存储,用于存储一些区块链的账户信息,网络信息
    
      pump(//进行浏览器本地信息存储
        mux.createStream('publicConfig'),//创建name为publicConfig的子流
        asStream(self.publicConfigStore),
        logStreamDisconnectWarning.bind(this, 'MetaMask PublicConfigStore')//logStreamDisconnectWarning函数下面有定义,'MetaMask PublicConfigStore'为error说明,
      )
    
      // ignore phishing warning message (handled elsewhere)
      mux.ignoreStream('phishing')//这里不对name为phishing的流进行处理
    
      // connect to async provider
      const jsonRpcConnection = createJsonRpcStream()//
      pump(//构建provider,接受浏览器传来的json rpc,并响应
        jsonRpcConnection.stream,
        mux.createStream('provider'),
        jsonRpcConnection.stream,
        logStreamDisconnectWarning.bind(this, 'MetaMask RpcProvider')
      )
    
      // handle sendAsync requests via dapp-side rpc engine
      const rpcEngine = new RpcEngine() 看了本博客MetaMask/json-rpc-engine后,可以知道这是push进将要对接受到的json rpc调用的处理
      rpcEngine.push(createIdRemapMiddleware())//获得个unique id拿来使用
      rpcEngine.push(createErrorMiddleware()) //进行错误的处理
      rpcEngine.push(jsonRpcConnection.middleware) //将json rpc 请求写入createJsonRpcStream双工流中
      self.rpcEngine = rpcEngine
    
      // forward json rpc notifications
      jsonRpcConnection.events.on('notification', function(payload) {//设置json-rpc-middleware-stream流相应的'notification'事件
        self.emit('data', null, payload) //触发data事件
      })
    
      // Work around for https://github.com/metamask/metamask-extension/issues/5459
      // drizzle accidently breaking the `this` reference
      self.send = self.send.bind(self)
      self.sendAsync = self.sendAsync.bind(self)
    }
    
    // Web3 1.0 provider uses `send` with a callback for async queries
    MetamaskInpageProvider.prototype.send = function (payload, callback) {//web3调用send()
      const self = this
    
      if (callback) {//如果是异步带回调的,就调用sendAsync
        self.sendAsync(payload, callback)
      } else {//否则就调用_sendSync
        return self._sendSync(payload)
      }
    }
    
    // handle sendAsync requests via asyncProvider
    // also remap ids inbound and outbound
    MetamaskInpageProvider.prototype.sendAsync = function (payload, cb) {
      const self = this
    
      if (payload.method === 'eth_signTypedData') {
        console.warn('MetaMask: This experimental version of eth_signTypedData will be deprecated in the next release in favor of the standard as defined in EIP-712. See https://git.io/fNzPl for more information on the new standard.')
      }
    
      self.rpcEngine.handle(payload, cb)//该json rpc就会被处理
    }
    
    MetamaskInpageProvider.prototype._sendSync = function (payload) {
      const self = this
    
      let selectedAddress
      let result = null
      switch (payload.method) {
    
        case 'eth_accounts':
          // read from localStorage
          selectedAddress = self.publicConfigStore.getState().selectedAddress //从本地存储中获得账户信息
          result = selectedAddress ? [selectedAddress] : []
          break
    
        case 'eth_coinbase':
          // read from localStorage
          selectedAddress = self.publicConfigStore.getState().selectedAddress//从本地存储中获得账户信息
          result = selectedAddress || null
          break
    
        case 'eth_uninstallFilter':
          self.sendAsync(payload, noop) //设置回调为{}再调用sendAsync
          result = true
          break
    
        case 'net_version':
          const networkVersion = self.publicConfigStore.getState().networkVersion//从本地存储中获得网络信息
          result = networkVersion || null
          break
    
        // throw not-supported Error
        default:
          var link = 'https://github.com/MetaMask/faq/blob/master/DEVELOPERS.md#dizzy-all-async---think-of-metamask-as-a-light-client'
          var message = `The MetaMask Web3 object does not support synchronous methods like ${payload.method} without a callback parameter. See ${link} for details.`
          throw new Error(message)
    
      }
    
      // return the result
      return {
        id: payload.id,
        jsonrpc: payload.jsonrpc,
        result: result,
      }
    }
    
    MetamaskInpageProvider.prototype.isConnected = function () {
      return true
    }
    
    MetamaskInpageProvider.prototype.isMetaMask = true
    
    // util
    
    function logStreamDisconnectWarning (remoteLabel, err) {
      let warningMsg = `MetamaskInpageProvider - lost connection to ${remoteLabel}`
      if (err) warningMsg += '
    ' + err.stack
      console.warn(warningMsg)
      const listeners = this.listenerCount('error')
      if (listeners > 0) {
        this.emit('error', warningMsg)
      }
    }
    
    function noop () {}

    Usage

    MetamaskInpageProvider的使用:
    // Create a stream to a remote provider:
    var metamaskStream = new LocalMessageDuplexStream({
      name: 'inpage',
      target: 'contentscript',
    })
    
    // compose the inpage provider
    var inpageProvider = new MetamaskInpageProvider(metamaskStream)
     
  • 相关阅读:
    mac os 基本命令
    一个程序员的郁闷吐槽
    域名那些事儿
    EventEmitter事件派发器
    Array类型的操作方法
    居中与垂直居中
    Web Storage —— 登录时记住密码
    字符串字符统计
    颜色字符串转换(正则)
    将字符串转换为驼峰格式
  • 原文地址:https://www.cnblogs.com/wanghui-garcia/p/9885472.html
Copyright © 2011-2022 走看看