mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-22 17:33:23 +01:00
Merge pull request #3975 from MetaMask/i3947-composableStore
Add ComposableObservableStore for subscription management
This commit is contained in:
commit
3afe76bcba
49
app/scripts/lib/ComposableObservableStore.js
Normal file
49
app/scripts/lib/ComposableObservableStore.js
Normal file
@ -0,0 +1,49 @@
|
||||
const ObservableStore = require('obs-store')
|
||||
|
||||
/**
|
||||
* An ObservableStore that can composes a flat
|
||||
* structure of child stores based on configuration
|
||||
*/
|
||||
class ComposableObservableStore extends ObservableStore {
|
||||
/**
|
||||
* Create a new store
|
||||
*
|
||||
* @param {Object} [initState] - The initial store state
|
||||
* @param {Object} [config] - Map of internal state keys to child stores
|
||||
*/
|
||||
constructor (initState, config) {
|
||||
super(initState)
|
||||
this.updateStructure(config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Composes a new internal store subscription structure
|
||||
*
|
||||
* @param {Object} [config] - Map of internal state keys to child stores
|
||||
*/
|
||||
updateStructure (config) {
|
||||
this.config = config
|
||||
this.removeAllListeners()
|
||||
for (const key in config) {
|
||||
config[key].subscribe((state) => {
|
||||
this.updateState({ [key]: state })
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges all child store state into a single object rather than
|
||||
* returning an object keyed by child store class name
|
||||
*
|
||||
* @returns {Object} - Object containing merged child store state
|
||||
*/
|
||||
getFlatState () {
|
||||
let flatState = {}
|
||||
for (const key in this.config) {
|
||||
flatState = { ...flatState, ...this.config[key].getState() }
|
||||
}
|
||||
return flatState
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ComposableObservableStore
|
@ -5,10 +5,10 @@
|
||||
*/
|
||||
|
||||
const EventEmitter = require('events')
|
||||
const extend = require('xtend')
|
||||
const pump = require('pump')
|
||||
const Dnode = require('dnode')
|
||||
const ObservableStore = require('obs-store')
|
||||
const ComposableObservableStore = require('./lib/ComposableObservableStore')
|
||||
const asStream = require('obs-store/lib/asStream')
|
||||
const AccountTracker = require('./lib/account-tracker')
|
||||
const RpcEngine = require('json-rpc-engine')
|
||||
@ -65,7 +65,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
this.platform = opts.platform
|
||||
|
||||
// observable state store
|
||||
this.store = new ObservableStore(initState)
|
||||
this.store = new ComposableObservableStore(initState)
|
||||
|
||||
// lock to ensure only one vault created at once
|
||||
this.createVaultMutex = new Mutex()
|
||||
@ -184,53 +184,36 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
this.typedMessageManager = new TypedMessageManager()
|
||||
this.publicConfigStore = this.initPublicConfigStore()
|
||||
|
||||
// manual disk state subscriptions
|
||||
this.txController.store.subscribe((state) => {
|
||||
this.store.updateState({ TransactionController: state })
|
||||
})
|
||||
this.keyringController.store.subscribe((state) => {
|
||||
this.store.updateState({ KeyringController: state })
|
||||
})
|
||||
this.preferencesController.store.subscribe((state) => {
|
||||
this.store.updateState({ PreferencesController: state })
|
||||
})
|
||||
this.addressBookController.store.subscribe((state) => {
|
||||
this.store.updateState({ AddressBookController: state })
|
||||
})
|
||||
this.currencyController.store.subscribe((state) => {
|
||||
this.store.updateState({ CurrencyController: state })
|
||||
})
|
||||
this.noticeController.store.subscribe((state) => {
|
||||
this.store.updateState({ NoticeController: state })
|
||||
})
|
||||
this.shapeshiftController.store.subscribe((state) => {
|
||||
this.store.updateState({ ShapeShiftController: state })
|
||||
})
|
||||
this.networkController.store.subscribe((state) => {
|
||||
this.store.updateState({ NetworkController: state })
|
||||
this.store.updateStructure({
|
||||
TransactionController: this.txController.store,
|
||||
KeyringController: this.keyringController.store,
|
||||
PreferencesController: this.preferencesController.store,
|
||||
AddressBookController: this.addressBookController.store,
|
||||
CurrencyController: this.currencyController.store,
|
||||
NoticeController: this.noticeController.store,
|
||||
ShapeShiftController: this.shapeshiftController.store,
|
||||
NetworkController: this.networkController.store,
|
||||
InfuraController: this.infuraController.store,
|
||||
})
|
||||
|
||||
this.infuraController.store.subscribe((state) => {
|
||||
this.store.updateState({ InfuraController: state })
|
||||
this.memStore = new ComposableObservableStore(null, {
|
||||
NetworkController: this.networkController.store,
|
||||
AccountTracker: this.accountTracker.store,
|
||||
TxController: this.txController.memStore,
|
||||
BalancesController: this.balancesController.store,
|
||||
MessageManager: this.messageManager.memStore,
|
||||
PersonalMessageManager: this.personalMessageManager.memStore,
|
||||
TypesMessageManager: this.typedMessageManager.memStore,
|
||||
KeyringController: this.keyringController.memStore,
|
||||
PreferencesController: this.preferencesController.store,
|
||||
RecentBlocksController: this.recentBlocksController.store,
|
||||
AddressBookController: this.addressBookController.store,
|
||||
CurrencyController: this.currencyController.store,
|
||||
NoticeController: this.noticeController.memStore,
|
||||
ShapeshiftController: this.shapeshiftController.store,
|
||||
InfuraController: this.infuraController.store,
|
||||
})
|
||||
|
||||
// manual mem state subscriptions
|
||||
const sendUpdate = this.sendUpdate.bind(this)
|
||||
this.networkController.store.subscribe(sendUpdate)
|
||||
this.accountTracker.store.subscribe(sendUpdate)
|
||||
this.txController.memStore.subscribe(sendUpdate)
|
||||
this.balancesController.store.subscribe(sendUpdate)
|
||||
this.messageManager.memStore.subscribe(sendUpdate)
|
||||
this.personalMessageManager.memStore.subscribe(sendUpdate)
|
||||
this.typedMessageManager.memStore.subscribe(sendUpdate)
|
||||
this.keyringController.memStore.subscribe(sendUpdate)
|
||||
this.preferencesController.store.subscribe(sendUpdate)
|
||||
this.recentBlocksController.store.subscribe(sendUpdate)
|
||||
this.addressBookController.store.subscribe(sendUpdate)
|
||||
this.currencyController.store.subscribe(sendUpdate)
|
||||
this.noticeController.memStore.subscribe(sendUpdate)
|
||||
this.shapeshiftController.store.subscribe(sendUpdate)
|
||||
this.infuraController.store.subscribe(sendUpdate)
|
||||
this.memStore.subscribe(this.sendUpdate.bind(this))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -308,33 +291,16 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
const vault = this.keyringController.store.getState().vault
|
||||
const isInitialized = (!!wallet || !!vault)
|
||||
|
||||
return extend(
|
||||
{
|
||||
isInitialized,
|
||||
},
|
||||
this.networkController.store.getState(),
|
||||
this.accountTracker.store.getState(),
|
||||
this.txController.memStore.getState(),
|
||||
this.messageManager.memStore.getState(),
|
||||
this.personalMessageManager.memStore.getState(),
|
||||
this.typedMessageManager.memStore.getState(),
|
||||
this.keyringController.memStore.getState(),
|
||||
this.balancesController.store.getState(),
|
||||
this.preferencesController.store.getState(),
|
||||
this.addressBookController.store.getState(),
|
||||
this.currencyController.store.getState(),
|
||||
this.noticeController.memStore.getState(),
|
||||
this.infuraController.store.getState(),
|
||||
this.recentBlocksController.store.getState(),
|
||||
// config manager
|
||||
this.configManager.getConfig(),
|
||||
this.shapeshiftController.store.getState(),
|
||||
{
|
||||
return {
|
||||
...{ isInitialized },
|
||||
...this.memStore.getFlatState(),
|
||||
...this.configManager.getConfig(),
|
||||
...{
|
||||
lostAccounts: this.configManager.getLostAccounts(),
|
||||
seedWords: this.configManager.getSeedWords(),
|
||||
forgottenPassword: this.configManager.getPasswordForgotten(),
|
||||
}
|
||||
)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
705
package-lock.json
generated
705
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -8,7 +8,7 @@
|
||||
"mascara": "gulp dev:mascara & node ./mascara/example/server",
|
||||
"dist": "gulp dist",
|
||||
"test": "npm run test:unit && npm run test:integration && npm run lint",
|
||||
"test:unit": "cross-env METAMASK_ENV=test mocha --exit --require babel-core/register --require test/helper.js --recursive \"test/unit/**/*.js\"",
|
||||
"test:unit": "cross-env METAMASK_ENV=test mocha --exit --require test/setup.js --recursive \"test/unit/**/*.js\"",
|
||||
"test:single": "cross-env METAMASK_ENV=test mocha --require test/helper.js",
|
||||
"test:integration": "npm run test:integration:build && npm run test:flat && npm run test:mascara",
|
||||
"test:integration:build": "gulp build:scss",
|
||||
|
5
test/setup.js
Normal file
5
test/setup.js
Normal file
@ -0,0 +1,5 @@
|
||||
require('babel-register')({
|
||||
ignore: name => name.includes('node_modules') && !name.includes('obs-store'),
|
||||
})
|
||||
|
||||
require('./helper')
|
35
test/unit/ComposableObservableStore.js
Normal file
35
test/unit/ComposableObservableStore.js
Normal file
@ -0,0 +1,35 @@
|
||||
const assert = require('assert')
|
||||
const ComposableObservableStore = require('../../app/scripts/lib/ComposableObservableStore')
|
||||
const ObservableStore = require('obs-store')
|
||||
|
||||
describe('ComposableObservableStore', () => {
|
||||
it('should register initial state', () => {
|
||||
const store = new ComposableObservableStore('state')
|
||||
assert.strictEqual(store.getState(), 'state')
|
||||
})
|
||||
|
||||
it('should register initial structure', () => {
|
||||
const testStore = new ObservableStore()
|
||||
const store = new ComposableObservableStore(null, { TestStore: testStore })
|
||||
testStore.putState('state')
|
||||
assert.deepEqual(store.getState(), { TestStore: 'state' })
|
||||
})
|
||||
|
||||
it('should update structure', () => {
|
||||
const testStore = new ObservableStore()
|
||||
const store = new ComposableObservableStore()
|
||||
store.updateStructure({ TestStore: testStore })
|
||||
testStore.putState('state')
|
||||
assert.deepEqual(store.getState(), { TestStore: 'state' })
|
||||
})
|
||||
|
||||
it('should return flattened state', () => {
|
||||
const fooStore = new ObservableStore({ foo: 'foo' })
|
||||
const barStore = new ObservableStore({ bar: 'bar' })
|
||||
const store = new ComposableObservableStore(null, {
|
||||
FooStore: fooStore,
|
||||
BarStore: barStore,
|
||||
})
|
||||
assert.deepEqual(store.getFlatState(), { foo: 'foo', bar: 'bar' })
|
||||
})
|
||||
})
|
Loading…
Reference in New Issue
Block a user