aboutsummaryrefslogtreecommitdiff
path: root/background/storage.js
diff options
context:
space:
mode:
authorWojtek Kosior <koszko@koszko.org>2021-06-30 12:28:05 +0200
committerWojtek Kosior <koszko@koszko.org>2021-06-30 12:28:05 +0200
commit261548ff184926567a623e90df7954aeef842d59 (patch)
tree9b5697a77c758eaae969a8fba8b4edea5ecf59d4 /background/storage.js
parent83a8d263f6efddf4f742bf7a687d10bfd1907ef8 (diff)
downloadbrowser-extension-261548ff184926567a623e90df7954aeef842d59.tar.gz
browser-extension-261548ff184926567a623e90df7954aeef842d59.zip
emply an sh-based build system; make some changes to blocking
Diffstat (limited to 'background/storage.js')
-rw-r--r--background/storage.js654
1 files changed, 330 insertions, 324 deletions
diff --git a/background/storage.js b/background/storage.js
index f3f08c9..48e4e52 100644
--- a/background/storage.js
+++ b/background/storage.js
@@ -5,390 +5,396 @@
* Redistribution terms are gathered in the `copyright' file.
*/
-"use strict";
-
-(() => {
- const TYPE_PREFIX = window.TYPE_PREFIX;
- const TYPE_NAME = window.TYPE_NAME;
- const list_prefixes = window.list_prefixes;
- const make_lock = window.make_lock;
- const lock = window.lock;
- const unlock = window.unlock;
- const make_once = window.make_once;
- const browser = window.browser;
- const is_chrome = window.is_chrome;
-
- var exports = {};
-
- /* We're yet to decide how to handle errors... */
-
- /* Here are some basic wrappers for storage API functions */
-
- async function get(key)
- {
- try {
- /* Fix for fact that Chrome does not use promises here */
- let promise = is_chrome ?
- new Promise((resolve, reject) =>
- chrome.storage.local.get(key,
- val => resolve(val))) :
- browser.storage.local.get(key);
-
- return (await promise)[key];
- } catch (e) {
- console.log(e);
- }
- }
+/*
+ * IMPORTS_START
+ * IMPORT TYPE_PREFIX
+ * IMPORT TYPE_NAME
+ * IMPORT list_prefixes
+ * IMPORT make_lock
+ * IMPORT lock
+ * IMPORT unlock
+ * IMPORT make_once
+ * IMPORT browser
+ * IMPORT is_chrome
+ * IMPORTS_END
+ */
- async function set(key, value)
- {
- try {
- return browser.storage.local.set({[key]: value});
- } catch (e) {
- console.log(e);
- }
- }
+var exports = {};
- async function setn(keys_and_values)
- {
- let obj = Object();
- while (keys_and_values.length > 1) {
- let value = keys_and_values.pop();
- let key = keys_and_values.pop();
- obj[key] = value;
- }
+/* We're yet to decide how to handle errors... */
- try {
- return browser.storage.local.set(obj);
- } catch (e) {
- console.log(e);
- }
- }
+/* Here are some basic wrappers for storage API functions */
- async function set_var(name, value)
- {
- return set(TYPE_PREFIX.VAR + name, value);
- }
+async function get(key)
+{
+ try {
+ /* Fix for fact that Chrome does not use promises here */
+ let promise = is_chrome ?
+ new Promise((resolve, reject) =>
+ chrome.storage.local.get(key,
+ val => resolve(val))) :
+ browser.storage.local.get(key);
- async function get_var(name)
- {
- return get(TYPE_PREFIX.VAR + name);
+ return (await promise)[key];
+ } catch (e) {
+ console.log(e);
+ }
+}
+
+async function set(key, value)
+{
+ try {
+ return browser.storage.local.set({[key]: value});
+ } catch (e) {
+ console.log(e);
+ }
+}
+
+async function setn(keys_and_values)
+{
+ let obj = Object();
+ while (keys_and_values.length > 1) {
+ let value = keys_and_values.pop();
+ let key = keys_and_values.pop();
+ obj[key] = value;
}
- /*
- * A special case of persisted variable is one that contains list
- * of items.
- */
-
- async function get_list_var(name)
- {
- let list = await get_var(name);
-
- return list === undefined ? [] : list;
+ try {
+ return browser.storage.local.set(obj);
+ } catch (e) {
+ console.log(e);
}
+}
- /* We maintain in-memory copies of some stored lists. */
+async function set_var(name, value)
+{
+ return set(TYPE_PREFIX.VAR + name, value);
+}
- async function list(prefix)
- {
- let name = TYPE_NAME[prefix] + "s"; /* Make plural. */
- let map = new Map();
+async function get_var(name)
+{
+ return get(TYPE_PREFIX.VAR + name);
+}
- for (let item of await get_list_var(name))
- map.set(item, await get(prefix + item));
+/*
+ * A special case of persisted variable is one that contains list
+ * of items.
+ */
- return {map, prefix, name, listeners : new Set(), lock : make_lock()};
- }
+async function get_list_var(name)
+{
+ let list = await get_var(name);
- var pages;
- var bags;
- var scripts;
+ return list === undefined ? [] : list;
+}
- var list_by_prefix = {};
+/* We maintain in-memory copies of some stored lists. */
- async function init()
- {
- for (let prefix of list_prefixes)
- list_by_prefix[prefix] = await list(prefix);
+async function list(prefix)
+{
+ let name = TYPE_NAME[prefix] + "s"; /* Make plural. */
+ let map = new Map();
- return exports;
- }
+ for (let item of await get_list_var(name))
+ map.set(item, await get(prefix + item));
- /*
- * Facilitate listening to changes
- */
+ return {map, prefix, name, listeners : new Set(), lock : make_lock()};
+}
- exports.add_change_listener = function (cb, prefixes=list_prefixes)
- {
- if (typeof(prefixes) === "string")
- prefixes = [prefixes];
+var pages;
+var bags;
+var scripts;
- for (let prefix of prefixes)
- list_by_prefix[prefix].listeners.add(cb);
- }
+var list_by_prefix = {};
- exports.remove_change_listener = function (cb, prefixes=list_prefixes)
- {
- if (typeof(prefixes) === "string")
- prefixes = [prefixes];
+async function init()
+{
+ for (let prefix of list_prefixes)
+ list_by_prefix[prefix] = await list(prefix);
- for (let prefix of prefixes)
- list_by_prefix[prefix].listeners.delete(cb);
- }
+ return exports;
+}
- function broadcast_change(change, list)
- {
- for (let listener_callback of list.listeners)
- listener_callback(change);
- }
+/*
+ * Facilitate listening to changes
+ */
- /* Prepare some hepler functions to get elements of a list */
+exports.add_change_listener = function (cb, prefixes=list_prefixes)
+{
+ if (typeof(prefixes) === "string")
+ prefixes = [prefixes];
- function list_items_it(list, with_values=false)
- {
- return with_values ? list.map.entries() : list.map.keys();
- }
+ for (let prefix of prefixes)
+ list_by_prefix[prefix].listeners.add(cb);
+}
- function list_entries_it(list)
- {
- return list_items_it(list, true);
- }
+exports.remove_change_listener = function (cb, prefixes=list_prefixes)
+{
+ if (typeof(prefixes) === "string")
+ prefixes = [prefixes];
- function list_items(list, with_values=false)
- {
- let array = [];
+ for (let prefix of prefixes)
+ list_by_prefix[prefix].listeners.delete(cb);
+}
- for (let item of list_items_it(list, with_values))
- array.push(item);
+function broadcast_change(change, list)
+{
+ for (let listener_callback of list.listeners)
+ listener_callback(change);
+}
- return array;
- }
+/* Prepare some hepler functions to get elements of a list */
- function list_entries(list)
- {
- return list_items(list, true);
- }
+function list_items_it(list, with_values=false)
+{
+ return with_values ? list.map.entries() : list.map.keys();
+}
- /*
- * Below we make additional effort to update map of given kind of items
- * every time an item is added/removed to keep everything coherent.
- */
- async function set_item(item, value, list)
- {
- await lock(list.lock);
- let result = await _set_item(...arguments);
- unlock(list.lock)
- return result;
- }
- async function _set_item(item, value, list)
- {
- let key = list.prefix + item;
- let old_val = list.map.get(item);
- if (old_val === undefined) {
- let items = list_items(list);
- items.push(item);
- await setn([key, value, "_" + list.name, items]);
- } else {
- await set(key, value);
- }
+function list_entries_it(list)
+{
+ return list_items_it(list, true);
+}
- list.map.set(item, value)
+function list_items(list, with_values=false)
+{
+ let array = [];
- let change = {
- prefix : list.prefix,
- item,
- old_val,
- new_val : value
- };
+ for (let item of list_items_it(list, with_values))
+ array.push(item);
- broadcast_change(change, list);
+ return array;
+}
- return old_val;
- }
+function list_entries(list)
+{
+ return list_items(list, true);
+}
- // TODO: The actual idea to set value to undefined is good - this way we can
- // also set a new list of items in the same API call. But such key
- // is still stored in the storage. We need to somehow remove it later.
- // For that, we're going to have to store 1 more list of each kind.
- async function remove_item(item, list)
- {
- await lock(list.lock);
- let result = await _remove_item(...arguments);
- unlock(list.lock)
- return result;
+/*
+ * Below we make additional effort to update map of given kind of items
+ * every time an item is added/removed to keep everything coherent.
+ */
+async function set_item(item, value, list)
+{
+ await lock(list.lock);
+ let result = await _set_item(...arguments);
+ unlock(list.lock)
+ return result;
+}
+async function _set_item(item, value, list)
+{
+ let key = list.prefix + item;
+ let old_val = list.map.get(item);
+ if (old_val === undefined) {
+ let items = list_items(list);
+ items.push(item);
+ await setn([key, value, "_" + list.name, items]);
+ } else {
+ await set(key, value);
}
- async function _remove_item(item, list)
- {
- let old_val = list.map.get(item);
+
+ list.map.set(item, value)
+
+ let change = {
+ prefix : list.prefix,
+ item,
+ old_val,
+ new_val : value
+ };
+
+ broadcast_change(change, list);
+
+ return old_val;
+}
+
+// TODO: The actual idea to set value to undefined is good - this way we can
+// also set a new list of items in the same API call. But such key
+// is still stored in the storage. We need to somehow remove it later.
+// For that, we're going to have to store 1 more list of each kind.
+async function remove_item(item, list)
+{
+ await lock(list.lock);
+ let result = await _remove_item(...arguments);
+ unlock(list.lock)
+ return result;
+}
+async function _remove_item(item, list)
+{
+ let old_val = list.map.get(item);
+ if (old_val === undefined)
+ return;
+
+ let key = list.prefix + item;
+ let items = list_items(list);
+ let index = items.indexOf(item);
+ items.splice(index, 1);
+
+ await setn([key, undefined, "_" + list.name, items]);
+
+ list.map.delete(item);
+
+ let change = {
+ prefix : list.prefix,
+ item,
+ old_val,
+ new_val : undefined
+ };
+
+ broadcast_change(change, list);
+
+ return old_val;
+}
+
+// TODO: same as above applies here
+async function replace_item(old_item, new_item, list, new_val=undefined)
+{
+ await lock(list.lock);
+ let result = await _replace_item(...arguments);
+ unlock(list.lock)
+ return result;
+}
+async function _replace_item(old_item, new_item, list, new_val=undefined)
+{
+ let old_val = list.map.get(old_item);
+ if (new_val === undefined) {
if (old_val === undefined)
return;
-
- let key = list.prefix + item;
- let items = list_items(list);
- let index = items.indexOf(item);
- items.splice(index, 1);
-
- await setn([key, undefined, "_" + list.name, items]);
-
- list.map.delete(item);
-
- let change = {
- prefix : list.prefix,
- item,
- old_val,
- new_val : undefined
- };
-
- broadcast_change(change, list);
-
+ new_val = old_val
+ } else if (new_val === old_val && new_item === old_item) {
return old_val;
}
- // TODO: same as above applies here
- async function replace_item(old_item, new_item, list, new_val=undefined)
- {
- await lock(list.lock);
- let result = await _replace_item(...arguments);
- unlock(list.lock)
- return result;
+ if (old_item === new_item || old_val === undefined) {
+ await _set_item(new_item, new_val, list);
+ return old_val;
}
- async function _replace_item(old_item, new_item, list, new_val=undefined)
- {
- let old_val = list.map.get(old_item);
- if (new_val === undefined) {
- if (old_val === undefined)
- return;
- new_val = old_val
- } else if (new_val === old_val && new_item === old_item) {
- return old_val;
- }
- if (old_item === new_item || old_val === undefined) {
- await _set_item(new_item, new_val, list);
- return old_val;
- }
+ let new_key = list.prefix + new_item;
+ let old_key = list.prefix + old_item;
+ let items = list_items(list);
+ let index = items.indexOf(old_item);
+ items[index] = new_item;
+ await setn([old_key, undefined, new_key, new_val,
+ "_" + list.name, items]);
- let new_key = list.prefix + new_item;
- let old_key = list.prefix + old_item;
- let items = list_items(list);
- let index = items.indexOf(old_item);
- items[index] = new_item;
- await setn([old_key, undefined, new_key, new_val,
- "_" + list.name, items]);
+ list.map.delete(old_item);
- list.map.delete(old_item);
+ let change = {
+ prefix : list.prefix,
+ item : old_item,
+ old_val,
+ new_val : undefined
+ };
- let change = {
- prefix : list.prefix,
- item : old_item,
- old_val,
- new_val : undefined
- };
+ broadcast_change(change, list);
- broadcast_change(change, list);
+ list.map.set(new_item, new_val);
- list.map.set(new_item, new_val);
+ change.item = new_item;
+ change.old_val = undefined;
+ change.new_val = new_val;
- change.item = new_item;
- change.old_val = undefined;
- change.new_val = new_val;
+ broadcast_change(change, list);
- broadcast_change(change, list);
-
- return old_val;
- }
+ return old_val;
+}
- /*
- * For scripts, item name is chosen by user, data should be
- * an object containing:
- * - script's url and hash or
- * - script's text or
- * - all three
- */
-
- /*
- * For bags, item name is chosen by user, data is an array of 2-element
- * arrays with type prefix and script/bag names.
- */
-
- /*
- * For pages data argument is an object with properties `allow'
- * and `components'. Item name is url.
- */
-
- exports.set = async function (prefix, item, data)
- {
- return set_item(item, data, list_by_prefix[prefix]);
- }
+/*
+ * For scripts, item name is chosen by user, data should be
+ * an object containing:
+ * - script's url and hash or
+ * - script's text or
+ * - all three
+ */
- exports.get = function (prefix, item)
- {
- return list_by_prefix[prefix].map.get(item);
- }
+/*
+ * For bags, item name is chosen by user, data is an array of 2-element
+ * arrays with type prefix and script/bag names.
+ */
- exports.remove = async function (prefix, item)
- {
- return remove_item(item, list_by_prefix[prefix]);
- }
+/*
+ * For pages data argument is an object with properties `allow'
+ * and `components'. Item name is url.
+ */
- exports.replace = async function (prefix, old_item, new_item,
- new_data=undefined)
- {
- return replace_item(old_item, new_item, list_by_prefix[prefix],
- new_data);
- }
+exports.set = async function (prefix, item, data)
+{
+ return set_item(item, data, list_by_prefix[prefix]);
+}
+
+exports.get = function (prefix, item)
+{
+ return list_by_prefix[prefix].map.get(item);
+}
+
+exports.remove = async function (prefix, item)
+{
+ return remove_item(item, list_by_prefix[prefix]);
+}
+
+exports.replace = async function (prefix, old_item, new_item,
+ new_data=undefined)
+{
+ return replace_item(old_item, new_item, list_by_prefix[prefix],
+ new_data);
+}
+
+exports.get_all_names = function (prefix)
+{
+ return list_items(list_by_prefix[prefix]);
+}
+
+exports.get_all_names_it = function (prefix)
+{
+ return list_items_it(list_by_prefix[prefix]);
+}
+
+exports.get_all = function (prefix)
+{
+ return list_entries(list_by_prefix[prefix]);
+}
+
+exports.get_all_it = function (prefix)
+{
+ return list_entries_it(list_by_prefix[prefix]);
+}
+
+/* Finally, a quick way to wipe all the data. */
+// TODO: maybe delete items in such order that none of them ever references
+// an already-deleted one?
+exports.clear = async function ()
+{
+ let lists = list_prefixes.map((p) => list_by_prefix[p]);
+
+ for (let list of lists)
+ await lock(list.lock);
- exports.get_all_names = function (prefix)
- {
- return list_items(list_by_prefix[prefix]);
- }
+ for (let list of lists) {
- exports.get_all_names_it = function (prefix)
- {
- return list_items_it(list_by_prefix[prefix]);
- }
+ let change = {
+ prefix : list.prefix,
+ new_val : undefined
+ };
- exports.get_all = function (prefix)
- {
- return list_entries(list_by_prefix[prefix]);
- }
+ for (let [item, val] of list_entries_it(list)) {
+ change.item = item;
+ change.old_val = val;
+ broadcast_change(change, list);
+ }
- exports.get_all_it = function (prefix)
- {
- return list_entries_it(list_by_prefix[prefix]);
+ list.map = new Map();
}
- /* Finally, a quick way to wipe all the data. */
- // TODO: maybe delete items in such order that none of them ever references
- // an already-deleted one?
- exports.clear = async function ()
- {
- let lists = list_prefixes.map((p) => list_by_prefix[p]);
-
- for (let list of lists)
- await lock(list.lock);
-
- for (let list of lists) {
-
- let change = {
- prefix : list.prefix,
- new_val : undefined
- };
+ await browser.storage.local.clear();
- for (let [item, val] of list_entries_it(list)) {
- change.item = item;
- change.old_val = val;
- broadcast_change(change, list);
- }
+ for (let list of lists)
+ unlock(list.lock);
+}
- list.map = new Map();
- }
-
- await browser.storage.local.clear();
+const get_storage = make_once(init);
- for (let list of lists)
- unlock(list.lock);
- }
-
- window.get_storage = make_once(init);
-})();
+/*
+ * EXPORTS_START
+ * EXPORT get_storage
+ * EXPORTS_END
+ */