diff options
author | Florian Dold <florian@dold.me> | 2024-11-06 14:35:11 +0100 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2024-11-06 14:35:11 +0100 |
commit | 5c1bcc68baed6593ca107ac4d6f5f2b850a7b688 (patch) | |
tree | 58bcd0745e6d29757107f2f6a4de7d90787f72d6 | |
parent | 2689781c2086a40f1252e7a8a4acb263074ed7ac (diff) |
wallet-core: implement exporting DB to file
-rw-r--r-- | packages/idb-bridge/src/SqliteBackend.ts | 15 | ||||
-rw-r--r-- | packages/taler-harness/src/bench1.ts | 12 | ||||
-rw-r--r-- | packages/taler-harness/src/bench3.ts | 12 | ||||
-rw-r--r-- | packages/taler-util/src/types-taler-wallet.ts | 28 | ||||
-rw-r--r-- | packages/taler-wallet-cli/src/index.ts | 6 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/host-impl.missing.ts | 1 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/host-impl.node.ts | 36 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/host-impl.qtart.ts | 30 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/host.ts | 4 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/wallet-api-types.ts | 26 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/wallet.ts | 71 | ||||
-rw-r--r-- | packages/taler-wallet-embedded/src/wallet-qjs-tests.ts | 6 |
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() { |