From: Chris Duncan Date: Thu, 13 Aug 2026 06:02:22 +0000 (-0700) Subject: Refactor async worker to avoid overwriting message handler, simplify dispatch, and... X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=241057cb48ddaf002a896cb9e47e36376ae286d5;p=nano25519.git Refactor async worker to avoid overwriting message handler, simplify dispatch, and narrow return cases. --- diff --git a/src/lib/nano25519.ts b/src/lib/nano25519.ts index 4c8e2a4..ff2fc60 100644 --- a/src/lib/nano25519.ts +++ b/src/lib/nano25519.ts @@ -315,6 +315,7 @@ const nano25519_worker = `;(${nano25519_worker_init})((${nano25519_init})([${nan */ let isWorkerReady: boolean = false let isWorkerListening: boolean = false +let tasks: Map[0]>> = new Map() let worker: Worker | NodeWorker let url: string @@ -353,17 +354,35 @@ function reset (): void { init() } +function onresult (msg: { data: Record }): void { + const { data } = msg + if (data.url !== url) return + if (!('id' in data) || typeof data.id !== 'string') return + + const executor = tasks.get(data.id) + if (executor == null) return + const [ok, err] = executor + + const { result } = data + console.log('received result from worker') + if (typeof result !== 'boolean' && typeof result !== 'string' && !isBytes(result)) { + err('Invalid return type') + } + ok(result) +} + // Check that the worker is running and listening before sending messages async function start (): Promise { if (!isWorkerReady) init() if (!isWorkerListening) { return new Promise(async (resolve, reject): Promise => { const onstarted = (msg: { data: Record }): void => { - const { data } = msg - if (data.url !== url) return - const { result } = data + if (msg.data.url !== url) return + const { result } = msg.data if (result === 'started') { console.log('worker started successfully') + BROWSER: { (worker as Worker).onmessage = onresult } + NODE: { (worker as NodeWorker).on('message', onresult) } isWorkerListening = true resolve() } else { @@ -373,59 +392,41 @@ async function start (): Promise { } console.log(`starting worker`) const id = crypto.randomUUID() + const data = { url, id, action: 'start' } BROWSER: { worker = worker as Worker worker.onerror = reject worker.onmessage = onstarted - worker.postMessage({ url, id, action: 'start' }) + worker.postMessage(data) } NODE: { worker = worker as unknown as NodeWorker worker.on('error', reject) worker.on('message', onstarted) - worker.postMessage({ data: { url, id, action: 'start' } }) + worker.postMessage({ data }) } }) } } // Send command and relevant data to nano25519 worker -async function dispatch (data: { [key: string]: string | ArrayBuffer | Uint8Array }): Promise> { - return new Promise((resolve, reject) => { - const id = crypto.randomUUID() - const transfer: ArrayBuffer[] = [] - for (let k of Object.keys(data)) { - if (isBytes(data[k])) { - data[k] = data[k].buffer.slice() - transfer.push(data[k]) - } - } - const onresult = (msg: { data: Record }): void => { - const { data } = msg - if (data.url !== url) return - if (data.id !== id) return - const { result } = data - console.log('received result from worker') - if (typeof result !== 'boolean' && typeof result !== 'string' && !isBytes(result)) { - return reject('Invalid return type') - } - resolve(result) - } - console.log('sending data to worker') - data.url = url - data.id = id - BROWSER: { - worker = worker as Worker - worker.onerror = reject - worker.onmessage = onresult - worker.postMessage(data, transfer) - } - NODE: { - worker = worker as unknown as NodeWorker - worker.on('error', reject) - worker.on('message', onresult) - worker.postMessage({ data }, transfer) +async function dispatch (data: Record>): Promise { + const id = crypto.randomUUID() + const transfer: ArrayBuffer[] = [] + for (let k of Object.keys(data)) { + if (isBytes(data[k])) { + data[k] = data[k].buffer.slice() + transfer.push(data[k]) } + } + console.log('sending data to worker') + data.url = url + data.id = id + return new Promise((resolve, reject) => { + tasks.set(id, [resolve, reject]) + console.log('tasks', tasks) + BROWSER: { (worker as Worker).postMessage(data, transfer) } + NODE: { (worker as NodeWorker).postMessage({ data }, transfer) } }) } @@ -461,10 +462,10 @@ async function stop (): Promise { }) } -export async function run (data: Record<"action", "derive"> & Record>): Promise> -export async function run (data: Record<"action", "sign"> & Record>): Promise> -export async function run (data: Record<"action", "verify"> & Record>): Promise -export async function run (data: Record>): Promise> { +export async function run (data: Record<'action', 'derive'> & Record>): Promise> +export async function run (data: Record<'action', 'sign'> & Record>): Promise> +export async function run (data: Record<'action', 'verify'> & Record>): Promise +export async function run (data: Record<'action', 'derive' | 'sign' | 'verify'> & Record>): Promise> { try { await start() } catch (err: any) { @@ -472,10 +473,29 @@ export async function run (data: Record } try { const result = await dispatch(data) - if (typeof result === 'string' && !/^([0-9a-f]{64}|[0-9a-f]{128})$/i.test(result)) { - throw new Error('Invalid result') + switch (data.action) { + case 'derive': { + if ((isBytes(result) && result.byteLength === 32) || (typeof result === 'string' && /^[0-9a-f]{64}$/i.test(result))) { + return result + } else { + throw new Error('derive result invalid') + } + } + case 'sign': { + if ((isBytes(result) && result.byteLength === 64) || (typeof result === 'string' && /^[0-9a-f]{128}$/i.test(result))) { + return result + } else { + throw new Error('sign result invalid') + } + } + case 'verify': { + if (typeof result === 'boolean') { + return result + } else { + throw new Error('verify result invalid') + } + } } - return result } catch (err: any) { try { await stop()