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:
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();
}
});