From 9f474e3d43b6f7e24a6611c9e5208b8698890e9d Mon Sep 17 00:00:00 2001 From: Varun Patil Date: Mon, 30 Oct 2023 18:00:50 -0700 Subject: [PATCH] worker: switch to library Signed-off-by: Varun Patil --- package-lock.json | 21 ++++- package.json | 3 +- src/components/frame/XImgCache.ts | 2 +- src/components/frame/XImgWorker.ts | 2 +- src/services/worker.ts | 121 ----------------------------- 5 files changed, 21 insertions(+), 128 deletions(-) delete mode 100644 src/services/worker.ts diff --git a/package-lock.json b/package-lock.json index 0626bb13..d26edec1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/package.json b/package.json index 1d93837f..45e1fc88 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/components/frame/XImgCache.ts b/src/components/frame/XImgCache.ts index b441a8f5..221e71e1 100644 --- a/src/components/frame/XImgCache.ts +++ b/src/components/frame/XImgCache.ts @@ -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 diff --git a/src/components/frame/XImgWorker.ts b/src/components/frame/XImgWorker.ts index 65247730..b6bef576 100644 --- a/src/components/frame/XImgWorker.ts +++ b/src/components/frame/XImgWorker.ts @@ -1,5 +1,5 @@ import { CacheExpiration } from 'workbox-expiration'; -import { exportWorker } from '@services/worker'; +import { exportWorker } from 'webworker-typed'; declare var self: ServiceWorkerGlobalScope; diff --git a/src/services/worker.ts b/src/services/worker.ts deleted file mode 100644 index b824e8ef..00000000 --- a/src/services/worker.ts +++ /dev/null @@ -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 = { - [K in keyof T]: T[K] extends (...args: infer A) => Promise - ? (...args: A) => Promise - : T[K] extends (...args: infer A) => infer R - ? (...args: A) => Promise - : 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(handlers: T): Async { - 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; -} - -/** - * 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(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(worker: Worker) { - const promises = new Map(); - - // 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; -}