diff --git a/js/src/api/api.js b/js/src/api/api.js index a1a7dbbb5..5ba401c33 100644 --- a/js/src/api/api.js +++ b/js/src/api/api.js @@ -47,13 +47,6 @@ export default class Api extends EventEmitter { this._trace = new Trace(transport); this._web3 = new Web3(transport); - if (isFunction(transport.subscribe)) { - this._pubsub = new Pubsub(transport); - } - - if (allowSubscriptions) { - this._subscriptions = new Subscriptions(this); - } // Doing a request here in test env would cause an error if (LocalAccountsMiddleware && process.env.NODE_ENV !== 'test') { const middleware = this.parity @@ -69,6 +62,14 @@ export default class Api extends EventEmitter { transport.addMiddleware(middleware); } + + if (isFunction(transport.subscribe)) { + this._pubsub = new Pubsub(transport); + } + + if (allowSubscriptions) { + this._subscriptions = new Subscriptions(this); + } } get isPubSub () { diff --git a/js/src/api/local/accounts/accounts.js b/js/src/api/local/accounts/accounts.js index d11ea2bad..ec117e25d 100644 --- a/js/src/api/local/accounts/accounts.js +++ b/js/src/api/local/accounts/accounts.js @@ -18,11 +18,12 @@ import Account from './account'; import localStore from 'store'; import { debounce } from 'lodash'; import { decryptPrivateKey } from '../ethkey'; +import EventEmitter from 'eventemitter3'; const NULL_ADDRESS = '0x0000000000000000000000000000000000000000'; const LS_STORE_KEY = '_parity::localAccounts'; -export default class Accounts { +export default class Accounts extends EventEmitter { persist = debounce(() => { this._lastState = JSON.stringify(this); @@ -30,6 +31,8 @@ export default class Accounts { }, 100); constructor (data = localStore.get(LS_STORE_KEY) || {}) { + super(); + this._lastState = JSON.stringify(data); window.addEventListener('storage', ({ key, newValue }) => { @@ -130,6 +133,8 @@ export default class Accounts { set dappsDefaultAddress (value) { this._dappsDefaultAddress = value.toLowerCase(); + this.emit('dappsDefaultAddressChange', this._dappsDefaultAddress); + this.persist(); } diff --git a/js/src/api/local/localAccountsMiddleware.js b/js/src/api/local/localAccountsMiddleware.js index adfe8f50d..bc18f21b1 100644 --- a/js/src/api/local/localAccountsMiddleware.js +++ b/js/src/api/local/localAccountsMiddleware.js @@ -26,7 +26,9 @@ export default class LocalAccountsMiddleware extends Middleware { constructor (transport) { super(transport); + const NOOP = () => {}; const register = this.register.bind(this); + const registerSubscribe = this.registerSubscribe.bind(this); register('eth_accounts', () => { return accounts.accountAddresses(); @@ -76,6 +78,14 @@ export default class LocalAccountsMiddleware extends Middleware { return accounts.dappsDefaultAddress; }); + registerSubscribe('parity_defaultAccount', (_, callback) => { + callback(null, accounts.dappsDefaultAddress); + + accounts.on('dappsDefaultAddressChange', (address) => { + callback(null, accounts.dappsDefaultAddress); + }); + }); + register('parity_exportAccount', ([address, password]) => { const account = accounts.get(address); @@ -109,6 +119,8 @@ export default class LocalAccountsMiddleware extends Middleware { return {}; }); + registerSubscribe('parity_hardwareAccountsInfo', NOOP); + register('parity_newAccountFromPhrase', ([phrase, password]) => { return phraseToWallet(phrase) .then((wallet) => { @@ -278,5 +290,15 @@ export default class LocalAccountsMiddleware extends Middleware { register('signer_requestsToConfirm', () => { return transactions.requestsToConfirm(); }); + + registerSubscribe('signer_subscribePending', (_, callback) => { + callback(null, transactions.requestsToConfirm()); + + transactions.on('update', () => { + callback(null, transactions.requestsToConfirm()); + }); + + return false; + }); } } diff --git a/js/src/api/local/transactions.js b/js/src/api/local/transactions.js index 421e73012..44cf61f69 100644 --- a/js/src/api/local/transactions.js +++ b/js/src/api/local/transactions.js @@ -16,14 +16,17 @@ import { toHex } from '../util/format'; import { TransportError } from '../transport'; +import EventEmitter from 'eventemitter3'; const AWAITING = Symbol('awaiting'); const LOCKED = Symbol('locked'); const CONFIRMED = Symbol('confirmed'); const REJECTED = Symbol('rejected'); -class Transactions { +class Transactions extends EventEmitter { constructor () { + super(); + this.reset(); } @@ -45,6 +48,8 @@ class Transactions { transaction: tx }; + this.emit('update'); + return id; } @@ -66,6 +71,8 @@ class Transactions { } state.status = LOCKED; + + this.emit('update'); } unlock (id) { @@ -76,6 +83,8 @@ class Transactions { } state.status = AWAITING; + + this.emit('update'); } hash (id) { @@ -107,6 +116,8 @@ class Transactions { state.hash = hash; state.status = CONFIRMED; + + this.emit('update'); } reject (id) { @@ -118,6 +129,8 @@ class Transactions { state.status = REJECTED; + this.emit('update'); + return true; } diff --git a/js/src/api/pubsub/signer/signer.js b/js/src/api/pubsub/signer/signer.js index 266da6b8a..25db34bdd 100644 --- a/js/src/api/pubsub/signer/signer.js +++ b/js/src/api/pubsub/signer/signer.js @@ -17,7 +17,7 @@ import PubsubBase from '../pubsubBase'; import { outSignerRequest } from '../../format/output'; -export default class Net extends PubsubBase { +export default class Signer extends PubsubBase { constructor (transport) { super(transport); this._api = { diff --git a/js/src/api/subscriptions/signer.js b/js/src/api/subscriptions/signer.js index a0c202c1b..30342cfa7 100644 --- a/js/src/api/subscriptions/signer.js +++ b/js/src/api/subscriptions/signer.js @@ -38,26 +38,32 @@ export default class Signer { start () { this._started = true; - if (this._api.isPubSub) { - const subscription = this._api.pubsub - .subscribeAndGetResult( - callback => this._api.pubsub.signer.pendingRequests(callback), - requests => { - this.updateSubscriptions(requests); - return requests; - } - ); + return this + ._api + .transport + .ready + .then(() => { + if (this._api.isPubSub) { + const subscription = this._api.pubsub + .subscribeAndGetResult( + callback => this._api.pubsub.signer.pendingRequests(callback), + requests => { + this.updateSubscriptions(requests); + return requests; + } + ); - return Promise.all([ - this._listRequests(false), - subscription - ]); - } + return Promise.all([ + this._listRequests(false), + subscription + ]); + } - return Promise.all([ - this._listRequests(true), - this._loggingSubscribe() - ]); + return Promise.all([ + this._listRequests(true), + this._loggingSubscribe() + ]); + }); } updateSubscriptions (requests) { diff --git a/js/src/api/transport/jsonRpcBase.js b/js/src/api/transport/jsonRpcBase.js index 1b96347d3..9e5e18bfe 100644 --- a/js/src/api/transport/jsonRpcBase.js +++ b/js/src/api/transport/jsonRpcBase.js @@ -31,6 +31,10 @@ export default class JsonRpcBase extends EventEmitter { this._middlewareList = Promise.resolve([]); } + get ready () { + return this._middlewareList.then(() => true); + } + encode (method, params) { const json = JSON.stringify({ jsonrpc: '2.0', diff --git a/js/src/api/transport/middleware.js b/js/src/api/transport/middleware.js index ef029b1cb..ccdf732a0 100644 --- a/js/src/api/transport/middleware.js +++ b/js/src/api/transport/middleware.js @@ -17,7 +17,20 @@ export default class Middleware { constructor (transport) { this._transport = transport; + this._subscribe = transport.subscribe; + + transport.subscribe = this.handleSubscribe.bind(this); + this._handlers = {}; + this._subHandlers = {}; + } + + registerSubscribe (method, handler) { + if (method in this._subHandlers) { + throw new Error(`${method} is already defined in the middleware!`); + } + + this._subHandlers[method] = handler; } register (method, handler) { @@ -28,10 +41,24 @@ export default class Middleware { this._handlers[method] = handler; } + handleSubscribe (api, callback, event) { + // Don't ask + const method = api.subscribe ? api.subscribe : event[0]; + const params = event.length === 2 ? event[1] : event; + + const handler = this._subHandlers[method]; + + if (handler) { + return handler(params, callback); + } + + this._subscribe.call(this._transport, api, callback, event); + } + handle (method, params) { const handler = this._handlers[method]; - if (handler != null) { + if (handler) { return handler(params); }