taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit 6d9021a18dc673d63206f6531da31e147e571550
parent c80cbe224219a230240dafbaeec0ed83563b3b56
Author: Florian Dold <dold@taler.net>
Date:   Thu, 20 Aug 2026 19:06:44 +0200

wallet-core: run Node crypto workers under ESM

Diffstat:
Apackages/taler-wallet-core/src/crypto/workers/nodeThreadWorker.test.ts | 32++++++++++++++++++++++++++++++++
Mpackages/taler-wallet-core/src/crypto/workers/nodeThreadWorker.ts | 69+++++++++++++++++----------------------------------------------------
Mpackages/taler-wallet-core/src/host-impl.node.ts | 15++-------------
3 files changed, 51 insertions(+), 65 deletions(-)

diff --git a/packages/taler-wallet-core/src/crypto/workers/nodeThreadWorker.test.ts b/packages/taler-wallet-core/src/crypto/workers/nodeThreadWorker.test.ts @@ -0,0 +1,32 @@ +/* + This file is part of GNU Taler + (C) 2026 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + +import assert from "node:assert"; +import { test } from "node:test"; +import { CryptoDispatcher } from "./crypto-dispatcher.js"; +import { NodeThreadCryptoWorkerFactory } from "./nodeThreadWorker.js"; + +test("node worker threads execute crypto RPCs in an ESM package", async () => { + const dispatcher = new CryptoDispatcher(new NodeThreadCryptoWorkerFactory()); + try { + const result = await dispatcher.doRpc("hashString", 0, { + str: "worker-thread-test", + }); + assert.strictEqual(typeof (result as { h?: unknown }).h, "string"); + } finally { + dispatcher.stop(); + } +}); diff --git a/packages/taler-wallet-core/src/crypto/workers/nodeThreadWorker.ts b/packages/taler-wallet-core/src/crypto/workers/nodeThreadWorker.ts @@ -19,7 +19,7 @@ */ import { Logger } from "@gnu-taler/taler-util"; import os from "node:os"; -import url from "node:url"; +import { parentPort, Worker } from "node:worker_threads"; import { nativeCryptoR } from "../cryptoImplementation.js"; import { CryptoWorkerFactory } from "./crypto-dispatcher.js"; import { CryptoWorker } from "./cryptoWorkerInterface.js"; @@ -27,45 +27,21 @@ import { processRequestWithImpl } from "./worker-common.js"; const logger = new Logger("nodeThreadWorker.ts"); -const f = import.meta.url - ? url.fileURLToPath(import.meta.url) - : "__not_available__"; - const workerCode = ` - // Try loading the glue library for embedded - try { - require("akono"); - } catch (e) { - try { - require("iono"); - } catch (e2) { - // Probably we're not on embedded ... + const { parentPort } = require("node:worker_threads"); + (async () => { + const tw = await import(${JSON.stringify(import.meta.url)}); + if (typeof tw.handleWorkerMessage !== "function") { + throw Error("module loaded for crypto worker lacks handleWorkerMessage"); } - } - const worker_threads = require('worker_threads'); - const parentPort = worker_threads.parentPort; - let tw; - try { - tw = require("${f}"); - } catch (e) { - console.warn("could not load from ${f}"); - } - if (!tw) { - try { - tw = require("@gnu-taler/taler-wallet-embedded"); - } catch (e) { - console.warn("could not load taler-wallet-embedded either"); - throw e; + if (typeof tw.handleWorkerError !== "function") { + throw Error("module loaded for crypto worker lacks handleWorkerError"); } - } - if (typeof tw.handleWorkerMessage !== "function") { - throw Error("module loaded for crypto worker lacks handleWorkerMessage"); - } - if (typeof tw.handleWorkerError !== "function") { - throw Error("module loaded for crypto worker lacks handleWorkerError"); - } - parentPort.on("message", tw.handleWorkerMessage); - parentPort.on("error", tw.handleWorkerError); + parentPort.on("message", tw.handleWorkerMessage); + parentPort.on("error", tw.handleWorkerError); + })().catch((e) => { + setImmediate(() => { throw e; }); + }); `; /** @@ -76,13 +52,8 @@ export function handleWorkerMessage(msg: any): void { const handleRequest = async (): Promise<void> => { const responseMsg = await processRequestWithImpl(msg, nativeCryptoR); try { - const _r = "require"; - const worker_threads: typeof import("worker_threads") = - module[_r]("worker_threads"); - // const worker_threads = require("worker_threads"); - const p = worker_threads.parentPort; - if (p) { - p.postMessage(responseMsg); + if (parentPort) { + parentPort.postMessage(responseMsg); } else { logger.error("parent port not available (not running in thread?"); } @@ -101,9 +72,6 @@ export function handleWorkerError(e: Error): void { export class NodeThreadCryptoWorkerFactory implements CryptoWorkerFactory { startWorker(): CryptoWorker { - if (typeof require === "undefined") { - throw Error("cannot make worker, require(...) not defined"); - } return new NodeThreadCryptoWorker(); } @@ -126,15 +94,12 @@ class NodeThreadCryptoWorker implements CryptoWorker { */ onerror: undefined | ((m: any) => void); - private nodeWorker: import("worker_threads").Worker; + private nodeWorker: Worker; constructor() { - const _r = "require"; - const worker_threads = module[_r]("worker_threads"); - logger.trace("starting node crypto worker"); - this.nodeWorker = new worker_threads.Worker(workerCode, { eval: true }); + this.nodeWorker = new Worker(workerCode, { eval: true }); this.nodeWorker.on("error", (err: Error) => { logger.error("error in node worker:", err); if (this.onerror) { diff --git a/packages/taler-wallet-core/src/host-impl.node.ts b/packages/taler-wallet-core/src/host-impl.node.ts @@ -261,19 +261,8 @@ export async function createNativeWalletHost2( logger.info("using synchronous crypto worker"); workerFactory = new SynchronousCryptoWorkerFactoryPlain(); } else if (cryptoWorkerType === "node-worker-thread") { - try { - // Try if we have worker threads available, fails in older node versions. - const _r = "require"; - const worker_threads = module[_r]("worker_threads"); - // require("worker_threads"); - workerFactory = new NodeThreadCryptoWorkerFactory(); - logger.info("using node thread crypto worker"); - } catch (e) { - logger.warn( - "worker threads not available, falling back to synchronous workers", - ); - workerFactory = new SynchronousCryptoWorkerFactoryPlain(); - } + workerFactory = new NodeThreadCryptoWorkerFactory(); + logger.info("using node thread crypto worker"); } else { throw Error(`unsupported crypto worker type '${cryptoWorkerType}'`); }