From 698be4c436240e97f66a66c3af23192033c818b3 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Fri, 28 Jun 2024 14:56:59 +0200 Subject: wallet-core: request handler refactoring WIP --- packages/taler-wallet-core/src/wallet.ts | 258 +++++++++++++++++++++---------- 1 file changed, 178 insertions(+), 80 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 b6167be12..c2ec17f48 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -26,6 +26,7 @@ import { IDBDatabase, IDBFactory } from "@gnu-taler/idb-bridge"; import { AbsoluteTime, ActiveTask, + AddExchangeRequest, AmountJson, AmountString, Amounts, @@ -40,7 +41,10 @@ import { ExchangesShortListResponse, GetCurrencySpecificationRequest, GetCurrencySpecificationResponse, + InitRequest, InitResponse, + IntegrationTestArgs, + IntegrationTestV2Args, KnownBankAccounts, KnownBankAccountsInfo, ListGlobalCurrencyAuditorsResponse, @@ -55,6 +59,8 @@ import { PrepareWithdrawExchangeRequest, PrepareWithdrawExchangeResponse, RecoverStoredBackupRequest, + SharePaymentRequest, + SharePaymentResult, StoredBackupList, TalerBankIntegrationHttpClient, TalerError, @@ -62,15 +68,19 @@ import { TalerProtocolTimestamp, TalerUriAction, TestingGetDenomStatsResponse, + TestingListTasksForTransactionRequest, TestingListTasksForTransactionsResponse, TestingWaitTransactionRequest, TimerAPI, TimerGroup, TransactionType, + UpdateExchangeEntryRequest, + ValidateIbanRequest, ValidateIbanResponse, WalletCoreVersion, WalletNotification, WalletRunConfig, + WithdrawTestBalanceRequest, canonicalizeBaseUrl, checkDbInvariant, codecForAbortTransaction, @@ -308,6 +318,7 @@ import { WALLET_MERCHANT_PROTOCOL_VERSION, } from "./versions.js"; import { + EmptyObject, WalletApiOperation, WalletCoreApiClient, WalletCoreResponseType, @@ -694,6 +705,158 @@ export interface PendingOperationsResponse { pendingOperations: any[]; } +async function handleRetryPendingNow( + wex: WalletExecutionContext, +): Promise { + logger.error("retryPendingNow currently not implemented"); + return {}; +} + +async function handleSharePayment( + wex: WalletExecutionContext, + req: SharePaymentRequest, +): Promise { + return await sharePayment(wex, req.merchantBaseUrl, req.orderId); +} + +async function handleDeleteStoredBackup( + wex: WalletExecutionContext, + req: DeleteStoredBackupRequest, +): Promise { + await deleteStoredBackup(wex, req); + return {}; +} + +async function handleRecoverStoredBackup( + wex: WalletExecutionContext, + req: RecoverStoredBackupRequest, +): Promise { + await recoverStoredBackup(wex, req); + return {}; +} + +async function handleSetWalletRunConfig( + wex: WalletExecutionContext, + req: InitRequest, +) { + if (logger.shouldLogTrace()) { + const initType = wex.ws.initCalled + ? "repeat initialization" + : "first initialization"; + logger.trace(`init request (${initType}): ${j2s(req)}`); + } + + // Write to the DB to make sure that we're failing early in + // case the DB is not writeable. + try { + await wex.db.runReadWriteTx({ storeNames: ["config"] }, async (tx) => { + tx.config.put({ + key: ConfigRecordKey.LastInitInfo, + value: timestampProtocolToDb(TalerProtocolTimestamp.now()), + }); + }); + } catch (e) { + logger.error("error writing to database during initialization"); + throw TalerError.fromDetail(TalerErrorCode.WALLET_DB_UNAVAILABLE, { + innerError: getErrorDetailFromException(e), + }); + } + wex.ws.initWithConfig(applyRunConfigDefaults(req.config)); + + if (wex.ws.config.testing.skipDefaults) { + logger.trace("skipping defaults"); + } else { + logger.trace("filling defaults"); + await fillDefaults(wex); + } + const resp: InitResponse = { + versionInfo: handleGetVersion(wex), + }; + + if (req.config?.lazyTaskLoop) { + logger.trace("lazily starting task loop"); + } else { + await wex.taskScheduler.ensureRunning(); + } + + wex.ws.initCalled = true; + return resp; +} + +async function handleWithdrawTestkudos(wex: WalletExecutionContext) { + await withdrawTestBalance(wex, { + amount: "TESTKUDOS:10" as AmountString, + corebankApiBaseUrl: "https://bank.test.taler.net/", + exchangeBaseUrl: "https://exchange.test.taler.net/", + }); + // FIXME: Is this correct? + return { + versionInfo: handleGetVersion(wex), + }; +} + +async function handleWithdrawTestBalance( + wex: WalletExecutionContext, + req: WithdrawTestBalanceRequest, +): Promise { + await withdrawTestBalance(wex, req); + return {}; +} + +async function handleTestingListTasksForTransaction( + wex: WalletExecutionContext, + req: TestingListTasksForTransactionRequest, +): Promise { + return { + taskIdList: listTaskForTransactionId(req.transactionId), + }; +} + +async function handleRunIntegrationTest( + wex: WalletExecutionContext, + req: IntegrationTestArgs, +): Promise { + await runIntegrationTest(wex, req); + return {}; +} + +async function handleRunIntegrationTestV2( + wex: WalletExecutionContext, + req: IntegrationTestV2Args, +): Promise { + await runIntegrationTest2(wex, req); + return {}; +} + +async function handleValidateIban( + wex: WalletExecutionContext, + req: ValidateIbanRequest, +): Promise { + const valRes = validateIban(req.iban); + const resp: ValidateIbanResponse = { + valid: valRes.type === "valid", + }; + return resp; +} + +async function handleAddExchange( + wex: WalletExecutionContext, + req: AddExchangeRequest, +): Promise { + await fetchFreshExchange(wex, req.exchangeBaseUrl, {}); + return {}; +} + +async function handleUpdateExchangeEntry( + wex: WalletExecutionContext, + req: UpdateExchangeEntryRequest, +): Promise { + await fetchFreshExchange(wex, req.exchangeBaseUrl, { + forceUpdate: !!req.force, + }); + return {}; +} + /** * Implementation of the "wallet-core" API. */ @@ -712,105 +875,45 @@ async function dispatchRequestInternal( // definitions we already have? switch (operation) { case WalletApiOperation.CreateStoredBackup: - return createStoredBackup(wex); + return await createStoredBackup(wex); case WalletApiOperation.DeleteStoredBackup: { const req = codecForDeleteStoredBackupRequest().decode(payload); - await deleteStoredBackup(wex, req); - return {}; + return await handleDeleteStoredBackup(wex, req); } case WalletApiOperation.ListStoredBackups: return listStoredBackups(wex); case WalletApiOperation.RecoverStoredBackup: { const req = codecForRecoverStoredBackupRequest().decode(payload); - await recoverStoredBackup(wex, req); - return {}; + return await handleRecoverStoredBackup(wex, req); } case WalletApiOperation.SetWalletRunConfig: case WalletApiOperation.InitWallet: { const req = codecForInitRequest().decode(payload); - - if (logger.shouldLogTrace()) { - const initType = wex.ws.initCalled - ? "repeat initialization" - : "first initialization"; - logger.trace(`init request (${initType}): ${j2s(req)}`); - } - - // Write to the DB to make sure that we're failing early in - // case the DB is not writeable. - try { - await wex.db.runReadWriteTx({ storeNames: ["config"] }, async (tx) => { - tx.config.put({ - key: ConfigRecordKey.LastInitInfo, - value: timestampProtocolToDb(TalerProtocolTimestamp.now()), - }); - }); - } catch (e) { - logger.error("error writing to database during initialization"); - throw TalerError.fromDetail(TalerErrorCode.WALLET_DB_UNAVAILABLE, { - innerError: getErrorDetailFromException(e), - }); - } - wex.ws.initWithConfig(applyRunConfigDefaults(req.config)); - - if (wex.ws.config.testing.skipDefaults) { - logger.trace("skipping defaults"); - } else { - logger.trace("filling defaults"); - await fillDefaults(wex); - } - const resp: InitResponse = { - versionInfo: handleGetVersion(wex), - }; - - if (req.config?.lazyTaskLoop) { - logger.trace("lazily starting task loop"); - } else { - await wex.taskScheduler.ensureRunning(); - } - - wex.ws.initCalled = true; - return resp; + return await handleSetWalletRunConfig(wex, req); } case WalletApiOperation.WithdrawTestkudos: { - await withdrawTestBalance(wex, { - amount: "TESTKUDOS:10" as AmountString, - corebankApiBaseUrl: "https://bank.test.taler.net/", - exchangeBaseUrl: "https://exchange.test.taler.net/", - }); - return { - versionInfo: handleGetVersion(wex), - }; + return await handleWithdrawTestkudos(wex); } case WalletApiOperation.WithdrawTestBalance: { const req = codecForWithdrawTestBalance().decode(payload); - await withdrawTestBalance(wex, req); - return {}; + return await handleWithdrawTestBalance(wex, req); } case WalletApiOperation.TestingListTaskForTransaction: { const req = codecForTestingListTasksForTransactionRequest().decode(payload); - return { - taskIdList: listTaskForTransactionId(req.transactionId), - } satisfies TestingListTasksForTransactionsResponse; + return await handleTestingListTasksForTransaction(wex, req); } case WalletApiOperation.RunIntegrationTest: { const req = codecForIntegrationTestArgs().decode(payload); - await runIntegrationTest(wex, req); - return {}; + return await handleRunIntegrationTest(wex, req); } case WalletApiOperation.RunIntegrationTestV2: { const req = codecForIntegrationTestV2Args().decode(payload); - await runIntegrationTest2(wex, req); - return {}; + return await handleRunIntegrationTestV2(wex, req); } case WalletApiOperation.ValidateIban: { const req = codecForValidateIbanRequest().decode(payload); - const valRes = validateIban(req.iban); - const resp: ValidateIbanResponse = { - valid: valRes.type === "valid", - }; - return resp; + return handleValidateIban(wex, req); } case WalletApiOperation.TestPay: { const req = codecForTestPayArgs().decode(payload); @@ -830,18 +933,14 @@ async function dispatchRequestInternal( } case WalletApiOperation.AddExchange: { const req = codecForAddExchangeRequest().decode(payload); - await fetchFreshExchange(wex, req.exchangeBaseUrl, {}); - return {}; + return await handleAddExchange(wex, req); } case WalletApiOperation.TestingPing: { return {}; } case WalletApiOperation.UpdateExchangeEntry: { const req = codecForUpdateExchangeEntryRequest().decode(payload); - await fetchFreshExchange(wex, req.exchangeBaseUrl, { - forceUpdate: !!req.force, - }); - return {}; + return await handleUpdateExchangeEntry(wex, req); } case WalletApiOperation.TestingGetDenomStats: { const req = codecForTestingGetDenomStatsRequest().decode(payload); @@ -1042,16 +1141,15 @@ async function dispatchRequestInternal( throw Error("transactionId missing"); } case WalletApiOperation.RetryPendingNow: { - logger.error("retryPendingNow currently not implemented"); - return {}; + return handleRetryPendingNow(wex); } case WalletApiOperation.SharePayment: { const req = codecForSharePaymentRequest().decode(payload); - return await sharePayment(wex, req.merchantBaseUrl, req.orderId); + return await handleSharePayment(wex, req); } case WalletApiOperation.PrepareWithdrawExchange: { const req = codecForPrepareWithdrawExchangeRequest().decode(payload); - return handlePrepareWithdrawExchange(wex, req); + return await handlePrepareWithdrawExchange(wex, req); } case WalletApiOperation.CheckPayForTemplate: { const req = codecForCheckPayTemplateRequest().decode(payload); -- cgit v1.2.3