From 277a5c641df336d8b5b2d9bd6559e45f0b02aa79 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 29 Feb 2024 18:37:13 +0100 Subject: wallet-core: improve config handling, test builtin exchange config --- packages/taler-wallet-core/src/wallet.ts | 133 ++++++++++++++++++++----------- 1 file changed, 87 insertions(+), 46 deletions(-) (limited to 'packages/taler-wallet-core/src/wallet.ts') diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index 0dc066730..b397c43d5 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -47,6 +47,7 @@ import { ObservabilityContext, ObservabilityEventType, OpenedPromise, + PartialWalletRunConfig, PrepareWithdrawExchangeRequest, PrepareWithdrawExchangeResponse, RecoverStoredBackupRequest, @@ -64,6 +65,7 @@ import { ValidateIbanResponse, WalletCoreVersion, WalletNotification, + WalletRunConfig, WithdrawalDetailsForAmount, checkDbInvariant, codecForAbortTransaction, @@ -99,6 +101,7 @@ import { codecForGetWithdrawalDetailsForAmountRequest, codecForGetWithdrawalDetailsForUri, codecForImportDbRequest, + codecForInitRequest, codecForInitiatePeerPullPaymentRequest, codecForInitiatePeerPushDebitRequest, codecForIntegrationTestArgs, @@ -277,8 +280,6 @@ import { } from "./versions.js"; import { WalletApiOperation, - WalletConfig, - WalletConfigParameter, WalletCoreApiClient, WalletCoreResponseType, } from "./wallet-api-types.js"; @@ -685,6 +686,17 @@ async function dispatchRequestInternal( return {}; } case WalletApiOperation.InitWallet: { + const req = codecForInitRequest().decode(payload); + + logger.info(`init request: ${req}`); + + if (wex.ws.initCalled) { + logger.warn( + "initWallet called twice, new run configuration is ignored", + ); + return; + } + logger.trace("initializing wallet"); // Write to the DB to make sure that we're failing early in // case the DB is not writeable. @@ -701,6 +713,9 @@ async function dispatchRequestInternal( innerError: getErrorDetailFromException(e), }); } + + wex.ws.initWithConfig(applyRunConfigDefaults(req.config)); + wex.ws.initCalled = true; if (wex.ws.config.testing.skipDefaults) { logger.trace("skipping defaults"); @@ -1437,7 +1452,12 @@ export function getNormalWalletExecutionContext( cancellationToken, cryptoApi: ws.cryptoApi, db: ws.db, - http: ws.http, + get http() { + if (ws.initCalled) { + return ws.http; + } + throw Error("wallet not initialized"); + }, taskScheduler: ws.taskScheduler, oc, }; @@ -1456,7 +1476,7 @@ async function handleCoreApiRequest( let wex: WalletExecutionContext; let oc: ObservabilityContext; - if (ws.config.testing.emitObservabilityEvents) { + if (ws.initCalled && ws.config.testing.emitObservabilityEvents) { oc = { observe(evt) { ws.notify({ @@ -1512,6 +1532,34 @@ async function handleCoreApiRequest( } } +export function applyRunConfigDefaults( + wcp?: PartialWalletRunConfig, +): WalletRunConfig { + return { + builtin: { + exchanges: wcp?.builtin?.exchanges ?? [ + { + exchangeBaseUrl: "https://exchange.demo.taler.net/", + currencyHint: "KUDOS", + }, + ], + }, + features: { + allowHttp: wcp?.features?.allowHttp ?? false, + }, + testing: { + denomselAllowLate: wcp?.testing?.denomselAllowLate ?? false, + devModeActive: wcp?.testing?.devModeActive ?? false, + insecureTrustExchange: wcp?.testing?.insecureTrustExchange ?? false, + preventThrottling: wcp?.testing?.preventThrottling ?? false, + skipDefaults: wcp?.testing?.skipDefaults ?? false, + emitObservabilityEvents: wcp?.testing?.emitObservabilityEvents ?? false, + }, + }; +} + +export type HttpFactory = (config: WalletRunConfig) => HttpRequestLibrary; + /** * Public handle to a running wallet. */ @@ -1521,17 +1569,15 @@ export class Wallet { private constructor( idb: IDBFactory, - http: HttpRequestLibrary, + httpFactory: HttpFactory, timer: TimerAPI, cryptoWorkerFactory: CryptoWorkerFactory, - config?: WalletConfigParameter, ) { this.ws = new InternalWalletState( idb, - http, + httpFactory, timer, cryptoWorkerFactory, - Wallet.getEffectiveConfig(config), ); } @@ -1544,44 +1590,15 @@ export class Wallet { static async create( idb: IDBFactory, - http: HttpRequestLibrary, + httpFactory: HttpFactory, timer: TimerAPI, cryptoWorkerFactory: CryptoWorkerFactory, - config?: WalletConfigParameter, ): Promise { - const w = new Wallet(idb, http, timer, cryptoWorkerFactory, config); + const w = new Wallet(idb, httpFactory, timer, cryptoWorkerFactory); w._client = await getClientFromWalletState(w.ws); return w; } - public static defaultConfig: Readonly = { - builtin: { - exchanges: [ - { - exchangeBaseUrl: "https://exchange.demo.taler.net/", - currencyHint: "KUDOS", - }, - ], - }, - features: { - allowHttp: false, - }, - testing: { - preventThrottling: false, - devModeActive: false, - insecureTrustExchange: false, - denomselAllowLate: false, - skipDefaults: false, - emitObservabilityEvents: false, - }, - }; - - static getEffectiveConfig( - param?: WalletConfigParameter, - ): Readonly { - return deepMerge(Wallet.defaultConfig, param ?? {}); - } - addNotificationListener(f: (n: WalletNotification) => void): CancelFn { return this.ws.addNotificationListener(f); } @@ -1637,10 +1654,12 @@ export class InternalWalletState { taskScheduler: TaskScheduler = new TaskSchedulerImpl(this); - config: Readonly; + private _config: Readonly | undefined; private _db: DbAccess | undefined = undefined; + private _http: HttpRequestLibrary | undefined = undefined; + get db(): DbAccess { if (!this._db) { throw Error("db not initialized"); @@ -1648,20 +1667,42 @@ export class InternalWalletState { return this._db; } + initWithConfig(newConfig: WalletRunConfig): void { + if (this._config) { + throw Error("config already set"); + } + this._config = newConfig; + + this._http = this.httpFactory(newConfig); + + if (this.config.testing.devModeActive) { + this._http = new DevExperimentHttpLib(this.http); + } + } + + get config(): WalletRunConfig { + if (!this._config) { + throw Error("config not initialized"); + } + return this._config; + } + + get http(): HttpRequestLibrary { + if (!this._http) { + throw Error("wallet not initialized"); + } + return this._http; + } + constructor( public idb: IDBFactory, - public http: HttpRequestLibrary, + private httpFactory: HttpFactory, public timer: TimerAPI, cryptoWorkerFactory: CryptoWorkerFactory, - configParam: WalletConfig, ) { this.cryptoDispatcher = new CryptoDispatcher(cryptoWorkerFactory); this.cryptoApi = this.cryptoDispatcher.cryptoApi; this.timerGroup = new TimerGroup(timer); - this.config = configParam; - if (this.config.testing.devModeActive) { - this.http = new DevExperimentHttpLib(this.http); - } } async ensureWalletDbOpen(): Promise { -- cgit v1.2.3