From af49bfc4351111d37214b8de80ed1bd44869009a Mon Sep 17 00:00:00 2001 From: Steven Vandevelde Date: Wed, 9 Jul 2025 17:28:30 +0200 Subject: [PATCH] feat: manage worker connections automatically --- src/pages/processor/artwork/_applet.astro | 27 +--------- src/scripts/applet/common.ts | 12 ++++- src/scripts/common.ts | 61 ++++++++++++++++++++++- src/scripts/processor/artwork/worker.ts | 49 ++---------------- 4 files changed, 75 insertions(+), 74 deletions(-) diff --git a/src/pages/processor/artwork/_applet.astro b/src/pages/processor/artwork/_applet.astro index 19adef7..5b7e1dc 100644 --- a/src/pages/processor/artwork/_applet.astro +++ b/src/pages/processor/artwork/_applet.astro @@ -1,15 +1,12 @@ diff --git a/src/scripts/applet/common.ts b/src/scripts/applet/common.ts index d924503..3d5dd6f 100644 --- a/src/scripts/applet/common.ts +++ b/src/scripts/applet/common.ts @@ -1,4 +1,5 @@ import type { Applet, AppletEvent, AppletScope } from "@web-applets/sdk"; +import type * as Comlink from "comlink"; import { applets } from "@web-applets/sdk"; import { type ElementConfigurator, h } from "spellcaster/hyperscript.js"; @@ -6,6 +7,7 @@ import { effect, isSignal, type Signal, signal } from "spellcaster/spellcaster.j import QS from "query-string"; import type { ResolvedUri } from "@applets/core/types"; +import { transfer, type WorkerActions } from "@scripts/common"; //////////////////////////////////////////// // 🪟 Applet connecting @@ -106,7 +108,9 @@ export type BroadcastedApplet = { setActionHandler(actionId: string, actionHandler: H): void; }; -export function register(): BroadcastedApplet { +export function register( + options: { worker?: Comlink.Remote } = {}, +): BroadcastedApplet { const url = new URL(location.href); const scope = applets.register(); @@ -281,6 +285,12 @@ export function register(): BroadcastedApplet { }, }; + if (options.worker !== undefined) + context.scope.onworkerport = (event) => { + if (!event.port) return; + options.worker?.perform(transfer(event.port)); + }; + return context; } diff --git a/src/scripts/common.ts b/src/scripts/common.ts index 83e7bbe..78b746e 100644 --- a/src/scripts/common.ts +++ b/src/scripts/common.ts @@ -8,6 +8,18 @@ import type { Track } from "@applets/core/types"; // export { SharedWorkerPolyfill as SharedWorker } from "@okikio/sharedworker"; export const SharedWorker = globalThis.SharedWorker; +//////////////////////////////////////////// +// 🌳 +//////////////////////////////////////////// + +export type WorkerActions = { + perform: ReturnType; +}; + +//////////////////////////////////////////// +// 🛠️ +//////////////////////////////////////////// + export function arrayShuffle(array: Array): Array { if (array.length === 0) { return []; @@ -47,13 +59,13 @@ export function comparable(value: unknown) { return xxh32(JSON.stringify(value)); } -export function endpoint>(ini: Comlink.Endpoint) { +export function endpoint = WorkerActions>(ini: Comlink.Endpoint) { const e = Comlink.wrap(ini); if ("start" in ini && typeof ini.start === "function") ini.start(); return e; } -export function expose>(actions: T): T { +export function expose>(actions: A): A { if (globalThis.SharedWorkerGlobalScope && self instanceof SharedWorkerGlobalScope) { self.onconnect = (event: MessageEvent) => { const port = event.ports[0]; @@ -95,6 +107,12 @@ export function jsonEncode(a: T): Uint8Array { return new TextEncoder().encode(JSON.stringify(a)); } +export function provide>(actions: A) { + return expose({ + perform: handleWorkerActions(actions), + }); +} + export async function trackArtworkCacheId(track: Track): Promise { return await crypto.subtle .digest("SHA-256", new TextEncoder().encode(track.uri)) @@ -105,3 +123,42 @@ export function transfer(a: T) { const b = getTransferables(a); return Comlink.transfer(a, b); } + +// PRIVATE + +function handleWorkerActions>(actions: A) { + async function handleAction( + port: MessagePort, + action: { + type: "action"; + id: string; + actionId: string; + arguments: any; + }, + ) { + const result = await actions[action.actionId]?.(action.arguments); + return postMessage(port, action.id, result); + } + + function postMessage(port: MessagePort, id: string, result: T) { + port.postMessage( + { + type: "actioncomplete", + id, + result, + }, + { + transfer: getTransferables(result), + }, + ); + } + + return (port: MessagePort) => { + port.onmessage = async (message) => { + switch (message.data?.type) { + case "action": + return handleAction(port, message.data); + } + }; + }; +} diff --git a/src/scripts/processor/artwork/worker.ts b/src/scripts/processor/artwork/worker.ts index b0b1126..cdc0557 100644 --- a/src/scripts/processor/artwork/worker.ts +++ b/src/scripts/processor/artwork/worker.ts @@ -2,7 +2,7 @@ import type { IPicture } from "music-metadata"; import * as IDB from "idb-keyval"; import type { Artwork, ArtworkRequest } from "./types"; -import { expose, transfer } from "@scripts/common"; +import { expose, provide, transfer } from "@scripts/common"; import { IDB_ARTWORK_PREFIX } from "./constants"; import { musicMetadataTags } from "../metadata/common"; import { getTransferables } from "@okikio/transferables"; @@ -13,53 +13,10 @@ let queue: ArtworkRequest[] = []; //////////////////////////////////////////// // ACTIONS //////////////////////////////////////////// -const c = expose({ - connect, -}); - -export type Actions = typeof c; - -const actions: { [key: string]: Function } = { +provide({ artwork, supply, -}; - -// ⚡️ - -async function connect(port: MessagePort) { - port.onmessage = async (message) => { - switch (message.data?.type) { - case "action": - return handleAction(port, message.data); - } - }; -} - -async function handleAction( - port: MessagePort, - action: { - type: "action"; - id: string; - actionId: string; - arguments: any; - }, -) { - const result = await actions[action.actionId]?.(action.arguments); - return postMessage(port, action.id, result); -} - -function postMessage(port: MessagePort, id: string, result: T) { - port.postMessage( - { - type: "actioncomplete", - id, - result, - }, - { - transfer: getTransferables(result), - }, - ); -} +}); // Actions -- 2.51.2