aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2024-11-06 14:35:11 +0100
committerFlorian Dold <florian@dold.me>2024-11-06 14:35:11 +0100
commit5c1bcc68baed6593ca107ac4d6f5f2b850a7b688 (patch)
tree58bcd0745e6d29757107f2f6a4de7d90787f72d6
parent2689781c2086a40f1252e7a8a4acb263074ed7ac (diff)
wallet-core: implement exporting DB to file
-rw-r--r--packages/idb-bridge/src/SqliteBackend.ts15
-rw-r--r--packages/taler-harness/src/bench1.ts12
-rw-r--r--packages/taler-harness/src/bench3.ts12
-rw-r--r--packages/taler-util/src/types-taler-wallet.ts28
-rw-r--r--packages/taler-wallet-cli/src/index.ts6
-rw-r--r--packages/taler-wallet-core/src/host-impl.missing.ts1
-rw-r--r--packages/taler-wallet-core/src/host-impl.node.ts36
-rw-r--r--packages/taler-wallet-core/src/host-impl.qtart.ts30
-rw-r--r--packages/taler-wallet-core/src/host.ts4
-rw-r--r--packages/taler-wallet-core/src/wallet-api-types.ts26
-rw-r--r--packages/taler-wallet-core/src/wallet.ts71
-rw-r--r--packages/taler-wallet-embedded/src/wallet-qjs-tests.ts6
12 files changed, 176 insertions, 71 deletions
diff --git a/packages/idb-bridge/src/SqliteBackend.ts b/packages/idb-bridge/src/SqliteBackend.ts
index 26ed43b0f..8213de366 100644
--- a/packages/idb-bridge/src/SqliteBackend.ts
+++ b/packages/idb-bridge/src/SqliteBackend.ts
@@ -44,15 +44,15 @@ import {
structuredEncapsulate,
structuredRevive,
} from "./index.js";
-import { ConstraintError, DataError } from "./util/errors.js";
-import { getIndexKeys } from "./util/getIndexKeys.js";
-import { deserializeKey, serializeKey } from "./util/key-storage.js";
-import { makeStoreKeyValue } from "./util/makeStoreKeyValue.js";
import {
Sqlite3Database,
Sqlite3Interface,
Sqlite3Statement,
} from "./sqlite3-interface.js";
+import { ConstraintError, DataError } from "./util/errors.js";
+import { getIndexKeys } from "./util/getIndexKeys.js";
+import { deserializeKey, serializeKey } from "./util/key-storage.js";
+import { makeStoreKeyValue } from "./util/makeStoreKeyValue.js";
function assertDbInvariant(b: boolean): asserts b {
if (!b) {
@@ -1927,6 +1927,13 @@ export class SqliteBackend implements Backend {
});
}
}
+
+ async backupToFile(path: string): Promise<void> {
+ const stmt = this._prep("VACUUM INTO $filename;");
+ stmt.run({
+ filename: path,
+ });
+ }
}
const schemaSql = `
diff --git a/packages/taler-harness/src/bench1.ts b/packages/taler-harness/src/bench1.ts
index d260ea731..169e9150a 100644
--- a/packages/taler-harness/src/bench1.ts
+++ b/packages/taler-harness/src/bench1.ts
@@ -28,7 +28,6 @@ import {
Logger,
} from "@gnu-taler/taler-util";
import {
- AccessStats,
createNativeWalletHost2,
Wallet,
WalletApiOperation,
@@ -66,7 +65,6 @@ export async function runBench1(configJson: any): Promise<void> {
}
let wallet = {} as Wallet;
- let getDbStats: () => AccessStats;
for (let i = 0; i < numIter; i++) {
// Create a new wallet in each iteration
@@ -75,7 +73,11 @@ export async function runBench1(configJson: any): Promise<void> {
if (i % restartWallet == 0) {
if (Object.keys(wallet).length !== 0) {
await wallet.client.call(WalletApiOperation.Shutdown, {});
- console.log("wallet DB stats", j2s(getDbStats!()));
+ const stats = wallet.client.call(
+ WalletApiOperation.TestingGetDbStats,
+ {},
+ );
+ console.log("wallet DB stats", j2s(stats));
}
const res = await createNativeWalletHost2({
@@ -84,7 +86,6 @@ export async function runBench1(configJson: any): Promise<void> {
httpLib: harnessHttpLib,
});
wallet = res.wallet;
- getDbStats = res.getDbStats;
await wallet.client.call(WalletApiOperation.InitWallet, {
config: {
testing: {
@@ -128,7 +129,8 @@ export async function runBench1(configJson: any): Promise<void> {
}
await wallet.client.call(WalletApiOperation.Shutdown, {});
- console.log("wallet DB stats", j2s(getDbStats!()));
+ const stats = wallet.client.call(WalletApiOperation.TestingGetDbStats, {});
+ console.log("wallet DB stats", j2s(stats));
}
/**
diff --git a/packages/taler-harness/src/bench3.ts b/packages/taler-harness/src/bench3.ts
index ddf763c5b..e33b0c356 100644
--- a/packages/taler-harness/src/bench3.ts
+++ b/packages/taler-harness/src/bench3.ts
@@ -28,7 +28,6 @@ import {
} from "@gnu-taler/taler-util";
import { createPlatformHttpLib } from "@gnu-taler/taler-util/http";
import {
- AccessStats,
createNativeWalletHost2,
Wallet,
WalletApiOperation,
@@ -77,7 +76,6 @@ export async function runBench3(configJson: any): Promise<void> {
logger.info("not trusting exchange (validating signatures)");
}
let wallet = {} as Wallet;
- let getDbStats: () => AccessStats;
for (let i = 0; i < numIter; i++) {
// Create a new wallet in each iteration
@@ -86,7 +84,11 @@ export async function runBench3(configJson: any): Promise<void> {
if (i % restartWallet == 0) {
if (Object.keys(wallet).length !== 0) {
await wallet.client.call(WalletApiOperation.Shutdown, {});
- console.log("wallet DB stats", j2s(getDbStats!()));
+ const stats = wallet.client.call(
+ WalletApiOperation.TestingGetDbStats,
+ {},
+ );
+ console.log("wallet DB stats", j2s(stats));
}
const res = await createNativeWalletHost2({
@@ -95,7 +97,6 @@ export async function runBench3(configJson: any): Promise<void> {
httpLib: myHttpLib,
});
wallet = res.wallet;
- getDbStats = res.getDbStats;
await wallet.client.call(WalletApiOperation.InitWallet, {
config: {
features: {},
@@ -140,7 +141,8 @@ export async function runBench3(configJson: any): Promise<void> {
}
await wallet.client.call(WalletApiOperation.Shutdown, {});
- console.log("wallet DB stats", j2s(getDbStats!()));
+ const stats = wallet.client.call(WalletApiOperation.TestingGetDbStats, {});
+ console.log("wallet DB stats", j2s(stats));
}
/**
diff --git a/packages/taler-util/src/types-taler-wallet.ts b/packages/taler-util/src/types-taler-wallet.ts
index 8a4de2b32..cbab53911 100644
--- a/packages/taler-util/src/types-taler-wallet.ts
+++ b/packages/taler-util/src/types-taler-wallet.ts
@@ -3582,3 +3582,31 @@ export const codecForStartExchangeWalletKycRequest =
.property("exchangeBaseUrl", codecForString())
.property("amount", codecForAmountString())
.build("StartExchangeWalletKycRequest");
+
+export interface ExportDbToFileRequest {
+ /**
+ * Directory that the DB should be exported into.
+ */
+ directory: string;
+
+ /**
+ * Stem of the exported DB filename.
+ *
+ * The final name will be ${directory}/${stem}.${extension},
+ * where the extension depends on the used DB backend.
+ */
+ stem: string;
+}
+
+export const codecForExportDbToFileRequest = (): Codec<ExportDbToFileRequest> =>
+ buildCodecForObject<ExportDbToFileRequest>()
+ .property("directory", codecForString())
+ .property("stem", codecForString())
+ .build("ExportDbToFileRequest");
+
+export interface ExportDbToFileResponse {
+ /**
+ * Full path to the backup.
+ */
+ path: string;
+}
diff --git a/packages/taler-wallet-cli/src/index.ts b/packages/taler-wallet-cli/src/index.ts
index 73276c06c..e306f3225 100644
--- a/packages/taler-wallet-cli/src/index.ts
+++ b/packages/taler-wallet-cli/src/index.ts
@@ -249,7 +249,6 @@ export interface WalletContext {
interface CreateWalletResult {
wallet: Wallet;
- getStats: () => AccessStats;
}
async function createLocalWallet(
@@ -275,7 +274,7 @@ async function createLocalWallet(
});
applyVerbose(walletCliArgs.wallet.verbose);
- const res = { wallet: wh.wallet, getStats: wh.getDbStats };
+ const res = { wallet: wh.wallet };
if (args.noInit) {
return res;
@@ -379,7 +378,8 @@ async function withWallet<T>(
await wh.wallet.client.call(WalletApiOperation.Shutdown, {});
if (process.env.TALER_WALLET_DBSTATS) {
console.log("database stats:");
- console.log(j2s(wh.getStats()));
+ const stats = await wh.wallet.client.call(WalletApiOperation.TestingGetDbStats, {});
+ console.log(j2s(stats));
}
return result;
}
diff --git a/packages/taler-wallet-core/src/host-impl.missing.ts b/packages/taler-wallet-core/src/host-impl.missing.ts
index 464a5af15..e03df2d8e 100644
--- a/packages/taler-wallet-core/src/host-impl.missing.ts
+++ b/packages/taler-wallet-core/src/host-impl.missing.ts
@@ -35,7 +35,6 @@ export async function createNativeWalletHost2(
args: DefaultNodeWalletArgs = {},
): Promise<{
wallet: Wallet;
- getDbStats: () => AccessStats;
}> {
throw Error("not implemented");
}
diff --git a/packages/taler-wallet-core/src/host-impl.node.ts b/packages/taler-wallet-core/src/host-impl.node.ts
index eb4191f81..7a6fc458e 100644
--- a/packages/taler-wallet-core/src/host-impl.node.ts
+++ b/packages/taler-wallet-core/src/host-impl.node.ts
@@ -22,10 +22,8 @@
/**
* Imports.
*/
-import type { IDBFactory } from "@gnu-taler/idb-bridge";
// eslint-disable-next-line no-duplicate-imports
import {
- AccessStats,
BridgeIDBFactory,
MemoryBackend,
createSqliteBackend,
@@ -46,18 +44,13 @@ import {
getSqlite3FilenameFromStoragePath,
makeTempfileId,
} from "./host-common.js";
-import { Wallet } from "./wallet.js";
+import { Wallet, WalletDatabaseImplementation } from "./wallet.js";
const logger = new Logger("host-impl.node.ts");
-interface MakeDbResult {
- idbFactory: BridgeIDBFactory;
- getStats: () => AccessStats;
-}
-
async function makeFileDb(
args: DefaultNodeWalletArgs = {},
-): Promise<MakeDbResult> {
+): Promise<WalletDatabaseImplementation> {
const myBackend = new MemoryBackend();
myBackend.enableTracing = false;
const storagePath = args.persistentStoragePath;
@@ -106,12 +99,15 @@ async function makeFileDb(
return {
idbFactory: myBridgeIdbFactory,
getStats: () => myBackend.accessStats,
+ exportToFile(directory, stem) {
+ throw Error("not supported");
+ },
};
}
async function makeSqliteDb(
args: DefaultNodeWalletArgs,
-): Promise<MakeDbResult> {
+): Promise<WalletDatabaseImplementation> {
if (process.env.TALER_WALLET_DBTRACING) {
BridgeIDBFactory.enableTracing = true;
} else {
@@ -138,6 +134,13 @@ async function makeSqliteDb(
getStats() {
return myBackend.accessStats;
},
+ async exportToFile(directory, stem) {
+ const path = `${directory}/${stem}.sqlite3`;
+ myBackend.backupToFile(path);
+ return {
+ path,
+ };
+ },
idbFactory: myBridgeIdbFactory,
};
}
@@ -151,7 +154,6 @@ export async function createNativeWalletHost2(
args: DefaultNodeWalletArgs = {},
): Promise<{
wallet: Wallet;
- getDbStats: () => AccessStats;
}> {
const myHttpFactory = (config: WalletRunConfig) => {
let myHttpLib;
@@ -166,7 +168,7 @@ export async function createNativeWalletHost2(
return myHttpLib;
};
- let dbResp: MakeDbResult;
+ let dbResp: WalletDatabaseImplementation;
if (
args.persistentStoragePath &&
@@ -179,8 +181,6 @@ export async function createNativeWalletHost2(
dbResp = await makeSqliteDb(args);
}
- const myIdbFactory: IDBFactory = dbResp.idbFactory as any as IDBFactory;
-
shimIndexedDB(dbResp.idbFactory);
let workerFactory;
@@ -209,18 +209,12 @@ export async function createNativeWalletHost2(
const timer = new SetTimeoutTimerAPI();
- const w = await Wallet.create(
- myIdbFactory,
- myHttpFactory,
- timer,
- workerFactory,
- );
+ const w = await Wallet.create(dbResp, myHttpFactory, timer, workerFactory);
if (args.notifyHandler) {
w.addNotificationListener(args.notifyHandler);
}
return {
wallet: w,
- getDbStats: dbResp.getStats,
};
}
diff --git a/packages/taler-wallet-core/src/host-impl.qtart.ts b/packages/taler-wallet-core/src/host-impl.qtart.ts
index b4ea04be5..8858087ab 100644
--- a/packages/taler-wallet-core/src/host-impl.qtart.ts
+++ b/packages/taler-wallet-core/src/host-impl.qtart.ts
@@ -23,7 +23,6 @@
* Imports.
*/
import type {
- IDBFactory,
ResultRow,
Sqlite3Interface,
Sqlite3Statement,
@@ -50,7 +49,7 @@ import {
getSqlite3FilenameFromStoragePath,
makeTempfileId,
} from "./host-common.js";
-import { Wallet } from "./wallet.js";
+import { Wallet, WalletDatabaseImplementation } from "./wallet.js";
const logger = new Logger("host-impl.qtart.ts");
@@ -103,7 +102,7 @@ export async function createQtartSqlite3Impl(): Promise<Sqlite3Interface> {
async function makeSqliteDb(
args: DefaultNodeWalletArgs,
-): Promise<MakeDbResult> {
+): Promise<WalletDatabaseImplementation> {
BridgeIDBFactory.enableTracing = false;
const filename = getSqlite3FilenameFromStoragePath(
args.persistentStoragePath,
@@ -123,13 +122,20 @@ async function makeSqliteDb(
primitiveStatements: numStmt,
};
},
+ async exportToFile(directory, stem) {
+ const path = `${directory}/${stem}.sqlite3`;
+ myBackend.backupToFile(path);
+ return {
+ path,
+ };
+ },
idbFactory: myBridgeIdbFactory,
};
}
async function makeFileDb(
args: DefaultNodeWalletArgs = {},
-): Promise<MakeDbResult> {
+): Promise<WalletDatabaseImplementation> {
BridgeIDBFactory.enableTracing = false;
const myBackend = new MemoryBackend();
myBackend.enableTracing = false;
@@ -165,6 +171,9 @@ async function makeFileDb(
return {
idbFactory: myBridgeIdbFactory,
getStats: () => myBackend.accessStats,
+ exportToFile(directory, stem) {
+ throw Error("not supported");
+ },
};
}
@@ -172,11 +181,10 @@ export async function createNativeWalletHost2(
args: DefaultNodeWalletArgs = {},
): Promise<{
wallet: Wallet;
- getDbStats: () => AccessStats;
}> {
BridgeIDBFactory.enableTracing = false;
- let dbResp: MakeDbResult;
+ let dbResp: WalletDatabaseImplementation;
if (
args.persistentStoragePath &&
@@ -189,8 +197,6 @@ export async function createNativeWalletHost2(
dbResp = await makeSqliteDb(args);
}
- const myIdbFactory: IDBFactory = dbResp.idbFactory as any as IDBFactory;
-
shimIndexedDB(dbResp.idbFactory);
const myHttpFactory = (config: WalletRunConfig) => {
@@ -211,18 +217,12 @@ export async function createNativeWalletHost2(
const timer = new SetTimeoutTimerAPI();
- const w = await Wallet.create(
- myIdbFactory,
- myHttpFactory,
- timer,
- workerFactory,
- );
+ const w = await Wallet.create(dbResp, myHttpFactory, timer, workerFactory);
if (args.notifyHandler) {
w.addNotificationListener(args.notifyHandler);
}
return {
wallet: w,
- getDbStats: dbResp.getStats,
};
}
diff --git a/packages/taler-wallet-core/src/host.ts b/packages/taler-wallet-core/src/host.ts
index feccf42a6..ed1377d56 100644
--- a/packages/taler-wallet-core/src/host.ts
+++ b/packages/taler-wallet-core/src/host.ts
@@ -14,10 +14,9 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
+import * as hostImpl from "#host-impl";
import { DefaultNodeWalletArgs } from "./host-common.js";
import { Wallet } from "./index.js";
-import * as hostImpl from "#host-impl";
-import { AccessStats } from "@gnu-taler/idb-bridge";
/**
* Helpers to initiate a wallet in a host environment.
@@ -30,7 +29,6 @@ export async function createNativeWalletHost2(
args: DefaultNodeWalletArgs = {},
): Promise<{
wallet: Wallet;
- getDbStats: () => AccessStats;
}> {
return hostImpl.createNativeWalletHost2(args);
}
diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts b/packages/taler-wallet-core/src/wallet-api-types.ts
index 79d918018..609a23d1e 100644
--- a/packages/taler-wallet-core/src/wallet-api-types.ts
+++ b/packages/taler-wallet-core/src/wallet-api-types.ts
@@ -66,6 +66,8 @@ import {
EmptyObject,
ExchangeDetailedResponse,
ExchangesListResponse,
+ ExportDbToFileRequest,
+ ExportDbToFileResponse,
FailTransactionRequest,
ForceRefreshRequest,
ForgetKnownBankAccountsRequest,
@@ -241,6 +243,7 @@ export enum WalletApiOperation {
SetWalletDeviceId = "setWalletDeviceId",
ImportDb = "importDb",
ExportDb = "exportDb",
+ ExportDbToFile = "exportDbToFile",
PreparePeerPushCredit = "preparePeerPushCredit",
CheckPeerPushDebit = "checkPeerPushDebit",
InitiatePeerPushDebit = "initiatePeerPushDebit",
@@ -280,6 +283,7 @@ export enum WalletApiOperation {
TestingWaitTransactionState = "testingWaitTransactionState",
TestingWaitExchangeState = "testingWaitExchangeState",
TestingWaitTasksDone = "testingWaitTasksDone",
+ TestingGetDbStats = "testingGetDbStats",
TestingSetTimetravel = "testingSetTimetravel",
TestingGetDenomStats = "testingGetDenomStats",
TestingPing = "testingPing",
@@ -871,6 +875,17 @@ export type ExportBackupOp = {
};
/**
+ * Export the database to a file.
+ *
+ * The target directory must already exist.
+ */
+export type ExportDbToFileOp = {
+ op: WalletApiOperation.ExportDbToFile;
+ request: ExportDbToFileRequest;
+ response: ExportDbToFileResponse;
+};
+
+/**
* Add a new backup provider.
*/
export type AddBackupProviderOp = {
@@ -1189,6 +1204,15 @@ export type TestingSetTimetravelOp = {
};
/**
+ * Add an offset to the wallet's internal time.
+ */
+export type TestingGetDbStats = {
+ op: WalletApiOperation.TestingSetTimetravel;
+ request: EmptyObject;
+ response: any;
+};
+
+/**
* Wait until all transactions are in a final state.
*/
export type TestingWaitTransactionsFinalOp = {
@@ -1343,6 +1367,7 @@ export type WalletOperations = {
[WalletApiOperation.ImportBackupRecovery]: ImportBackupRecoveryOp;
[WalletApiOperation.RunBackupCycle]: RunBackupCycleOp;
[WalletApiOperation.ExportBackup]: ExportBackupOp;
+ [WalletApiOperation.ExportDbToFile]: ExportDbToFileOp;
[WalletApiOperation.AddBackupProvider]: AddBackupProviderOp;
[WalletApiOperation.RemoveBackupProvider]: RemoveBackupProviderOp;
[WalletApiOperation.GetBackupInfo]: GetBackupInfoOp;
@@ -1368,6 +1393,7 @@ export type WalletOperations = {
[WalletApiOperation.TestingWaitTransactionsFinal]: TestingWaitTransactionsFinalOp;
[WalletApiOperation.TestingWaitRefreshesFinal]: TestingWaitRefreshesFinalOp;
[WalletApiOperation.TestingSetTimetravel]: TestingSetTimetravelOp;
+ [WalletApiOperation.TestingGetDbStats]: TestingGetDbStats;
[WalletApiOperation.TestingWaitTransactionState]: TestingWaitTransactionStateOp;
[WalletApiOperation.TestingWaitExchangeState]: TestingWaitExchangeStateOp;
[WalletApiOperation.TestingWaitTasksDone]: TestingWaitTasksDoneOp;
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
index cdc066d85..1a70685c7 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -22,7 +22,11 @@
/**
* Imports.
*/
-import { IDBDatabase, IDBFactory } from "@gnu-taler/idb-bridge";
+import {
+ AccessStats,
+ BridgeIDBFactory,
+ IDBDatabase,
+} from "@gnu-taler/idb-bridge";
import {
AbortTransactionRequest,
AbsoluteTime,
@@ -53,6 +57,8 @@ import {
DenominationInfo,
Duration,
EmptyObject,
+ ExportDbToFileRequest,
+ ExportDbToFileResponse,
FailTransactionRequest,
ForgetKnownBankAccountsRequest,
GetActiveTasksResponse,
@@ -144,6 +150,7 @@ import {
codecForDeleteStoredBackupRequest,
codecForDeleteTransactionRequest,
codecForEmptyObject,
+ codecForExportDbToFileRequest,
codecForFailTransactionRequest,
codecForForceRefreshRequest,
codecForForgetKnownBankAccounts,
@@ -689,8 +696,8 @@ async function getClientFromWalletState(
async function createStoredBackup(
wex: WalletExecutionContext,
): Promise<CreateStoredBackupResponse> {
- const backup = await exportDb(wex.ws.idb);
- const backupsDb = await openStoredBackupsDatabase(wex.ws.idb);
+ const backup = await exportDb(wex.ws.idbFactory);
+ const backupsDb = await openStoredBackupsDatabase(wex.ws.idbFactory);
const name = `backup-${new Date().getTime()}`;
await backupsDb.runAllStoresReadWriteTx({}, async (tx) => {
await tx.backupMeta.add({
@@ -709,7 +716,7 @@ async function listStoredBackups(
const storedBackups: StoredBackupList = {
storedBackups: [],
};
- const backupsDb = await openStoredBackupsDatabase(wex.ws.idb);
+ const backupsDb = await openStoredBackupsDatabase(wex.ws.idbFactory);
await backupsDb.runAllStoresReadWriteTx({}, async (tx) => {
await tx.backupMeta.iter().forEach((x) => {
storedBackups.storedBackups.push({
@@ -724,7 +731,7 @@ async function deleteStoredBackup(
wex: WalletExecutionContext,
req: DeleteStoredBackupRequest,
): Promise<void> {
- const backupsDb = await openStoredBackupsDatabase(wex.ws.idb);
+ const backupsDb = await openStoredBackupsDatabase(wex.ws.idbFactory);
await backupsDb.runAllStoresReadWriteTx({}, async (tx) => {
await tx.backupData.delete(req.name);
await tx.backupMeta.delete(req.name);
@@ -737,7 +744,7 @@ async function recoverStoredBackup(
): Promise<void> {
logger.info(`Recovering stored backup ${req.name}`);
const { name } = req;
- const backupsDb = await openStoredBackupsDatabase(wex.ws.idb);
+ const backupsDb = await openStoredBackupsDatabase(wex.ws.idbFactory);
const bd = await backupsDb.runAllStoresReadWriteTx({}, async (tx) => {
const backupMeta = tx.backupMeta.get(name);
if (!backupMeta) {
@@ -1443,6 +1450,19 @@ async function handleCreateStoredBackup(
return await createStoredBackup(wex);
}
+async function handleExportDbToFile(
+ wex: WalletExecutionContext,
+ req: ExportDbToFileRequest,
+): Promise<ExportDbToFileResponse> {
+ const res = await wex.ws.dbImplementation.exportToFile(
+ req.directory,
+ req.stem,
+ );
+ return {
+ path: res.path,
+ };
+}
+
async function handleAcceptBankIntegratedWithdrawal(
wex: WalletExecutionContext,
req: AcceptBankIntegratedWithdrawalRequest,
@@ -1556,6 +1576,16 @@ const handlers: { [T in WalletApiOperation]: HandlerWithValidator<T> } = {
codec: codecForAny(),
handler: handleTestingWaitExchangeState,
},
+ [WalletApiOperation.TestingGetDbStats]: {
+ codec: codecForEmptyObject(),
+ handler: async (wex) => {
+ return wex.ws.dbImplementation.getStats();
+ },
+ },
+ [WalletApiOperation.ExportDbToFile]: {
+ codec: codecForExportDbToFileRequest(),
+ handler: handleExportDbToFile,
+ },
[WalletApiOperation.HintApplicationResumed]: {
codec: codecForEmptyObject(),
handler: handleHintApplicationResumed,
@@ -1937,7 +1967,7 @@ const handlers: { [T in WalletApiOperation]: HandlerWithValidator<T> } = {
[WalletApiOperation.ExportDb]: {
codec: codecForEmptyObject(),
handler: async (wex, req) => {
- const dbDump = await exportDb(wex.ws.idb);
+ const dbDump = await exportDb(wex.ws.idbFactory);
return dbDump;
},
},
@@ -2292,6 +2322,12 @@ function applyRunConfigDefaults(wcp?: PartialWalletRunConfig): WalletRunConfig {
export type HttpFactory = (config: WalletRunConfig) => HttpRequestLibrary;
+export interface WalletDatabaseImplementation {
+ idbFactory: BridgeIDBFactory;
+ getStats: () => AccessStats;
+ exportToFile: (directory: string, stem: string) => Promise<{ path: string }>;
+}
+
/**
* Public handle to a running wallet.
*/
@@ -2300,13 +2336,13 @@ export class Wallet {
private _client: WalletCoreApiClient | undefined;
private constructor(
- idb: IDBFactory,
+ dbImplementation: WalletDatabaseImplementation,
httpFactory: HttpFactory,
timer: TimerAPI,
cryptoWorkerFactory: CryptoWorkerFactory,
) {
this.ws = new InternalWalletState(
- idb,
+ dbImplementation,
httpFactory,
timer,
cryptoWorkerFactory,
@@ -2321,12 +2357,17 @@ export class Wallet {
}
static async create(
- idb: IDBFactory,
+ dbImplementation: WalletDatabaseImplementation,
httpFactory: HttpFactory,
timer: TimerAPI,
cryptoWorkerFactory: CryptoWorkerFactory,
): Promise<Wallet> {
- const w = new Wallet(idb, httpFactory, timer, cryptoWorkerFactory);
+ const w = new Wallet(
+ dbImplementation,
+ httpFactory,
+ timer,
+ cryptoWorkerFactory,
+ );
w._client = await getClientFromWalletState(w.ws);
return w;
}
@@ -2484,6 +2525,10 @@ export class InternalWalletState {
private longpollRequestIdCounter = 1;
+ public get idbFactory(): BridgeIDBFactory {
+ return this.dbImplementation.idbFactory;
+ }
+
get db(): DbAccess<typeof WalletStoresV1> {
if (!this._dbAccessHandle) {
this._dbAccessHandle = this.createDbAccessHandle(
@@ -2616,7 +2661,7 @@ export class InternalWalletState {
}
constructor(
- public idb: IDBFactory,
+ public dbImplementation: WalletDatabaseImplementation,
private httpFactory: HttpFactory,
public timer: TimerAPI,
cryptoWorkerFactory: CryptoWorkerFactory,
@@ -2634,7 +2679,7 @@ export class InternalWalletState {
logger.info("version change requested for Taler DB");
};
try {
- const myDb = await openTalerDatabase(this.idb, myVersionChange);
+ const myDb = await openTalerDatabase(this.idbFactory, myVersionChange);
this._indexedDbHandle = myDb;
} catch (e) {
logger.error("error writing to database during initialization");
diff --git a/packages/taler-wallet-embedded/src/wallet-qjs-tests.ts b/packages/taler-wallet-embedded/src/wallet-qjs-tests.ts
index ca4eb28c0..89db976a4 100644
--- a/packages/taler-wallet-embedded/src/wallet-qjs-tests.ts
+++ b/packages/taler-wallet-embedded/src/wallet-qjs-tests.ts
@@ -91,7 +91,11 @@ export async function testWithLocal(path: string) {
await w.wallet.client.call(WalletApiOperation.TestingWaitTasksDone, {});
console.log("done with task loop");
await w.wallet.client.call(WalletApiOperation.Shutdown, {});
- console.log("DB stats:", j2s(w.getDbStats()));
+ const stats = await w.wallet.client.call(
+ WalletApiOperation.TestingGetDbStats,
+ {},
+ );
+ console.log("DB stats:", j2s(stats));
}
export async function testArgon2id() {