From 0a2540d676904e804544b95959bae223e42bc0c1 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Fri, 8 Mar 2024 10:30:23 +0100 Subject: wallet-core: notification-based waiting for dependent transactions instead of long-polling --- packages/taler-wallet-core/src/withdraw.ts | 86 ++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 5 deletions(-) (limited to 'packages/taler-wallet-core/src/withdraw.ts') diff --git a/packages/taler-wallet-core/src/withdraw.ts b/packages/taler-wallet-core/src/withdraw.ts index 0f70479a5..f27e9e132 100644 --- a/packages/taler-wallet-core/src/withdraw.ts +++ b/packages/taler-wallet-core/src/withdraw.ts @@ -94,10 +94,6 @@ import { readSuccessResponseJsonOrThrow, throwUnexpectedRequestError, } from "@gnu-taler/taler-util/http"; -import { - selectForcedWithdrawalDenominations, - selectWithdrawalDenominations, -} from "./denomSelection.js"; import { PendingTaskType, TaskIdStr, @@ -127,6 +123,10 @@ import { WithdrawalRecordType, timestampPreciseToDb, } from "./db.js"; +import { + selectForcedWithdrawalDenominations, + selectWithdrawalDenominations, +} from "./denomSelection.js"; import { isWithdrawableDenom } from "./denominations.js"; import { ReadyExchangeSummary, @@ -1935,7 +1935,8 @@ export async function getWithdrawalDetailsForUri( uri: talerWithdrawUri, }); } - }).finally(() => { + }) + .finally(() => { ongoingChecks[talerWithdrawUri] = false; }); } @@ -2703,6 +2704,7 @@ async function waitWithdrawalRegistered( wex: WalletExecutionContext, ctx: WithdrawTransactionContext, ): Promise { + // FIXME: Doesn't support cancellation yet // FIXME: We should use Symbol.dispose magic here for cleanup! const withdrawalNotifFlag = new AsyncFlag(); @@ -2914,3 +2916,77 @@ export async function createManualWithdrawal( transactionId: ctx.transactionId, }; } + +/** + * Wait until a refresh operation is final. + */ +export async function waitWithdrawalFinal( + wex: WalletExecutionContext, + withdrawalGroupId: string, +): Promise { + const ctx = new WithdrawTransactionContext(wex, withdrawalGroupId); + wex.taskScheduler.startShepherdTask(ctx.taskId); + + // FIXME: Clean up using the new JS "using" / Symbol.dispose syntax. + const withdrawalNotifFlag = new AsyncFlag(); + // Raise purchaseNotifFlag whenever we get a notification + // about our refresh. + const cancelNotif = wex.ws.addNotificationListener((notif) => { + if ( + notif.type === NotificationType.TransactionStateTransition && + notif.transactionId === ctx.transactionId + ) { + withdrawalNotifFlag.raise(); + } + }); + const unregisterOnCancelled = wex.cancellationToken.onCancelled(() => { + cancelNotif(); + withdrawalNotifFlag.raise(); + }); + + try { + await internalWaitWithdrawalFinal(ctx, withdrawalNotifFlag); + } catch (e) { + unregisterOnCancelled(); + cancelNotif(); + } +} + +async function internalWaitWithdrawalFinal( + ctx: WithdrawTransactionContext, + flag: AsyncFlag, +): Promise { + while (true) { + if (ctx.wex.cancellationToken.isCancelled) { + throw Error("cancelled"); + } + + // Check if refresh is final + const res = await ctx.wex.db.runReadOnlyTx( + ["withdrawalGroups", "operationRetries"], + async (tx) => { + return { + wg: await tx.withdrawalGroups.get(ctx.withdrawalGroupId), + }; + }, + ); + const { wg } = res; + if (!wg) { + // Must've been deleted, we consider that final. + return; + } + switch (wg.status) { + case WithdrawalGroupStatus.AbortedBank: + case WithdrawalGroupStatus.AbortedExchange: + case WithdrawalGroupStatus.Done: + case WithdrawalGroupStatus.FailedAbortingBank: + case WithdrawalGroupStatus.FailedBankAborted: + // Transaction is final + return; + } + + // Wait for the next transition + await flag.wait(); + flag.reset(); + } +} -- cgit v1.2.3