From 261548ff184926567a623e90df7954aeef842d59 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Wed, 30 Jun 2021 12:28:05 +0200 Subject: emply an sh-based build system; make some changes to blocking --- background/storage.js | 654 +++++++++++++++++++++++++------------------------- 1 file changed, 330 insertions(+), 324 deletions(-) (limited to 'background/storage.js') 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 + */ -- cgit v1.2.3