diff --git a/app/scripts/background.js b/app/scripts/background.js index da022c490641..d9a2b0a6e2b6 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -4,6 +4,7 @@ const pump = require('pump') const log = require('loglevel') const extension = require('extensionizer') const LocalStorageStore = require('obs-store/lib/localStorage') +const ExtensionStore = require('./lib/extension-store') const storeTransform = require('obs-store/lib/transform') const asStream = require('obs-store/lib/asStream') const ExtensionPlatform = require('./platforms/extension') @@ -28,6 +29,7 @@ let popupIsOpen = false // state persistence const diskStore = new LocalStorageStore({ storageKey: STORAGE_KEY }) +const extensionStore = new ExtensionStore() // initialization flow initialize().catch(log.error) @@ -47,6 +49,13 @@ async function loadStateFromPersistence () { const migrator = new Migrator({ migrations }) // read from disk let versionedData = diskStore.getState() || migrator.generateInitialState(firstTimeState) + // fetch from extension store and merge in data + + if (extensionStore.isSupported && extensionStore.isEnabled) { + const extensionData = await extensionStore.fetch() // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) + versionedData = { ...versionedData, ...extensionData } + } + // migrate data versionedData = await migrator.migrateData(versionedData) // write to disk @@ -76,6 +85,7 @@ function setupController (initState) { pump( asStream(controller.store), storeTransform(versionifyData), + storeTransform(syncDataWithExtension), asStream(diskStore) ) @@ -85,6 +95,13 @@ function setupController (initState) { return versionedData } + function syncDataWithExtension(state) { + if (extensionStore.isSupported && extensionStore.isEnabled) { + extensionStore.sync(state) // TODO: handle possible exceptions (https://developer.chrome.com/apps/runtime#property-lastError) + } + return state + } + // // connect to other contexts // diff --git a/app/scripts/lib/extension-store.js b/app/scripts/lib/extension-store.js new file mode 100644 index 000000000000..67ee71f16bae --- /dev/null +++ b/app/scripts/lib/extension-store.js @@ -0,0 +1,39 @@ +const extension = require('extensionizer') + +const KEYS_TO_SYNC = ['KeyringController', 'PreferencesController'] +const FIREFOX_SYNC_DISABLED_MESSAGE = 'Please set webextensions.storage.sync.enabled to true in about:config' + +const handleDisabledSyncAndResolve = (resolve, toResolve) => { + // Firefox 52 has sync available on extension.storage, but it is disabled by default + const lastError = extension.runtime.lastError + if (lastError && lastError.message.includes(FIREFOX_SYNC_DISABLED_MESSAGE)) { + resolve({}) + } else { + resolve(toResolve) + } +} + +module.exports = class ExtensionStore { + constructor() { + this.isSupported = !!(extension.storage.sync) + this.isEnabled = true // TODO: get value from user settings + } + async fetch() { + return new Promise((resolve) => { + extension.storage.sync.get(KEYS_TO_SYNC, (data) => { + handleDisabledSyncAndResolve(resolve, data) + }) + }) + } + async sync(state) { + const dataToSync = KEYS_TO_SYNC.reduce((result, key) => { + result[key] = state.data[key] + return result + }, {}) + return new Promise((resolve) => { + extension.storage.sync.set(dataToSync, () => { + handleDisabledSyncAndResolve(resolve) + }) + }) + } +} diff --git a/test/unit/extension-store-test.js b/test/unit/extension-store-test.js new file mode 100644 index 000000000000..e3b5713fbd16 --- /dev/null +++ b/test/unit/extension-store-test.js @@ -0,0 +1,29 @@ +const assert = require('assert') + +const ExtensionStore = require('../../app/scripts/lib/extension-store') + +describe('Extension Store', function () { + let extensionStore + + beforeEach(function () { + extensionStore = new ExtensionStore() + }) + + describe('#fetch', function () { + it('should return a promise', function () { + + }) + it('after promise resolution, should have loaded the proper data from the extension', function () { + + }) + }) + + describe('#sync', function () { + it('should return a promise', function () { + + }) + it('after promise resolution, should have synced the proper data from the extension', function () { + + }) + }) +})