diff options
Diffstat (limited to 'packages/taler-wallet-core/src/refresh.ts')
-rw-r--r-- | packages/taler-wallet-core/src/refresh.ts | 77 |
1 files changed, 76 insertions, 1 deletions
diff --git a/packages/taler-wallet-core/src/refresh.ts b/packages/taler-wallet-core/src/refresh.ts index c6a7b768d..7bf231870 100644 --- a/packages/taler-wallet-core/src/refresh.ts +++ b/packages/taler-wallet-core/src/refresh.ts @@ -21,6 +21,7 @@ import { Amounts, amountToPretty, assertUnreachable, + AsyncFlag, checkDbInvariant, codecForExchangeMeltResponse, codecForExchangeRevealResponse, @@ -61,7 +62,6 @@ import { readSuccessResponseJsonOrThrow, readUnexpectedResponseDetails, } from "@gnu-taler/taler-util/http"; -import { selectWithdrawalDenominations } from "./denomSelection.js"; import { constructTaskIdentifier, makeCoinAvailable, @@ -92,6 +92,7 @@ import { WalletDbReadOnlyTransaction, WalletDbReadWriteTransaction, } from "./db.js"; +import { selectWithdrawalDenominations } from "./denomSelection.js"; import { fetchFreshExchange } from "./exchanges.js"; import { constructTransactionIdentifier, @@ -1462,3 +1463,77 @@ export async function forceRefresh( refreshGroupId: res.refreshGroupId, }; } + +/** + * Wait until a refresh operation is final. + */ +export async function waitRefreshFinal( + wex: WalletExecutionContext, + refreshGroupId: string, +): Promise<void> { + const ctx = new RefreshTransactionContext(wex, refreshGroupId); + wex.taskScheduler.startShepherdTask(ctx.taskId); + + // FIXME: Clean up using the new JS "using" / Symbol.dispose syntax. + const refreshNotifFlag = 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 + ) { + refreshNotifFlag.raise(); + } + }); + const unregisterOnCancelled = wex.cancellationToken.onCancelled(() => { + cancelNotif(); + refreshNotifFlag.raise(); + }); + + try { + await internalWaitRefreshFinal(ctx, refreshNotifFlag); + } catch (e) { + unregisterOnCancelled(); + cancelNotif(); + } +} + +async function internalWaitRefreshFinal( + ctx: RefreshTransactionContext, + flag: AsyncFlag, +): Promise<void> { + while (true) { + if (ctx.wex.cancellationToken.isCancelled) { + throw Error("cancelled"); + } + + // Check if refresh is final + const res = await ctx.wex.db.runReadOnlyTx( + ["refreshGroups", "operationRetries"], + async (tx) => { + return { + rg: await tx.refreshGroups.get(ctx.refreshGroupId), + }; + }, + ); + const { rg } = res; + if (!rg) { + // Must've been deleted, we consider that final. + return; + } + switch (rg.operationStatus) { + case RefreshOperationStatus.Failed: + case RefreshOperationStatus.Finished: + // Transaction is final + return; + case RefreshOperationStatus.Pending: + case RefreshOperationStatus.Suspended: + break; + } + + // Wait for the next transition + await flag.wait(); + flag.reset(); + } +} |