aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2024-06-30 22:10:39 +0200
committerFlorian Dold <florian@dold.me>2024-06-30 22:10:39 +0200
commitaff3c5c19d1c08f96037faa80446a27c641e0219 (patch)
tree74a31e39d541cfa3819ac4e2e02731e30cb84b06 /packages/taler-wallet-core
parentc297b5130cb7e9ceba4602548d9ccb68735d55e5 (diff)
downloadwallet-core-aff3c5c19d1c08f96037faa80446a27c641e0219.tar.xz
wallet-core: request handler refactoring WIP
Diffstat (limited to 'packages/taler-wallet-core')
-rw-r--r--packages/taler-wallet-core/src/wallet-api-types.ts5
-rw-r--r--packages/taler-wallet-core/src/wallet.ts432
2 files changed, 272 insertions, 165 deletions
diff --git a/packages/taler-wallet-core/src/wallet-api-types.ts b/packages/taler-wallet-core/src/wallet-api-types.ts
index c1943daa1..12abb6469 100644
--- a/packages/taler-wallet-core/src/wallet-api-types.ts
+++ b/packages/taler-wallet-core/src/wallet-api-types.ts
@@ -95,6 +95,7 @@ import {
InitiatePeerPushDebitRequest,
InitiatePeerPushDebitResponse,
IntegrationTestArgs,
+ IntegrationTestV2Args,
KnownBankAccounts,
ListAssociatedRefreshesRequest,
ListAssociatedRefreshesResponse,
@@ -275,7 +276,6 @@ export enum WalletApiOperation {
TestingWaitTransactionState = "testingWaitTransactionState",
TestingWaitTasksDone = "testingWaitTasksDone",
TestingSetTimetravel = "testingSetTimetravel",
- TestingInfiniteTransactionLoop = "testingInfiniteTransactionLoop",
TestingGetDenomStats = "testingGetDenomStats",
TestingPing = "testingPing",
TestingGetReserveHistory = "testingGetReserveHistory",
@@ -1068,7 +1068,7 @@ export type RunIntegrationTestOp = {
*/
export type RunIntegrationTestV2Op = {
op: WalletApiOperation.RunIntegrationTestV2;
- request: IntegrationTestArgs;
+ request: IntegrationTestV2Args;
response: EmptyObject;
};
@@ -1344,7 +1344,6 @@ export type WalletOperations = {
[WalletApiOperation.RecoverStoredBackup]: RecoverStoredBackupsOp;
[WalletApiOperation.UpdateExchangeEntry]: UpdateExchangeEntryOp;
[WalletApiOperation.PrepareWithdrawExchange]: PrepareWithdrawExchangeOp;
- [WalletApiOperation.TestingInfiniteTransactionLoop]: any;
[WalletApiOperation.DeleteExchange]: DeleteExchangeOp;
[WalletApiOperation.GetExchangeResources]: GetExchangeResourcesOp;
[WalletApiOperation.ListGlobalCurrencyAuditors]: ListGlobalCurrencyAuditorsOp;
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
index 9e3aea137..5b3b4da29 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -26,21 +26,29 @@ import { IDBDatabase, IDBFactory } from "@gnu-taler/idb-bridge";
import {
AbortTransactionRequest,
AbsoluteTime,
+ AcceptBankIntegratedWithdrawalRequest,
AcceptManualWithdrawalRequest,
AcceptManualWithdrawalResult,
+ AcceptWithdrawalResponse,
ActiveTask,
AddExchangeRequest,
+ AddGlobalCurrencyAuditorRequest,
+ AddGlobalCurrencyExchangeRequest,
AddKnownBankAccountsRequest,
AmountJson,
AmountString,
Amounts,
CancellationToken,
+ CanonicalizeBaseUrlRequest,
+ CanonicalizeBaseUrlResponse,
+ Codec,
CoinDumpJson,
CoinStatus,
ConfirmPayRequest,
ConfirmPayResult,
CoreApiResponse,
CreateStoredBackupResponse,
+ DeleteExchangeRequest,
DeleteStoredBackupRequest,
DenominationInfo,
Duration,
@@ -78,6 +86,8 @@ import {
PrepareWithdrawExchangeRequest,
PrepareWithdrawExchangeResponse,
RecoverStoredBackupRequest,
+ RemoveGlobalCurrencyAuditorRequest,
+ RemoveGlobalCurrencyExchangeRequest,
SharePaymentRequest,
SharePaymentResult,
StartRefundQueryRequest,
@@ -91,6 +101,7 @@ import {
TestingGetDenomStatsRequest,
TestingGetDenomStatsResponse,
TestingGetReserveHistoryRequest,
+ TestingSetTimetravelRequest,
TestingWaitTransactionRequest,
TimerAPI,
TimerGroup,
@@ -174,7 +185,6 @@ import {
codecForTestPayArgs,
codecForTestingGetDenomStatsRequest,
codecForTestingGetReserveHistoryRequest,
- codecForTestingListTasksForTransactionRequest,
codecForTestingSetTimetravelRequest,
codecForTransactionByIdRequest,
codecForTransactionsRequest,
@@ -343,6 +353,7 @@ import {
import {
WalletApiOperation,
WalletCoreApiClient,
+ WalletCoreRequestType,
WalletCoreResponseType,
} from "./wallet-api-types.js";
import {
@@ -800,9 +811,7 @@ async function handleWithdrawTestkudos(wex: WalletExecutionContext) {
exchangeBaseUrl: "https://exchange.test.taler.net/",
});
// FIXME: Is this correct?
- return {
- versionInfo: handleGetVersion(wex),
- };
+ return {};
}
async function handleWithdrawTestBalance(
@@ -1195,6 +1204,250 @@ async function handleListGlobalCurrencyExchanges(
return resp;
}
+async function handleListGlobalCurrencyAuditors(
+ wex: WalletExecutionContext,
+ req: EmptyObject,
+): Promise<ListGlobalCurrencyAuditorsResponse> {
+ const resp: ListGlobalCurrencyAuditorsResponse = {
+ auditors: [],
+ };
+ await wex.db.runReadOnlyTx(
+ { storeNames: ["globalCurrencyAuditors"] },
+ async (tx) => {
+ const gcaList = await tx.globalCurrencyAuditors.iter().toArray();
+ for (const gca of gcaList) {
+ resp.auditors.push({
+ currency: gca.currency,
+ auditorBaseUrl: gca.auditorBaseUrl,
+ auditorPub: gca.auditorPub,
+ });
+ }
+ },
+ );
+ return resp;
+}
+
+async function handleAddGlobalCurrencyExchange(
+ wex: WalletExecutionContext,
+ req: AddGlobalCurrencyExchangeRequest,
+): Promise<EmptyObject> {
+ await wex.db.runReadWriteTx(
+ { storeNames: ["globalCurrencyExchanges"] },
+ async (tx) => {
+ const key = [req.currency, req.exchangeBaseUrl, req.exchangeMasterPub];
+ const existingRec =
+ await tx.globalCurrencyExchanges.indexes.byCurrencyAndUrlAndPub.get(
+ key,
+ );
+ if (existingRec) {
+ return;
+ }
+ wex.ws.exchangeCache.clear();
+ await tx.globalCurrencyExchanges.add({
+ currency: req.currency,
+ exchangeBaseUrl: req.exchangeBaseUrl,
+ exchangeMasterPub: req.exchangeMasterPub,
+ });
+ },
+ );
+ return {};
+}
+
+async function handleRemoveGlobalCurrencyAuditor(
+ wex: WalletExecutionContext,
+ req: RemoveGlobalCurrencyAuditorRequest,
+): Promise<EmptyObject> {
+ await wex.db.runReadWriteTx(
+ { storeNames: ["globalCurrencyAuditors"] },
+ async (tx) => {
+ const key = [req.currency, req.auditorBaseUrl, req.auditorPub];
+ const existingRec =
+ await tx.globalCurrencyAuditors.indexes.byCurrencyAndUrlAndPub.get(key);
+ if (!existingRec) {
+ return;
+ }
+ checkDbInvariant(!!existingRec.id, `no global currency for ${j2s(key)}`);
+ await tx.globalCurrencyAuditors.delete(existingRec.id);
+ wex.ws.exchangeCache.clear();
+ },
+ );
+ return {};
+}
+
+async function handleRemoveGlobalCurrencyExchange(
+ wex: WalletExecutionContext,
+ req: RemoveGlobalCurrencyExchangeRequest,
+): Promise<EmptyObject> {
+ await wex.db.runReadWriteTx(
+ { storeNames: ["globalCurrencyExchanges"] },
+ async (tx) => {
+ const key = [req.currency, req.exchangeBaseUrl, req.exchangeMasterPub];
+ const existingRec =
+ await tx.globalCurrencyExchanges.indexes.byCurrencyAndUrlAndPub.get(
+ key,
+ );
+ if (!existingRec) {
+ return;
+ }
+ wex.ws.exchangeCache.clear();
+ checkDbInvariant(!!existingRec.id, `no global exchange for ${j2s(key)}`);
+ await tx.globalCurrencyExchanges.delete(existingRec.id);
+ },
+ );
+ return {};
+}
+
+async function handleAddGlobalCurrencyAuditor(
+ wex: WalletExecutionContext,
+ req: AddGlobalCurrencyAuditorRequest,
+): Promise<EmptyObject> {
+ await wex.db.runReadWriteTx(
+ { storeNames: ["globalCurrencyAuditors"] },
+ async (tx) => {
+ const key = [req.currency, req.auditorBaseUrl, req.auditorPub];
+ const existingRec =
+ await tx.globalCurrencyAuditors.indexes.byCurrencyAndUrlAndPub.get(key);
+ if (existingRec) {
+ return;
+ }
+ await tx.globalCurrencyAuditors.add({
+ currency: req.currency,
+ auditorBaseUrl: req.auditorBaseUrl,
+ auditorPub: req.auditorPub,
+ });
+ wex.ws.exchangeCache.clear();
+ },
+ );
+ return {};
+}
+
+async function handleShutdown(
+ wex: WalletExecutionContext,
+ req: EmptyObject,
+): Promise<EmptyObject> {
+ wex.ws.stop();
+ return {};
+}
+
+async function handleTestingSetTimetravel(
+ wex: WalletExecutionContext,
+ req: TestingSetTimetravelRequest,
+): Promise<EmptyObject> {
+ setDangerousTimetravel(req.offsetMs);
+ await wex.taskScheduler.reload();
+ return {};
+}
+
+async function handleCanonicalizeBaseUrl(
+ wex: WalletExecutionContext,
+ req: CanonicalizeBaseUrlRequest,
+): Promise<CanonicalizeBaseUrlResponse> {
+ return {
+ url: canonicalizeBaseUrl(req.url),
+ };
+}
+
+async function handleDeleteExchange(
+ wex: WalletExecutionContext,
+ req: DeleteExchangeRequest,
+): Promise<EmptyObject> {
+ await deleteExchange(wex, req);
+ return {};
+}
+
+async function handleCreateStoredBackup(
+ wex: WalletExecutionContext,
+ req: EmptyObject,
+): Promise<CreateStoredBackupResponse> {
+ return await createStoredBackup(wex);
+}
+
+async function handleAcceptBankIntegratedWithdrawal(
+ wex: WalletExecutionContext,
+ req: AcceptBankIntegratedWithdrawalRequest,
+): Promise<AcceptWithdrawalResponse> {
+ return await acceptWithdrawalFromUri(wex, {
+ selectedExchange: req.exchangeBaseUrl,
+ talerWithdrawUri: req.talerWithdrawUri,
+ forcedDenomSel: req.forcedDenomSel,
+ restrictAge: req.restrictAge,
+ amount: req.amount,
+ });
+}
+
+interface HandlerWithValidator<Tag extends WalletApiOperation> {
+ codec: Codec<WalletCoreRequestType<Tag>>;
+ handler: (
+ wex: WalletExecutionContext,
+ req: WalletCoreRequestType<Tag>,
+ ) => Promise<WalletCoreResponseType<Tag>>;
+}
+
+// @ts-ignore
+const handlers: { [T in WalletApiOperation]: HandlerWithValidator<T> } = {
+ [WalletApiOperation.AbortTransaction]: {
+ codec: codecForAbortTransaction(),
+ handler: handleAbortTransaction,
+ },
+ [WalletApiOperation.CreateStoredBackup]: {
+ codec: codecForEmptyObject(),
+ handler: handleCreateStoredBackup,
+ },
+ [WalletApiOperation.DeleteStoredBackup]: {
+ codec: codecForDeleteStoredBackupRequest(),
+ handler: handleDeleteStoredBackup,
+ },
+ [WalletApiOperation.ListStoredBackups]: {
+ codec: codecForEmptyObject(),
+ handler: listStoredBackups,
+ },
+ [WalletApiOperation.SetWalletRunConfig]: {
+ codec: codecForInitRequest(),
+ handler: handleSetWalletRunConfig,
+ },
+ // Alias for SetWalletRunConfig
+ [WalletApiOperation.InitWallet]: {
+ codec: codecForInitRequest(),
+ handler: handleSetWalletRunConfig,
+ },
+ [WalletApiOperation.RecoverStoredBackup]: {
+ codec: codecForRecoverStoredBackupRequest(),
+ handler: handleRecoverStoredBackup,
+ },
+ [WalletApiOperation.WithdrawTestkudos]: {
+ codec: codecForEmptyObject(),
+ handler: handleWithdrawTestkudos,
+ },
+ [WalletApiOperation.WithdrawTestBalance]: {
+ codec: codecForWithdrawTestBalance(),
+ handler: handleWithdrawTestBalance,
+ },
+ [WalletApiOperation.RunIntegrationTest]: {
+ codec: codecForIntegrationTestArgs(),
+ handler: handleRunIntegrationTest,
+ },
+ [WalletApiOperation.RunIntegrationTestV2]: {
+ codec: codecForIntegrationTestV2Args(),
+ handler: handleRunIntegrationTestV2,
+ },
+ [WalletApiOperation.ValidateIban]: {
+ codec: codecForValidateIbanRequest(),
+ handler: handleValidateIban,
+ },
+ [WalletApiOperation.TestPay]: {
+ codec: codecForTestPayArgs(),
+ handler: testPay,
+ },
+ [WalletApiOperation.GetTransactions]: {
+ codec: codecForTransactionsRequest(),
+ handler: getTransactions,
+ },
+ [WalletApiOperation.GetTransactionById]: {
+ codec: codecForTransactionByIdRequest(),
+ handler: getTransactionById,
+ },
+};
+
/**
* Implementation of the "wallet-core" API.
*/
@@ -1213,7 +1466,7 @@ async function dispatchRequestInternal(
// definitions we already have?
switch (operation) {
case WalletApiOperation.CreateStoredBackup:
- return await createStoredBackup(wex);
+ return await handleCreateStoredBackup(wex, {});
case WalletApiOperation.DeleteStoredBackup: {
const req = codecForDeleteStoredBackupRequest().decode(payload);
return await handleDeleteStoredBackup(wex, req);
@@ -1356,13 +1609,7 @@ async function dispatchRequestInternal(
case WalletApiOperation.AcceptBankIntegratedWithdrawal: {
const req =
codecForAcceptBankIntegratedWithdrawalRequest().decode(payload);
- return await acceptWithdrawalFromUri(wex, {
- selectedExchange: req.exchangeBaseUrl,
- talerWithdrawUri: req.talerWithdrawUri,
- forcedDenomSel: req.forcedDenomSel,
- restrictAge: req.restrictAge,
- amount: req.amount,
- });
+ return handleAcceptBankIntegratedWithdrawal(wex, req);
}
case WalletApiOperation.ConfirmWithdrawal: {
const req = codecForConfirmWithdrawalRequestRequest().decode(payload);
@@ -1567,100 +1814,20 @@ async function dispatchRequestInternal(
return await handleListGlobalCurrencyExchanges(wex, req);
}
case WalletApiOperation.ListGlobalCurrencyAuditors: {
- const resp: ListGlobalCurrencyAuditorsResponse = {
- auditors: [],
- };
- await wex.db.runReadOnlyTx(
- { storeNames: ["globalCurrencyAuditors"] },
- async (tx) => {
- const gcaList = await tx.globalCurrencyAuditors.iter().toArray();
- for (const gca of gcaList) {
- resp.auditors.push({
- currency: gca.currency,
- auditorBaseUrl: gca.auditorBaseUrl,
- auditorPub: gca.auditorPub,
- });
- }
- },
- );
- return resp;
+ const req = codecForEmptyObject().decode(payload);
+ return await handleListGlobalCurrencyAuditors(wex, req);
}
case WalletApiOperation.AddGlobalCurrencyExchange: {
const req = codecForAddGlobalCurrencyExchangeRequest().decode(payload);
- await wex.db.runReadWriteTx(
- { storeNames: ["globalCurrencyExchanges"] },
- async (tx) => {
- const key = [
- req.currency,
- req.exchangeBaseUrl,
- req.exchangeMasterPub,
- ];
- const existingRec =
- await tx.globalCurrencyExchanges.indexes.byCurrencyAndUrlAndPub.get(
- key,
- );
- if (existingRec) {
- return;
- }
- wex.ws.exchangeCache.clear();
- await tx.globalCurrencyExchanges.add({
- currency: req.currency,
- exchangeBaseUrl: req.exchangeBaseUrl,
- exchangeMasterPub: req.exchangeMasterPub,
- });
- },
- );
- return {};
+ return handleAddGlobalCurrencyExchange(wex, req);
}
case WalletApiOperation.RemoveGlobalCurrencyExchange: {
const req = codecForRemoveGlobalCurrencyExchangeRequest().decode(payload);
- await wex.db.runReadWriteTx(
- { storeNames: ["globalCurrencyExchanges"] },
- async (tx) => {
- const key = [
- req.currency,
- req.exchangeBaseUrl,
- req.exchangeMasterPub,
- ];
- const existingRec =
- await tx.globalCurrencyExchanges.indexes.byCurrencyAndUrlAndPub.get(
- key,
- );
- if (!existingRec) {
- return;
- }
- wex.ws.exchangeCache.clear();
- checkDbInvariant(
- !!existingRec.id,
- `no global exchange for ${j2s(key)}`,
- );
- await tx.globalCurrencyExchanges.delete(existingRec.id);
- },
- );
- return {};
+ return handleRemoveGlobalCurrencyExchange(wex, req);
}
case WalletApiOperation.AddGlobalCurrencyAuditor: {
const req = codecForAddGlobalCurrencyAuditorRequest().decode(payload);
- await wex.db.runReadWriteTx(
- { storeNames: ["globalCurrencyAuditors"] },
- async (tx) => {
- const key = [req.currency, req.auditorBaseUrl, req.auditorPub];
- const existingRec =
- await tx.globalCurrencyAuditors.indexes.byCurrencyAndUrlAndPub.get(
- key,
- );
- if (existingRec) {
- return;
- }
- await tx.globalCurrencyAuditors.add({
- currency: req.currency,
- auditorBaseUrl: req.auditorBaseUrl,
- auditorPub: req.auditorPub,
- });
- wex.ws.exchangeCache.clear();
- },
- );
- return {};
+ return handleAddGlobalCurrencyAuditor(wex, req);
}
case WalletApiOperation.TestingWaitTasksDone: {
await waitTasksDone(wex);
@@ -1671,26 +1838,7 @@ async function dispatchRequestInternal(
return {};
case WalletApiOperation.RemoveGlobalCurrencyAuditor: {
const req = codecForRemoveGlobalCurrencyAuditorRequest().decode(payload);
- await wex.db.runReadWriteTx(
- { storeNames: ["globalCurrencyAuditors"] },
- async (tx) => {
- const key = [req.currency, req.auditorBaseUrl, req.auditorPub];
- const existingRec =
- await tx.globalCurrencyAuditors.indexes.byCurrencyAndUrlAndPub.get(
- key,
- );
- if (!existingRec) {
- return;
- }
- checkDbInvariant(
- !!existingRec.id,
- `no global currency for ${j2s(key)}`,
- );
- await tx.globalCurrencyAuditors.delete(existingRec.id);
- wex.ws.exchangeCache.clear();
- },
- );
- return {};
+ return await handleRemoveGlobalCurrencyAuditor(wex, req);
}
case WalletApiOperation.ImportDb: {
const req = codecForImportDbRequest().decode(payload);
@@ -1735,8 +1883,8 @@ async function dispatchRequestInternal(
return {};
}
case WalletApiOperation.Shutdown: {
- wex.ws.stop();
- return {};
+ const req = codecForEmptyObject().decode(payload);
+ return await handleShutdown(wex, req);
}
case WalletApiOperation.GetVersion: {
return handleGetVersion(wex);
@@ -1747,14 +1895,11 @@ async function dispatchRequestInternal(
return await waitUntilRefreshesDone(wex);
case WalletApiOperation.TestingSetTimetravel: {
const req = codecForTestingSetTimetravelRequest().decode(payload);
- setDangerousTimetravel(req.offsetMs);
- await wex.taskScheduler.reload();
- return {};
+ return await handleTestingSetTimetravel(wex, req);
}
case WalletApiOperation.DeleteExchange: {
const req = codecForDeleteExchangeRequest().decode(payload);
- await deleteExchange(wex, req);
- return {};
+ return await handleDeleteExchange(wex, req);
}
case WalletApiOperation.GetExchangeResources: {
const req = codecForGetExchangeResourcesRequest().decode(payload);
@@ -1762,45 +1907,8 @@ async function dispatchRequestInternal(
}
case WalletApiOperation.CanonicalizeBaseUrl: {
const req = codecForCanonicalizeBaseUrlRequest().decode(payload);
- return {
- url: canonicalizeBaseUrl(req.url),
- };
- }
- case WalletApiOperation.TestingInfiniteTransactionLoop: {
- const myDelayMs = (payload as any).delayMs ?? 5;
- const shouldFetch = !!(payload as any).shouldFetch;
- const doFetch = async () => {
- while (1) {
- const url =
- "https://exchange.demo.taler.net/reserves/01PMMB9PJN0QBWAFBXV6R0KNJJMAKXCV4D6FDG0GJFDJQXGYP32G?timeout_ms=30000";
- logger.info(`fetching ${url}`);
- const res = await wex.http.fetch(url);
- logger.info(`fetch result ${res.status}`);
- }
- };
- if (shouldFetch) {
- // In the background!
- doFetch();
- }
- let loopCount = 0;
- while (true) {
- logger.info(`looping test write tx, iteration ${loopCount}`);
- await wex.db.runReadWriteTx({ storeNames: ["config"] }, async (tx) => {
- await tx.config.put({
- key: ConfigRecordKey.TestLoopTx,
- value: loopCount,
- });
- });
- if (myDelayMs != 0) {
- await new Promise<void>((resolve, reject) => {
- setTimeout(() => resolve(), myDelayMs);
- });
- }
- loopCount = (loopCount + 1) % (Number.MAX_SAFE_INTEGER - 1);
- }
+ return handleCanonicalizeBaseUrl(wex, req);
}
- // default:
- // assertUnreachable(operation);
}
throw TalerError.fromDetail(
TalerErrorCode.WALLET_CORE_API_OPERATION_UNKNOWN,