]> zoso.dev Git - libnemo.git/commitdiff
Re-re-factor Thread back to Pool. It doesn't have an application in this library...
authorChris Duncan <chris@zoso.dev>
Mon, 18 Nov 2024 23:22:57 +0000 (15:22 -0800)
committerChris Duncan <chris@zoso.dev>
Mon, 18 Nov 2024 23:22:57 +0000 (15:22 -0800)
src/lib/pool.ts [new file with mode: 0644]
src/lib/safe.ts
src/lib/thread.ts [deleted file]

diff --git a/src/lib/pool.ts b/src/lib/pool.ts
new file mode 100644 (file)
index 0000000..e8a9826
--- /dev/null
@@ -0,0 +1,78 @@
+// SPDX-FileCopyrightText: 2024 Chris Duncan <chris@zoso.dev>
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+import { isDataView } from 'node:util/types'
+
+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 Thread = {
+       isBusy: boolean
+       worker: Worker
+}
+
+/**
+* Processes an array of tasks using Web Workers.
+*/
+export class Pool {
+       #queue: object[] = []
+       #resolve: Function = (value: unknown) => { }
+       #results: object[] = []
+       #threads: Thread[] = []
+
+       get isDone () {
+               for (const thread of this.#threads) {
+                       if (thread.isBusy) {
+                               return false
+                       }
+                       return true
+               }
+       }
+
+       constructor (url: string | URL) {
+               for (let i = navigator.hardwareConcurrency - 1; i > 0; i--) {
+                       const thread = {
+                               isBusy: false,
+                               worker: new Worker(new URL(url, import.meta.url), { type: 'module' })
+                       }
+                       thread.worker.addEventListener('message', (message) => {
+                               thread.isBusy = false
+                               this.#report(thread, message.data ?? message)
+                       })
+                       this.#threads.push(thread)
+               }
+       }
+
+       #assign (thread: Thread) {
+               const next = this.#queue.shift()
+               if (next != null) {
+                       thread.isBusy = true
+                       thread.worker.postMessage(next)
+               }
+       }
+
+       #report (thread: Thread, result: any) {
+               this.#results.push(result)
+               if (this.#queue.length > 0) {
+                       this.#assign(thread)
+               } else if (this.isDone) {
+                       this.#resolve(this.#results)
+               }
+       }
+
+       async work (data: object[]): Promise<any> {
+               if (!Array.isArray(data)) data = [data]
+               return new Promise(resolve => {
+                       this.#queue = data
+                       this.#resolve = resolve
+                       for (const thread of this.#threads) {
+                               this.#assign(thread)
+                       }
+               })
+       }
+}
index 9c541ed9d7f464cc34bf04780604039cbe47f963..e22503f4bde4a0018f28fdfb9d4983e85a431674 100644 (file)
@@ -3,18 +3,14 @@
 
 import { buffer, hex, utf8 } from './convert.js'
 import { Entropy } from './entropy.js'
-import { workerUrl } from './passkey.js'
-import { Thread } from './thread.js'
 const { subtle } = globalThis.crypto
 const ERR_MSG = 'Failed to store item in Safe'
 
 export class Safe {
        #storage: Storage
-       #thread: Thread
 
        constructor () {
                this.#storage = globalThis.sessionStorage
-               this.#thread = new Thread(workerUrl)
        }
 
        /**
@@ -48,10 +44,8 @@ export class Safe {
                const iv = new Entropy()
                if (typeof passkey === 'string') {
                        try {
-                               const keyBuffer = await this.#thread.work({ password: passkey, iv: iv.bytes })
-                               passkey = await subtle.importKey('raw', keyBuffer, 'AES-GCM', false, ['encrypt'])
-                               // passkey = await subtle.importKey('raw', utf8.toBytes(passkey), 'PBKDF2', false, ['deriveBits', 'deriveKey'])
-                               // passkey = await subtle.deriveKey({ name: 'PBKDF2', hash: 'SHA-512', salt: iv.bytes, iterations: 210000 }, passkey, { name: 'AES-GCM', length: 256 }, false, ['encrypt'])
+                               passkey = await subtle.importKey('raw', utf8.toBytes(passkey), 'PBKDF2', false, ['deriveBits', 'deriveKey'])
+                               passkey = await subtle.deriveKey({ name: 'PBKDF2', hash: 'SHA-512', salt: iv.bytes, iterations: 210000 }, passkey, { name: 'AES-GCM', length: 256 }, false, ['encrypt'])
                        } catch (err) {
                                throw new Error(ERR_MSG)
                        }
diff --git a/src/lib/thread.ts b/src/lib/thread.ts
deleted file mode 100644 (file)
index 171416b..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-// SPDX-FileCopyrightText: 2024 Chris Duncan <chris@zoso.dev>
-// 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', (message) => {
-                       const result = message.data ?? message
-                       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<any> {
-               return new Promise(resolve => {
-                       if (this.#isAvailable) {
-                               this.#post({ data, resolve })
-                       } else {
-                               this.#queue.push({ data, resolve })
-                       }
-               })
-       }
-}