Skip to content

Commit

Permalink
v2.70
Browse files Browse the repository at this point in the history
  • Loading branch information
erosman authored Jun 3, 2023
1 parent 63c60e2 commit 71ae6ef
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 64 deletions.
38 changes: 36 additions & 2 deletions content/api-message.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,61 @@
import {App} from './app.js';

// ---------- API Message Handler (Side Effect) ------------
class OnMessage {
export class OnMessage {

static {
// message from api.js
browser.runtime.onMessage.addListener((...e) => this.process(...e));
this.pref = {};
}

static process(message, sender) {
static async process(message, sender) {
const {name, api, data: e} = message;
if (!api) { return; }

const id = `_${name}`;
const pref = this.pref;

// only set if in container/incognito
const storeId = sender.tab.cookieStoreId !== 'firefox-default' && sender.tab.cookieStoreId;
const logError = (error) => App.log(name, `${message.api}${error.message}`, 'error');
let needUpdate = false;

switch (api) {
// ---------- internal use only (not GM API) ---------
case 'log':
return App.log(name, e.message, e.type);

// ---------- GM API ---------------------------------

// ---------- storage --------------------------------
case 'setValue':
// e is an object of key/value
Object.entries(e).forEach(([key, value]) => {
if (pref[id].storage[key] !== value) {
pref[id].storage[key] = value;
needUpdate = true;
}
});

if (!needUpdate) { return; } // return if storage hasn't changed

return browser.storage.local.set({[id]: pref[id]}); // Promise with no arguments OR reject with error message

case 'deleteValue':
// e is an array
e.forEach(item => {
if (pref[id].storage.hasOwnProperty(item)) {
delete pref[id].storage[item];
needUpdate = true;
}
});

if (!needUpdate) { return; } // return if storage hasn't changed

return browser.storage.local.set({[id]: pref[id]}); // Promise with no arguments OR reject with error message
// ---------- /storage -------------------------------

case 'download':
// Promise with id OR reject with error message
return browser.downloads.download({
Expand Down
120 changes: 62 additions & 58 deletions content/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,67 @@ browser.userScripts.onBeforeScript.addListener(script => {
// ---------- GM4 Object based functions -----------------
const GM = {

// ---------- background functions ---------------------
// ---------- storage ----------------------------------
async getValue(key, defaultValue) {
const data = await API.getData();
return API.getStorageValue(data.storage, key, defaultValue);
},

// based on browser.storage.local.set()
// An object containing one or more key/value pairs to be stored in storage.
// If an item already exists, its value will be updated.
async setValue(key, value) {
if (!key) { return; }

const obj = typeof key === 'string' ? {[key]: value} : key; // change to object

// update sync storage
Object.entries(obj).forEach(([key, value]) => storage[key] = value);

// update async storage
return browser.runtime.sendMessage({
name,
api: 'setValue',
data: obj
});
},

// based on browser.storage.local.remove()
// A string, or array of strings, representing the key(s) of the item(s) to be removed.
async deleteValue(key) {
if (!key) { return; }

const arr = Array.isArray(key) ? key : [key]; // change to array

// update sync storage
arr.forEach(item => delete storage[item]);

// update async storage
return browser.runtime.sendMessage({
name,
api: 'deleteValue',
data: arr
});
},

async listValues() {
const data = await API.getData();
const value = Object.keys(data.storage);
return script.export(value);
},

addValueChangeListener(key, callback) {
browser.storage.onChanged.addListener(API.onChanged);
valueChange[key] = callback;
return key;
},

removeValueChangeListener(key) {
delete valueChange[key];
},
// ---------- /storage ---------------------------------

// ---------- other background functions ---------------
download(url, filename) {
// --- check url
url = API.checkURL(url);
Expand Down Expand Up @@ -457,63 +517,7 @@ browser.userScripts.onBeforeScript.addListener(script => {
API.callUserScriptCallback(init, type,
typeof response.response === 'string' ? script.export(response) : cloneInto(response, window));
},
// ---------- /background functions --------------------

// ---------- storage ----------------------------------
async getValue(key, defaultValue) {
const data = await API.getData();
return API.getStorageValue(data.storage, key, defaultValue);
},

// based on browser.storage.local.set()
// An object containing one or more key/value pairs to be stored in storage.
// If an item already exists, its value will be updated.
async setValue(key, value) {
if (!key) { return; }

const obj = typeof key === 'string' ? {[key]: value} : key; // change to object

// update sync storage
Object.entries(obj).forEach(([key, value]) => storage[key] = value);

// update async storage
const data = await API.getData();
Object.entries(obj).forEach(([key, value]) => data.storage[key] = value);
return browser.storage.local.set({[id]: data});
},

// based on browser.storage.local.remove()
// A string, or array of strings, representing the key(s) of the item(s) to be removed.
async deleteValue(key) {
if (!key) { return; }

const arr = Array.isArray(key) ? key : [key]; // change to array

// update sync storage
arr.forEach(item => delete storage[item]);

// update async storage
const data = await API.getData();
arr.forEach(item => delete data.storage[item]);
return browser.storage.local.set({[id]: data});
},

async listValues() {
const data = await API.getData();
const value = Object.keys(data.storage);
return script.export(value);
},

addValueChangeListener(key, callback) {
browser.storage.onChanged.addListener(API.onChanged);
valueChange[key] = callback;
return key;
},

removeValueChangeListener(key) {
delete valueChange[key];
},
// ---------- /storage ---------------------------------
// ---------- /other background functions --------------

// ---------- DOM functions ----------------------------
addStyle(str) {
Expand Down
6 changes: 5 additions & 1 deletion content/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import {Match} from './match.js';
import {Script} from './script.js';
import {Counter} from './counter.js';
import {Migrate} from './migrate.js';
import {OnMessage} from './api-message.js';
import './menus.js'
import './installer.js';
import './web-request.js';
import './api-message.js';

// ---------- User Preference ------------------------------
await App.getPref();
Expand All @@ -25,6 +25,9 @@ class ProcessPref {

await Migrate.init(pref); // migrate after storage sync check

// --- API Message
OnMessage.pref = pref;

// --- Script Counter
Counter.init(pref);

Expand All @@ -50,6 +53,7 @@ class ProcessPref {
delete pref[item];
});

OnMessage.pref = pref; // update API message pref
Counter.pref = pref; // update Counter pref
this.processPrefUpdate(changes); // apply changes
Sync.set(changes, pref); // set changes to sync
Expand Down
3 changes: 0 additions & 3 deletions content/help.html
Original file line number Diff line number Diff line change
Expand Up @@ -2298,9 +2298,6 @@ <h3>ℹ️ Asynchronous & Synchronous Storage</h3>
</tbody>
</table>

<p class="warning">Setting multiple asynchronous GM_setValue in succession may result in setting mishap.</p>


<h4>New API Options: getValue, setValue, deleteValue <span>(v2.69)</span></h4>
<p>Userscripts often need to get/set multiple values. Each storage operation result in costly asynchronous read/write which means resources, time, and hard disk wear (especially for SSDs). These new API options aim to alleviate the aforementioned. The new options are based on <a href="https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/storage/StorageArea/get" target="_blank">StorageArea.get()</a>, <a href="https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/storage/StorageArea/set" target="_blank">StorageArea.set()</a> & <a href="https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/storage/StorageArea/remove" target="_blank">StorageArea.remove()</a>.</p>

Expand Down

0 comments on commit 71ae6ef

Please sign in to comment.