parent
e1c89f9cb0
commit
9f474e3d43
|
@ -30,7 +30,8 @@
|
|||
"vue-router": "^3.6.5",
|
||||
"vue-virtual-scroller": "1.1.2",
|
||||
"vue2-leaflet": "^2.7.1",
|
||||
"webdav": "^5.3.0"
|
||||
"webdav": "^5.3.0",
|
||||
"webworker-typed": "^1.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.39.0",
|
||||
|
@ -8908,7 +8909,6 @@
|
|||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
|
||||
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
|
@ -9879,6 +9879,14 @@
|
|||
"url": "https://opencollective.com/webpack"
|
||||
}
|
||||
},
|
||||
"node_modules/webworker-typed": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/webworker-typed/-/webworker-typed-1.0.4.tgz",
|
||||
"integrity": "sha512-gKIJ8MkFlF44KOSs0eNPhnOUcig9vBcbzDCn0jnHZwKBpvg/p/vM3Gjruaw0fUnxnXGffrDC+aSkwTH2pIC/zg==",
|
||||
"peerDependencies": {
|
||||
"typescript": "^5.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
|
||||
|
@ -16671,8 +16679,7 @@
|
|||
"typescript": {
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
|
||||
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w=="
|
||||
},
|
||||
"unbox-primitive": {
|
||||
"version": "1.0.2",
|
||||
|
@ -17340,6 +17347,12 @@
|
|||
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
|
||||
"integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w=="
|
||||
},
|
||||
"webworker-typed": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/webworker-typed/-/webworker-typed-1.0.4.tgz",
|
||||
"integrity": "sha512-gKIJ8MkFlF44KOSs0eNPhnOUcig9vBcbzDCn0jnHZwKBpvg/p/vM3Gjruaw0fUnxnXGffrDC+aSkwTH2pIC/zg==",
|
||||
"requires": {}
|
||||
},
|
||||
"whatwg-url": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
|
||||
|
|
|
@ -51,7 +51,8 @@
|
|||
"vue-router": "^3.6.5",
|
||||
"vue-virtual-scroller": "1.1.2",
|
||||
"vue2-leaflet": "^2.7.1",
|
||||
"webdav": "^5.3.0"
|
||||
"webdav": "^5.3.0",
|
||||
"webworker-typed": "^1.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.2.0",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { API } from '@services/API';
|
||||
import { onDOMLoaded } from '@services/utils';
|
||||
import { importWorker } from '@services/worker';
|
||||
import { importWorker } from 'webworker-typed';
|
||||
import type XImgWorker from './XImgWorker';
|
||||
|
||||
// Global web worker to fetch images
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { CacheExpiration } from 'workbox-expiration';
|
||||
import { exportWorker } from '@services/worker';
|
||||
import { exportWorker } from 'webworker-typed';
|
||||
|
||||
declare var self: ServiceWorkerGlobalScope;
|
||||
|
||||
|
|
|
@ -1,121 +0,0 @@
|
|||
/**
|
||||
* Data sent from main thread to worker.
|
||||
*/
|
||||
type CommRequest = {
|
||||
reqid: number;
|
||||
name: string;
|
||||
args: any[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Data sent from worker to main thread.
|
||||
*/
|
||||
type CommResult = {
|
||||
reqid: number;
|
||||
resolve?: any;
|
||||
reject?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Map of function names to functions.
|
||||
*/
|
||||
type FunctionMap = { [name: string]: Function };
|
||||
|
||||
/**
|
||||
* Utility type to convert all methods in an object to async.
|
||||
*/
|
||||
type Async<T extends FunctionMap> = {
|
||||
[K in keyof T]: T[K] extends (...args: infer A) => Promise<infer R>
|
||||
? (...args: A) => Promise<R>
|
||||
: T[K] extends (...args: infer A) => infer R
|
||||
? (...args: A) => Promise<R>
|
||||
: T[K];
|
||||
};
|
||||
|
||||
/**
|
||||
* Export methods from a worker to the main thread.
|
||||
*
|
||||
* @param handlers Object with methods to export
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // my-worker.ts
|
||||
* function foo() { return 'bar'; }
|
||||
*
|
||||
* async function asyncFoo() { return 'bar'; }
|
||||
*
|
||||
* export default exportWorker({
|
||||
* foo,
|
||||
* asyncFoo,
|
||||
* inline: () => 'bar',
|
||||
* });
|
||||
*/
|
||||
export function exportWorker<T extends FunctionMap>(handlers: T): Async<T> {
|
||||
self.onmessage = async ({ data }: { data: CommRequest }) => {
|
||||
try {
|
||||
// Get handler from registrations
|
||||
const handler = handlers[data.name];
|
||||
if (!handler) throw new Error(`[BUG] No handler for type ${data.name}`);
|
||||
|
||||
// Run handler
|
||||
let result = handler.apply(self, data.args);
|
||||
if (result instanceof Promise) {
|
||||
result = await result;
|
||||
}
|
||||
|
||||
// Success - post back to main thread
|
||||
self.postMessage({ reqid: data.reqid, resolve: result } as CommResult);
|
||||
} catch (e) {
|
||||
// Error - post back rejection
|
||||
self.postMessage({ reqid: data.reqid, reject: e.message } as CommResult);
|
||||
}
|
||||
};
|
||||
|
||||
return null as unknown as Async<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Import a worker exported with `exportWorker`.
|
||||
*
|
||||
* @param worker Worker to import
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // main.ts
|
||||
* import type MyWorker from './my-worker.ts';
|
||||
*
|
||||
* const worker = importWorker<typeof MyWorker>(new Worker(new URL('./XImgWorkerStub.ts', import.meta.url)));
|
||||
*
|
||||
* async (() => {
|
||||
* // all methods are async
|
||||
* console.assert(await worker.foo() === 'bar');
|
||||
* console.assert(await worker.asyncFoo() === 'bar');
|
||||
* console.assert(await worker.inline() === 'bar');
|
||||
* });
|
||||
*/
|
||||
export function importWorker<T>(worker: Worker) {
|
||||
const promises = new Map<number, { resolve: Function; reject: Function }>();
|
||||
|
||||
// Handle messages from worker
|
||||
worker.onmessage = ({ data }: { data: CommResult }) => {
|
||||
const { reqid, resolve, reject } = data;
|
||||
if (resolve) promises.get(reqid)?.resolve(resolve);
|
||||
if (reject) promises.get(reqid)?.reject(reject);
|
||||
promises.delete(reqid);
|
||||
};
|
||||
|
||||
// Create proxy to call worker methods
|
||||
const proxy = new Proxy(worker, {
|
||||
get(target: Worker, name: string) {
|
||||
return async function wrapper(...args: any[]) {
|
||||
return await new Promise((resolve, reject) => {
|
||||
const reqid = Math.random();
|
||||
promises.set(reqid, { resolve, reject });
|
||||
target.postMessage({ reqid, name, args } as CommRequest);
|
||||
});
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
return proxy as T;
|
||||
}
|
Loading…
Reference in New Issue