From fe8749c3f81547d080ea23d580497750d52fed91 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 25 May 2023 19:26:40 +0200 Subject: wallet-core: implement cancelAbortingTransaction for deposit groups --- packages/taler-wallet-core/src/db.ts | 14 ++-- .../taler-wallet-core/src/operations/deposits.ts | 80 +++++++++++++++------- .../src/operations/transactions.ts | 18 +++++ packages/taler-wallet-core/src/wallet.ts | 7 ++ 4 files changed, 88 insertions(+), 31 deletions(-) (limited to 'packages/taler-wallet-core/src') diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index d2a91aac4..8d66ee27b 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -1628,11 +1628,15 @@ export interface BackupProviderRecord { } export enum DepositOperationStatus { - Finished = 50 /* OperationStatusRange.DORMANT_START */, - Suspended = 51 /* OperationStatusRange.DORMANT_START + 1 */, - Aborted = 52 /* OperationStatusRange.DORMANT_START + 2 */, - Pending = 10 /* OperationStatusRange.ACTIVE_START */, - Aborting = 11 /* OperationStatusRange.ACTIVE_START + 1 */, + Pending = 10, + Aborting = 11, + + Suspended = 20, + SuspendedAborting = 21, + + Finished = 50, + Failed = 51, + Aborted = 52, } export interface DepositTrackingInfo { diff --git a/packages/taler-wallet-core/src/operations/deposits.ts b/packages/taler-wallet-core/src/operations/deposits.ts index 6c41d76f6..dc743e17f 100644 --- a/packages/taler-wallet-core/src/operations/deposits.ts +++ b/packages/taler-wallet-core/src/operations/deposits.ts @@ -167,6 +167,14 @@ export function computeDepositTransactionStatus( return { major: TransactionMajorState.Aborted, } + case DepositOperationStatus.Failed: + return { + major: TransactionMajorState.Failed, + } + case DepositOperationStatus.SuspendedAborting: + return { + major: TransactionMajorState.SuspendedAborting, + } default: throw Error(`unexpected deposit group state (${dg.operationStatus})`); } @@ -184,7 +192,7 @@ export async function suspendDepositGroup( tag: PendingTaskType.Deposit, depositGroupId, }); - let res = await ws.db + const transitionInfo = await ws.db .mktx((x) => [x.depositGroups]) .runReadWrite(async (tx) => { const dg = await tx.depositGroups.get(depositGroupId); @@ -212,14 +220,7 @@ export async function suspendDepositGroup( return undefined; }); stopLongpolling(ws, retryTag); - if (res) { - ws.notify({ - type: NotificationType.TransactionStateTransition, - transactionId, - oldTxState: res.oldTxState, - newTxState: res.newTxState, - }); - } + notifyTransition(ws, transactionId, transitionInfo); } export async function resumeDepositGroup( @@ -230,7 +231,7 @@ export async function resumeDepositGroup( tag: TransactionType.Deposit, depositGroupId, }); - let res = await ws.db + const transitionInfo = await ws.db .mktx((x) => [x.depositGroups]) .runReadWrite(async (tx) => { const dg = await tx.depositGroups.get(depositGroupId); @@ -258,14 +259,7 @@ export async function resumeDepositGroup( return undefined; }); ws.workAvailable.trigger(); - if (res) { - ws.notify({ - type: NotificationType.TransactionStateTransition, - transactionId, - oldTxState: res.oldTxState, - newTxState: res.newTxState, - }); - } + notifyTransition(ws, transactionId, transitionInfo); } export async function abortDepositGroup( @@ -280,7 +274,7 @@ export async function abortDepositGroup( tag: PendingTaskType.Deposit, depositGroupId, }); - let res = await ws.db + const transitionInfo = await ws.db .mktx((x) => [x.depositGroups]) .runReadWrite(async (tx) => { const dg = await tx.depositGroups.get(depositGroupId); @@ -311,14 +305,48 @@ export async function abortDepositGroup( stopLongpolling(ws, retryTag); // Need to process the operation again. ws.workAvailable.trigger(); - if (res) { - ws.notify({ - type: NotificationType.TransactionStateTransition, - transactionId, - oldTxState: res.oldTxState, - newTxState: res.newTxState, + notifyTransition(ws, transactionId, transitionInfo); +} + +export async function cancelAbortingDepositGroup( + ws: InternalWalletState, + depositGroupId: string, +): Promise { + const transactionId = constructTransactionIdentifier({ + tag: TransactionType.Deposit, + depositGroupId, + }); + const retryTag = constructTaskIdentifier({ + tag: PendingTaskType.Deposit, + depositGroupId, + }); + const transitionInfo = await ws.db + .mktx((x) => [x.depositGroups]) + .runReadWrite(async (tx) => { + const dg = await tx.depositGroups.get(depositGroupId); + if (!dg) { + logger.warn( + `can't cancel aborting deposit group, depositGroupId=${depositGroupId} not found`, + ); + return undefined; + } + const oldState = computeDepositTransactionStatus(dg); + switch (dg.operationStatus) { + case DepositOperationStatus.SuspendedAborting: + case DepositOperationStatus.Aborting: { + dg.operationStatus = DepositOperationStatus.Failed; + await tx.depositGroups.put(dg); + return { + oldTxState: oldState, + newTxState: computeDepositTransactionStatus(dg), + }; + } + } + return undefined; }); - } + // FIXME: Also cancel ongoing work (via cancellation token, once implemented) + stopLongpolling(ws, retryTag); + notifyTransition(ws, transactionId, transitionInfo); } export async function deleteDepositGroup( diff --git a/packages/taler-wallet-core/src/operations/transactions.ts b/packages/taler-wallet-core/src/operations/transactions.ts index 74df9acfb..84f879f58 100644 --- a/packages/taler-wallet-core/src/operations/transactions.ts +++ b/packages/taler-wallet-core/src/operations/transactions.ts @@ -75,6 +75,7 @@ import { } from "./common.js"; import { abortDepositGroup, + cancelAbortingDepositGroup, computeDepositTransactionStatus, processDepositGroup, resumeDepositGroup, @@ -1401,6 +1402,23 @@ export async function suspendTransaction( } } +export async function cancelAbortingTransaction( + ws: InternalWalletState, + transactionId: string, +): Promise { + const tx = parseTransactionIdentifier(transactionId); + if (!tx) { + throw Error("invalid transaction ID"); + } + switch (tx.tag) { + case TransactionType.Deposit: + await cancelAbortingDepositGroup(ws, tx.depositGroupId); + return; + default: + logger.warn(`unable to suspend transaction of type '${tx.tag}'`); + } +} + /** * Resume a suspended transaction. */ diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index b20791241..85b0b9250 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -65,6 +65,7 @@ import { codecForApplyDevExperiment, codecForApplyRefundFromPurchaseIdRequest, codecForApplyRefundRequest, + codecForCancelAbortingTransactionRequest, codecForCheckPeerPullPaymentRequest, codecForCheckPeerPushDebitRequest, codecForConfirmPayRequest, @@ -231,6 +232,7 @@ import { import { acceptTip, prepareTip, processTip } from "./operations/tip.js"; import { abortTransaction, + cancelAbortingTransaction, deleteTransaction, getTransactionById, getTransactions, @@ -1229,6 +1231,11 @@ async function dispatchRequestInternal( await suspendTransaction(ws, req.transactionId); return {}; } + case WalletApiOperation.CancelAbortingTransaction: { + const req = codecForCancelAbortingTransactionRequest().decode(payload); + await cancelAbortingTransaction(ws, req.transactionId); + return {}; + } case WalletApiOperation.ResumeTransaction: { const req = codecForResumeTransaction().decode(payload); await resumeTransaction(ws, req.transactionId); -- cgit v1.2.3