aboutsummaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorkumavis <aaron@kumavis.me>2017-01-12 14:47:56 +0800
committerkumavis <aaron@kumavis.me>2017-01-12 14:47:56 +0800
commit3bc996878b467e1fa5fd63656bd465377daa137d (patch)
tree9c1661af778b58cd6d83c7d5fb5727f7a61b6dd9 /app
parent2019c02fc0fc33d4bd98416654370250d7aa0ca6 (diff)
downloadtangerine-wallet-browser-3bc996878b467e1fa5fd63656bd465377daa137d.tar
tangerine-wallet-browser-3bc996878b467e1fa5fd63656bd465377daa137d.tar.gz
tangerine-wallet-browser-3bc996878b467e1fa5fd63656bd465377daa137d.tar.bz2
tangerine-wallet-browser-3bc996878b467e1fa5fd63656bd465377daa137d.tar.lz
tangerine-wallet-browser-3bc996878b467e1fa5fd63656bd465377daa137d.tar.xz
tangerine-wallet-browser-3bc996878b467e1fa5fd63656bd465377daa137d.tar.zst
tangerine-wallet-browser-3bc996878b467e1fa5fd63656bd465377daa137d.zip
background - move pojo migrator to outside of metamask controller
Diffstat (limited to 'app')
-rw-r--r--app/scripts/background.js94
-rw-r--r--app/scripts/first-time-state.js11
-rw-r--r--app/scripts/lib/config-manager.js49
-rw-r--r--app/scripts/lib/migrations.js13
-rw-r--r--app/scripts/lib/observable/host.js4
-rw-r--r--app/scripts/lib/observable/index.js10
-rw-r--r--app/scripts/lib/observable/local-storage.js37
-rw-r--r--app/scripts/lib/observable/remote.js2
-rw-r--r--app/scripts/lib/observable/util/sync.js24
-rw-r--r--app/scripts/lib/observable/util/transform.js13
-rw-r--r--app/scripts/metamask-controller.js6
11 files changed, 159 insertions, 104 deletions
diff --git a/app/scripts/background.js b/app/scripts/background.js
index f3c0b52b3..8aa886594 100644
--- a/app/scripts/background.js
+++ b/app/scripts/background.js
@@ -1,41 +1,57 @@
const urlUtil = require('url')
-const extend = require('xtend')
const Dnode = require('dnode')
const eos = require('end-of-stream')
+const Migrator = require('pojo-migrator')
+const migrations = require('./lib/migrations')
+const LocalStorageStore = require('./lib/observable/local-storage')
const PortStream = require('./lib/port-stream.js')
const notification = require('./lib/notifications.js')
const messageManager = require('./lib/message-manager')
const setupMultiplex = require('./lib/stream-utils.js').setupMultiplex
const MetamaskController = require('./metamask-controller')
const extension = require('./lib/extension')
+const firstTimeState = require('./first-time-state')
const STORAGE_KEY = 'metamask-config'
const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG'
-var popupIsOpen = false
+let popupIsOpen = false
+//
+// State and Persistence
+//
+
+// state persistence
+
+let dataStore = new LocalStorageStore({ storageKey: STORAGE_KEY })
+// initial state for first time users
+if (!dataStore.get()) {
+ dataStore.put({ meta: { version: 0 }, data: firstTimeState })
+}
+
+// migrations
+
+let migrator = new Migrator({
+ migrations,
+ // Data persistence methods
+ loadData: () => dataStore.get(),
+ setData: (newState) => dataStore.put(newState),
+})
+
+//
+// MetaMask Controller
+//
+
const controller = new MetamaskController({
// User confirmation callbacks:
showUnconfirmedMessage: triggerUi,
unlockAccountMessage: triggerUi,
showUnapprovedTx: triggerUi,
// initial state
- initState: loadData(),
+ initState: migrator.getData(),
})
// setup state persistence
-controller.store.subscribe(setData)
-
-const txManager = controller.txManager
-function triggerUi () {
- if (!popupIsOpen) notification.show()
-}
-// On first install, open a window to MetaMask website to how-it-works.
-
-extension.runtime.onInstalled.addListener(function (details) {
- if ((details.reason === 'install') && (!METAMASK_DEBUG)) {
- extension.tabs.create({url: 'https://metamask.io/#how-it-works'})
- }
-})
+controller.store.subscribe((newState) => migrator.saveData(newState))
//
// connect to other contexts
@@ -94,11 +110,23 @@ function setupControllerConnection (stream) {
}
//
-// plugin badge text
+// User Interface setup
//
-txManager.on('updateBadge', updateBadge)
+// popup trigger
+function triggerUi () {
+ if (!popupIsOpen) notification.show()
+}
+// On first install, open a window to MetaMask website to how-it-works.
+extension.runtime.onInstalled.addListener(function (details) {
+ if ((details.reason === 'install') && (!METAMASK_DEBUG)) {
+ extension.tabs.create({url: 'https://metamask.io/#how-it-works'})
+ }
+})
+
+// plugin badge text
+controller.txManager.on('updateBadge', updateBadge)
function updateBadge () {
var label = ''
var unapprovedTxCount = controller.txManager.unapprovedTxCount
@@ -111,33 +139,3 @@ function updateBadge () {
extension.browserAction.setBadgeText({ text: label })
extension.browserAction.setBadgeBackgroundColor({ color: '#506F8B' })
}
-
-// data :: setters/getters
-
-function loadData () {
- let defaultData = {
- meta: {
- version: 0,
- },
- data: {
- config: {
- provider: {
- type: 'testnet',
- },
- },
- },
- }
-
- var persisted
- try {
- persisted = JSON.parse(window.localStorage[STORAGE_KEY])
- } catch (err) {
- persisted = null
- }
-
- return extend(defaultData, persisted)
-}
-
-function setData (data) {
- window.localStorage[STORAGE_KEY] = JSON.stringify(data)
-}
diff --git a/app/scripts/first-time-state.js b/app/scripts/first-time-state.js
new file mode 100644
index 000000000..3196981ba
--- /dev/null
+++ b/app/scripts/first-time-state.js
@@ -0,0 +1,11 @@
+//
+// The default state of MetaMask
+//
+
+module.exports = {
+ config: {
+ provider: {
+ type: 'testnet',
+ },
+ },
+} \ No newline at end of file
diff --git a/app/scripts/lib/config-manager.js b/app/scripts/lib/config-manager.js
index 01e6ccc3c..6d7305377 100644
--- a/app/scripts/lib/config-manager.js
+++ b/app/scripts/lib/config-manager.js
@@ -1,6 +1,4 @@
-const Migrator = require('pojo-migrator')
const MetamaskConfig = require('../config.js')
-const migrations = require('./migrations')
const ethUtil = require('ethereumjs-util')
const normalize = require('./sig-util').normalize
@@ -20,38 +18,17 @@ function ConfigManager (opts) {
// ConfigManager is observable and will emit updates
this._subs = []
this.store = opts.store
-
- /* The migrator exported on the config-manager
- * has two methods the user should be concerned with:
- *
- * getData(), which returns the app-consumable data object
- * saveData(), which persists the app-consumable data object.
- */
- this.migrator = new Migrator({
-
- // Migrations must start at version 1 or later.
- // They are objects with a `version` number
- // and a `migrate` function.
- //
- // The `migrate` function receives the previous
- // config data format, and returns the new one.
- migrations: migrations,
-
- // Data persistence methods
- loadData: () => this.store.get(),
- setData: (value) => this.store.put(value),
- })
}
ConfigManager.prototype.setConfig = function (config) {
- var data = this.migrator.getData()
+ var data = this.store.get()
data.config = config
this.setData(data)
this._emitUpdates(config)
}
ConfigManager.prototype.getConfig = function () {
- var data = this.migrator.getData()
+ var data = this.store.get()
if ('config' in data) {
return data.config
} else {
@@ -94,15 +71,15 @@ ConfigManager.prototype.getProvider = function () {
}
ConfigManager.prototype.setData = function (data) {
- this.migrator.saveData(data)
+ this.store.put(data)
}
ConfigManager.prototype.getData = function () {
- return this.migrator.getData()
+ return this.store.get()
}
ConfigManager.prototype.setWallet = function (wallet) {
- var data = this.migrator.getData()
+ var data = this.store.get()
data.wallet = wallet
this.setData(data)
}
@@ -119,11 +96,11 @@ ConfigManager.prototype.getVault = function () {
}
ConfigManager.prototype.getKeychains = function () {
- return this.migrator.getData().keychains || []
+ return this.store.get().keychains || []
}
ConfigManager.prototype.setKeychains = function (keychains) {
- var data = this.migrator.getData()
+ var data = this.store.get()
data.keychains = keychains
this.setData(data)
}
@@ -140,19 +117,19 @@ ConfigManager.prototype.setSelectedAccount = function (address) {
}
ConfigManager.prototype.getWallet = function () {
- return this.migrator.getData().wallet
+ return this.store.get().wallet
}
// Takes a boolean
ConfigManager.prototype.setShowSeedWords = function (should) {
- var data = this.migrator.getData()
+ var data = this.store.get()
data.showSeedWords = should
this.setData(data)
}
ConfigManager.prototype.getShouldShowSeedWords = function () {
- var data = this.migrator.getData()
+ var data = this.store.get()
return data.showSeedWords
}
@@ -187,7 +164,7 @@ ConfigManager.prototype.getCurrentRpcAddress = function () {
}
ConfigManager.prototype.setData = function (data) {
- this.migrator.saveData(data)
+ this.store.put(data)
}
//
@@ -195,7 +172,7 @@ ConfigManager.prototype.setData = function (data) {
//
ConfigManager.prototype.getTxList = function () {
- var data = this.migrator.getData()
+ var data = this.store.get()
if (data.transactions !== undefined) {
return data.transactions
} else {
@@ -204,7 +181,7 @@ ConfigManager.prototype.getTxList = function () {
}
ConfigManager.prototype.setTxList = function (txList) {
- var data = this.migrator.getData()
+ var data = this.store.get()
data.transactions = txList
this.setData(data)
}
diff --git a/app/scripts/lib/migrations.js b/app/scripts/lib/migrations.js
index f026cbe53..12f60def1 100644
--- a/app/scripts/lib/migrations.js
+++ b/app/scripts/lib/migrations.js
@@ -1,3 +1,16 @@
+/* The migrator has two methods the user should be concerned with:
+ *
+ * getData(), which returns the app-consumable data object
+ * saveData(), which persists the app-consumable data object.
+ */
+
+// Migrations must start at version 1 or later.
+// They are objects with a `version` number
+// and a `migrate` function.
+//
+// The `migrate` function receives the previous
+// config data format, and returns the new one.
+
module.exports = [
require('../migrations/002'),
require('../migrations/003'),
diff --git a/app/scripts/lib/observable/host.js b/app/scripts/lib/observable/host.js
index 69f674be8..d1b110503 100644
--- a/app/scripts/lib/observable/host.js
+++ b/app/scripts/lib/observable/host.js
@@ -12,14 +12,14 @@ class HostStore extends ObservableStore {
constructor (initState, opts) {
super(initState)
- this.opts = opts || {}
+ this._opts = opts || {}
}
createStream () {
const self = this
// setup remotely exposed api
let remoteApi = {}
- if (!self.opts.readOnly) {
+ if (!self._opts.readOnly) {
remoteApi.put = (newState) => self.put(newState)
}
// listen for connection to remote
diff --git a/app/scripts/lib/observable/index.js b/app/scripts/lib/observable/index.js
index d193e5554..1ff112e95 100644
--- a/app/scripts/lib/observable/index.js
+++ b/app/scripts/lib/observable/index.js
@@ -7,22 +7,30 @@ class ObservableStore extends EventEmitter {
this._state = initialState
}
+ // wrapper around internal get
get () {
return this._state
}
-
+
+ // wrapper around internal put
put (newState) {
this._put(newState)
}
+ // subscribe to changes
subscribe (handler) {
this.on('update', handler)
}
+ // unsubscribe to changes
unsubscribe (handler) {
this.removeListener('update', handler)
}
+ //
+ // private
+ //
+
_put (newState) {
this._state = newState
this.emit('update', newState)
diff --git a/app/scripts/lib/observable/local-storage.js b/app/scripts/lib/observable/local-storage.js
new file mode 100644
index 000000000..6ed3860f6
--- /dev/null
+++ b/app/scripts/lib/observable/local-storage.js
@@ -0,0 +1,37 @@
+const ObservableStore = require('./index')
+
+//
+// LocalStorageStore
+//
+// uses localStorage instead of a cache
+//
+
+class LocalStorageStore extends ObservableStore {
+
+ constructor (opts) {
+ super()
+ delete this._state
+
+ this._opts = opts || {}
+ if (!this._opts.storageKey) {
+ throw new Error('LocalStorageStore - no "storageKey" specified')
+ }
+ this._storageKey = this._opts.storageKey
+ }
+
+ get() {
+ try {
+ return JSON.parse(global.localStorage[this._storageKey])
+ } catch (err) {
+ return undefined
+ }
+ }
+
+ _put(newState) {
+ global.localStorage[this._storageKey] = JSON.stringify(newState)
+ this.emit('update', newState)
+ }
+
+}
+
+module.exports = LocalStorageStore
diff --git a/app/scripts/lib/observable/remote.js b/app/scripts/lib/observable/remote.js
index b5a3254a2..603f6f0b8 100644
--- a/app/scripts/lib/observable/remote.js
+++ b/app/scripts/lib/observable/remote.js
@@ -12,7 +12,7 @@ class RemoteStore extends ObservableStore {
constructor (initState, opts) {
super(initState)
- this.opts = opts || {}
+ this._opts = opts || {}
this._remote = null
}
diff --git a/app/scripts/lib/observable/util/sync.js b/app/scripts/lib/observable/util/sync.js
new file mode 100644
index 000000000..c61feb02e
--- /dev/null
+++ b/app/scripts/lib/observable/util/sync.js
@@ -0,0 +1,24 @@
+
+//
+// synchronizeStore(inStore, outStore, stateTransform)
+//
+// keeps outStore synchronized with inStore, via an optional stateTransform
+//
+
+module.exports = synchronizeStore
+
+
+function synchronizeStore(inStore, outStore, stateTransform) {
+ stateTransform = stateTransform || transformNoop
+ const initState = stateTransform(inStore.get())
+ outStore.put(initState)
+ inStore.subscribe((inState) => {
+ const outState = stateTransform(inState)
+ outStore.put(outState)
+ })
+ return outStore
+}
+
+function transformNoop(state) {
+ return state
+} \ No newline at end of file
diff --git a/app/scripts/lib/observable/util/transform.js b/app/scripts/lib/observable/util/transform.js
deleted file mode 100644
index 87946f402..000000000
--- a/app/scripts/lib/observable/util/transform.js
+++ /dev/null
@@ -1,13 +0,0 @@
-
-module.exports = transformStore
-
-
-function transformStore(inStore, outStore, stateTransform) {
- const initState = stateTransform(inStore.get())
- outStore.put(initState)
- inStore.subscribe((inState) => {
- const outState = stateTransform(inState)
- outStore.put(outState)
- })
- return outStore
-} \ No newline at end of file
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index 8e0eaf54c..e15844a56 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -14,7 +14,7 @@ const nodeify = require('./lib/nodeify')
const IdStoreMigrator = require('./lib/idStore-migrator')
const ObservableStore = require('./lib/observable/')
const HostStore = require('./lib/observable/host')
-const transformStore = require('./lib/observable/util/transform')
+const synchronizeStore = require('./lib/observable/util/sync')
const version = require('../manifest.json').version
module.exports = class MetamaskController extends EventEmitter {
@@ -244,12 +244,12 @@ module.exports = class MetamaskController extends EventEmitter {
var publicConfigStore = new HostStore(initPublicState, { readOnly: true })
// sync publicConfigStore with transform
- transformStore(this.store, publicConfigStore, selectPublicState)
+ synchronizeStore(this.store, publicConfigStore, selectPublicState)
function selectPublicState(state) {
let result = { selectedAccount: undefined }
try {
- result.selectedAccount = state.data.config.selectedAccount
+ result.selectedAccount = state.config.selectedAccount
} catch (err) {
console.warn('Error in "selectPublicState": ' + err.message)
}