Add async store

This commit is contained in:
yflory 2024-11-19 18:07:39 +01:00
parent b9b94a1c31
commit dcc790535a
3 changed files with 203 additions and 1 deletions

View File

@ -0,0 +1,52 @@
// SPDX-FileCopyrightText: 2023 XWiki CryptPad Team <contact@cryptpad.org> and contributors
//
// SPDX-License-Identifier: AGPL-3.0-or-later
/* global importScripts */
const Interface = require('./interface');
const Util = require('../../common/common-util');
let start = (setConfig) => {
let ready = false;
let closed = false;
let onMsg;
const sendMsgEv = Util.mkEvent();
const closeStore = () => { closed = true; };
const onMessage = (f) => {
sendMsgEv.reg((data) => {
setTimeout(() => {
f(data);
});
});
};
const postMsg = (data) => {
if (closed) { return; }
sendMsgEv.fire(data);
};
const query = () => {
if (!onMsg || closed) { return; }
onMsg.fire({data, origin:''});
};
let init = (cfg) => {
if (ready) { return; }
setConfig(cfg);
Interface.init(closeStore);
ready = true;
Interface.initClient({
postMsg
}, function (_onMsg) {
onMsg = _onMsg;
postMsg('STORE_READY');
});
};
return {
init,
onMessage,
query
};
};
module.exports = { start };

View File

@ -25,6 +25,7 @@ import * as Store from './async-store.js';
import * as StoreRpc from './core/store-rpc.js';
import * as Interface from './core/interface.js';
import * as SWConnector from './core/sw-connector.js';
import * as AsyncConnector from './core/async-connector.js';
// Components
import * as Migrate from './components/migrate-user-object.js';
@ -107,6 +108,7 @@ let start = (cfg: StoreConfig):void => {
let inWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope;
let inSharedWorker = typeof SharedWorkerGlobalScope !== 'undefined' && self instanceof SharedWorkerGlobalScope;
let storeObject = {};
if (inSharedWorker) {
console.error('SHAREDWORKER');
SWConnector.start(start);
@ -116,10 +118,11 @@ if (inSharedWorker) {
console.error('NODEJS');
} else {
console.error('BROWSER');
storeObject = AsyncConnector.start(start);
}
export {
start
storeObject
};

View File

@ -0,0 +1,147 @@
(() => {
const factory = function () {
// XXX TODO
// Support NodeJS
// Support WebWorker
// Return a usable API instead of postMsg/msgEv
// XXX handle AppConfig, ApiConfig, MEssages and Broadcast in this file directly?
// --> pull them using require if browser or... ?
let create = function (cfg = {}) {
let { noWorker, noSharedWorker, AppConfig,
ApiConfig, Messages, Broadcast } = cfg;
const mkEvent = function () {
var handlers = [];
return {
reg: function (cb) {
handlers.push(cb);
},
unreg: function (cb) {
if (handlers.indexOf(cb) === -1) { return; }
handlers.splice(handlers.indexOf(cb), 1);
},
fire: function () {
var args = Array.prototype.slice.call(arguments);
handlers.forEach(function (h) {
h.apply(null, args);
});
}
};
};
let called = false;
let msgEv = mkEvent();
let todo = (resolve, reject) => {
if (called) { return; }
called = true;
if (!noWorker && !noSharedWorker && typeof(SharedWorker) !== "undefined") {
worker = new SharedWorker('/common/worker.bundle.js?' + urlArgs);
worker.onerror = function (e) {
console.error(e.message);
};
worker.port.onmessage = function (ev) {
if (ev.data === "SW_READY") {
return;
}
msgEv.fire(ev);
};
postMsg = function (data) {
worker.port.postMessage(Util.clone(data));
};
postMsg({
type: 'INIT',
cfg: {
AppConfig,
ApiConfig,
Messages,
Broadcast
}
});
window.addEventListener('unload', function () {
postMsg('CLOSE');
});
return void resolve(postMsg, msgEv);
}
// eslint-disable-next-line no-constant-condition
if (!noWorker && Worker) {
worker = new Worker('/common/worker.bundle.js?' + urlArgs);
worker.onerror = function (e) {
console.error(e.message);
};
worker.onmessage = function (ev) {
msgEv.fire(ev);
};
postMsg = function (data) {
worker.postMessage(data);
};
return void resolve(postMsg, msgEv);
}
// Use the async store in the main thread if workers
// aren't available
if (typeof(require) === "undefined") { return; }
require(['/common/worker.bundle.js'], function (Store) {
Store.onMessage(function (data) {
msgEv.fire({data: data, origin: ''});
});
postMsg = function (d) {
setTimeout(function () {
Store.query(d);
});
};
Store.init({
AppConfig,
ApiConfig,
Messages,
Broadcast
});
resolve(postMsg, msgEv);
});
};
return new Promise((resolve, reject) => {
if (typeof(SharedWorker) !== "undefined") {
try {
new SharedWorker('');
} catch (e) {
noSharedWorker = true;
console.log('Disabling SharedWorker because of privacy settings.');
}
}
if (typeof(Worker) !== "undefined") {
try {
worker = new Worker('/common/outer/testworker.js?' + urlArgs);
worker.onerror = function (errEv) {
errEv.preventDefault();
errEv.stopPropagation();
noWorker = true;
worker.terminate();
todo(resolve, reject);
};
worker.onmessage = function (ev) {
if (ev.data === "OK") {
worker.terminate();
todo(resolve, reject);
}
};
} catch (e) {
noWorker = true;
todo(resolve, reject);
}
}
});
};
return create;
};
if (typeof(module) !== 'undefined' && module.exports) {
module.exports = factory();
} else if ((typeof(define) !== 'undefined' && define !== null) && (define.amd !== null)) {
define([], factory);
}
})();