From 61a1e03a2cfb0f400f778f2efef7ac61a32f5a9d Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Mon, 18 Nov 2024 09:52:51 -0800 Subject: [PATCH] Create Thread class to manage worker messages in an asynchronous queue, and begin implementation in Safe class. --- src/lib/safe.ts | 2 ++ src/lib/thread.ts | 59 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 src/lib/thread.ts diff --git a/src/lib/safe.ts b/src/lib/safe.ts index 8654756..9fc4119 100644 --- a/src/lib/safe.ts +++ b/src/lib/safe.ts @@ -3,11 +3,13 @@ import { buffer, hex, utf8 } from './convert.js' import { Entropy } from './entropy.js' +import { Thread } from './thread.js' const { subtle } = globalThis.crypto const ERR_MSG = 'Failed to store item in Safe' export class Safe { #storage = globalThis.sessionStorage + #thread = new Thread(new URL('./placeholder.js', import.meta.url)) /** * Encrypts data with a password and stores it in the Safe. diff --git a/src/lib/thread.ts b/src/lib/thread.ts new file mode 100644 index 0000000..79addc4 --- /dev/null +++ b/src/lib/thread.ts @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: 2024 Chris Duncan +// SPDX-License-Identifier: GPL-3.0-or-later + +if (globalThis.Worker == null) { + const { Worker } = await import('node:worker_threads') + //@ts-expect-error + Worker.prototype.addEventListener = Worker.prototype.addListener + //@ts-expect-error + globalThis.Worker = Worker +} + +type Task = { + data: object, + resolve: Function +} + +/** +* Processes tasks from a queue using a Web Worker. +*/ +export class Thread { + #isAvailable: boolean = true + #queue: Task[] = [] + #task?: Task + #worker: Worker + + #post (next: Task) { + this.#isAvailable = false + this.#task = next + this.#worker.postMessage(next.data) + } + + constructor (url: string | URL) { + this.#worker = new Worker(new URL(url, import.meta.url), { type: 'module' }) + this.#worker.addEventListener('message', (event) => { + const result = event.data ?? event + if (this.#task == null) { + throw new ReferenceError(`Error resolving Worker result: ${result}`) + } + const resolve = this.#task.resolve + const next = this.#queue.shift() + if (next == null) { + this.#isAvailable = true + } else { + this.#post(next) + } + resolve(result) + }) + } + + async work (data: object): Promise { + return new Promise(resolve => { + if (this.#isAvailable) { + this.#post({ data, resolve }) + } else { + this.#queue.push({ data, resolve }) + } + }) + } +} -- 2.34.1