taler-typescript-core

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

commit 54acc650f976de4d3bb38d06f1d67d1be13aeca7
parent 5a4c06c2dcda8b8cad3208cd47714bd466619c13
Author: Florian Dold <dold@taler.net>
Date:   Fri, 28 Aug 2026 17:09:21 +0200

wallet-core: stop temporary SQLite import helpers

Diffstat:
Mpackages/idb-bridge/src/node-helper-sqlite3-impl.test.ts | 2++
Mpackages/idb-bridge/src/node-helper-sqlite3-impl.ts | 42+++++++++++++++++++++++++++++++++++++++++-
Mpackages/taler-wallet-core/src/host-impl.node.ts | 33++++++++++++++++++++++++---------
Mpackages/taler-wallet-core/src/requests.test.ts | 1+
4 files changed, 68 insertions(+), 10 deletions(-)

diff --git a/packages/idb-bridge/src/node-helper-sqlite3-impl.test.ts b/packages/idb-bridge/src/node-helper-sqlite3-impl.test.ts @@ -23,6 +23,7 @@ import { Sqlite3Error } from "./sqlite3-interface.js"; test("sqlite3 helper", async (t) => { const filename = ":memory:"; const impl = await createNodeHelperSqlite3Impl(); + t.after(async () => await impl.shutdown()); const db = await impl.open(filename); @@ -104,4 +105,5 @@ test("sqlite3 helper", async (t) => { ); await db.close(); + await impl.shutdown(); }); diff --git a/packages/idb-bridge/src/node-helper-sqlite3-impl.ts b/packages/idb-bridge/src/node-helper-sqlite3-impl.ts @@ -76,6 +76,7 @@ class Helper { private isListening: boolean = false; public proc: ChildProcessByStdio<stream.Writable, stream.Readable, null>; private promStarted: Promise<void>; + private shutdownPromise: Promise<void> | undefined; constructor(opts?: { enableTracing: boolean }) { this.enableTracing = opts?.enableTracing ?? false; @@ -227,6 +228,37 @@ class Helper { } return resp; } + + shutdown(): Promise<void> { + if (this.shutdownPromise) { + return this.shutdownPromise; + } + this.shutdownPromise = new Promise<void>((resolve, reject) => { + if (this.proc.exitCode !== null) { + resolve(); + return; + } + this.refProc(); + this.proc.once("error", reject); + this.proc.once("exit", (code, signal) => { + if (code === 0) { + resolve(); + } else { + reject( + Error( + `taler-helper-sqlite3 exited with ${ + signal ? `signal ${signal}` : `status ${code}` + }`, + ), + ); + } + }); + // The helper exits cleanly on EOF. Its SHUTDOWN protocol command is + // not implemented by all deployed helper versions. + this.proc.stdin.end(); + }); + return this.shutdownPromise; + } } enum TypeTag { @@ -401,9 +433,14 @@ function expectCommunicateSuccess(commRes: Uint8Array): void { } } +export interface NodeHelperSqlite3Interface extends Sqlite3Interface { + /** Stop the helper process after all databases have been closed. */ + shutdown(): Promise<void>; +} + export async function createNodeHelperSqlite3Impl( opts: { enableTracing?: boolean } = {}, -): Promise<Sqlite3Interface> { +): Promise<NodeHelperSqlite3Interface> { const enableTracing = opts.enableTracing ?? false; const helper = new Helper({ enableTracing }); const resp = await helper.communicate(HelperCmd.HELLO, new Uint8Array()); @@ -412,6 +449,9 @@ export async function createNodeHelperSqlite3Impl( let counterPrep = 1; return { + async shutdown(): Promise<void> { + await helper.shutdown(); + }, async open(filename: string): Promise<Sqlite3Database> { if (enableTracing) { console.error(`opening database ${filename}`); diff --git a/packages/taler-wallet-core/src/host-impl.node.ts b/packages/taler-wallet-core/src/host-impl.node.ts @@ -60,7 +60,10 @@ import { import * as fs from "node:fs"; import { IdbWalletDbHandle } from "./db/indexeddb/handle.js"; import { SqliteWalletDbHandle } from "./db/sqlite/handle.js"; -import { importWalletDbDump } from "./db/migration/import.js"; +import { + getWalletDbDumpBackend, + importWalletDbDump, +} from "./db/migration/import.js"; const logger = new Logger("host-impl.node.ts"); @@ -86,14 +89,26 @@ function addNodeDatabaseCapabilities(handle: WalletDbHandle): WalletDbHandle { }; handle.readBackupJson = async (path) => JSON.parse(await fs.promises.readFile(path, "utf-8")); - handle.importAnyDatabase = async (dump, finalize, options) => - await importWalletDbDump( - await createNodeHelperSqlite3Impl({ enableTracing: false }), - handle, - dump, - finalize, - options, - ); + handle.importAnyDatabase = async (dump, finalize, options) => { + if (getWalletDbDumpBackend(dump) === handle.name) { + await handle.importDatabase(dump, finalize, options); + return; + } + const temporarySqlite = await createNodeHelperSqlite3Impl({ + enableTracing: false, + }); + try { + await importWalletDbDump( + temporarySqlite, + handle, + dump, + finalize, + options, + ); + } finally { + await temporarySqlite.shutdown(); + } + }; return handle; } diff --git a/packages/taler-wallet-core/src/requests.test.ts b/packages/taler-wallet-core/src/requests.test.ts @@ -228,6 +228,7 @@ test("importDb request converts a foreign backend dump", async () => { } else { await target.close(); } + await sqlite3Impl.shutdown(); } });