import debug from "debug"; import { NostrEvent, ReqCommand, WorkerMessage } from "./types"; import { v4 as uuid } from "uuid"; export class WorkerRelayInterface { #worker: Worker; #log = (msg: any) => console.debug(msg); #commandQueue: Map) => void> = new Map(); constructor(path: string) { this.#log(`Module path: ${path}`); this.#worker = new Worker(path, { type: "module" }); this.#worker.onmessage = e => { const cmd = e.data as WorkerMessage; if (cmd.cmd === "reply") { const q = this.#commandQueue.get(cmd.id); q?.(cmd, e.ports); this.#commandQueue.delete(cmd.id); } }; } async init() { return (await this.#workerRpc("init")).result; } async open() { return (await this.#workerRpc("open")).result; } async migrate() { return (await this.#workerRpc("migrate")).result; } async event(ev: NostrEvent) { return (await this.#workerRpc("event", ev)).result; } async req(req: ReqCommand) { return await this.#workerRpc>("req", req); } async count(req: ReqCommand) { return (await this.#workerRpc("count", req)).result; } async summary() { return (await this.#workerRpc>("summary")).result; } async close(id: string) { return (await this.#workerRpc("close", id)).result; } async dump() { return (await this.#workerRpc("dumpDb")).result; } async sql(sql: string, params: Array) { return (await this.#workerRpc>>("sql", { sql, params })).result; } #workerRpc(cmd: string, args?: T, timeout = 30_000) { const id = uuid(); const msg = { id, cmd, args, } as WorkerMessage; this.#worker.postMessage(msg); return new Promise<{ result: R; port: MessagePort | undefined; }>((resolve, reject) => { let t: ReturnType; this.#commandQueue.set(id, (v, port) => { clearTimeout(t); const cmdReply = v as WorkerMessage; resolve({ result: cmdReply.args, port: port.length > 0 ? port[0] : undefined, }); }); t = setTimeout(() => { reject("timeout"); this.#commandQueue.delete(id); }, timeout); }); } }