diff options
Diffstat (limited to 'js/firefox/extension-storage.jsm')
-rw-r--r-- | js/firefox/extension-storage.jsm | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/js/firefox/extension-storage.jsm b/js/firefox/extension-storage.jsm new file mode 100644 index 0000000..02c59a3 --- /dev/null +++ b/js/firefox/extension-storage.jsm @@ -0,0 +1,152 @@ +//Copied from resource://gre/modules/ExtensionStorage.jsm in Nightly. +//Will be removed when this addon moves to the WebExtensions API. + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +this.EXPORTED_SYMBOLS = ["ExtensionStorage"]; + +const Ci = Components.interfaces; +const Cc = Components.classes; +const Cu = Components.utils; +const Cr = Components.results; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/osfile.jsm") +Cu.import("resource://gre/modules/AsyncShutdown.jsm"); + +let Path = OS.Path; +let profileDir = OS.Constants.Path.profileDir; + +this.ExtensionStorage = { + cache: new Map(), + listeners: new Map(), + + extensionDir: Path.join(profileDir, "browser-extension-data"), + + getExtensionDir(extensionId) { + return Path.join(this.extensionDir, extensionId); + }, + + getStorageFile(extensionId) { + return Path.join(this.extensionDir, extensionId, "storage.js"); + }, + + read(extensionId) { + if (this.cache.has(extensionId)) { + return this.cache.get(extensionId); + } + + let path = this.getStorageFile(extensionId); + let decoder = new TextDecoder(); + let promise = OS.File.read(path); + promise = promise.then(array => { + return JSON.parse(decoder.decode(array)); + }).catch(() => { + Cu.reportError("Unable to parse JSON data for extension storage."); + return {}; + }); + this.cache.set(extensionId, promise); + return promise; + }, + + write(extensionId) { + let promise = this.read(extensionId).then(extData => { + let encoder = new TextEncoder(); + let array = encoder.encode(JSON.stringify(extData)); + let path = this.getStorageFile(extensionId); + OS.File.makeDir(this.getExtensionDir(extensionId), {ignoreExisting: true, from: profileDir}); + let promise = OS.File.writeAtomic(path, array); + return promise; + }).catch(() => { + // Make sure this promise is never rejected. + Cu.reportError("Unable to write JSON data for extension storage."); + }); + + AsyncShutdown.profileBeforeChange.addBlocker( + "ExtensionStorage: Finish writing extension data", + promise); + + return promise.then(() => { + AsyncShutdown.profileBeforeChange.removeBlocker(promise); + }); + }, + + set(extensionId, items) { + return this.read(extensionId).then(extData => { + let changes = {}; + for (let prop in items) { + changes[prop] = {oldValue: extData[prop], newValue: items[prop]}; + extData[prop] = items[prop]; + } + + let listeners = this.listeners.get(extensionId); + if (listeners) { + for (let listener of listeners) { + listener(changes); + } + } + + return this.write(extensionId); + }); + }, + + remove(extensionId, items) { + return this.read(extensionId).then(extData => { + let changes = {}; + for (let prop in items) { + changes[prop] = {oldValue: extData[prop]}; + delete extData[prop]; + } + + let listeners = this.listeners.get(extensionId); + if (listeners) { + for (let listener of listeners) { + listener(changes); + } + } + + return this.write(extensionId); + }); + }, + + get(extensionId, keys) { + return this.read(extensionId).then(extData => { + let result = {}; + if (keys === null) { + Object.assign(result, extData); + } else if (typeof(keys) == "object") { + for (let prop in keys) { + if (prop in extData) { + result[prop] = extData[prop]; + } else { + result[prop] = keys[prop]; + } + } + } else if (typeof(keys) == "string") { + result[prop] = extData[prop] || undefined; + } else { + for (let prop of keys) { + result[prop] = extData[prop] || undefined; + } + } + + return result; + }); + }, + + addOnChangedListener(extensionId, listener) { + let listeners = this.listeners.get(extensionId) || new Set(); + listeners.add(listener); + this.listeners.set(extensionId, listeners); + }, + + removeOnChangedListener(extensionId, listener) { + let listeners = this.listeners.get(extensionId); + listeners.delete(listener); + }, +}; |