diff options
Diffstat (limited to 'packages/taler-wallet-core/src/operations/tip.ts')
-rw-r--r-- | packages/taler-wallet-core/src/operations/tip.ts | 108 |
1 files changed, 106 insertions, 2 deletions
diff --git a/packages/taler-wallet-core/src/operations/tip.ts b/packages/taler-wallet-core/src/operations/tip.ts index 524970faa..70b595c2f 100644 --- a/packages/taler-wallet-core/src/operations/tip.ts +++ b/packages/taler-wallet-core/src/operations/tip.ts @@ -48,6 +48,7 @@ import { CoinSourceType, DenominationRecord, TipRecord, + TipRecordStatus, } from "../db.js"; import { makeErrorDetail } from "@gnu-taler/taler-util"; import { InternalWalletState } from "../internal-wallet-state.js"; @@ -57,6 +58,7 @@ import { } from "@gnu-taler/taler-util/http"; import { checkDbInvariant, checkLogicInvariant } from "../util/invariants.js"; import { + constructTaskIdentifier, OperationAttemptResult, OperationAttemptResultType, } from "../util/retries.js"; @@ -68,7 +70,13 @@ import { updateWithdrawalDenoms, } from "./withdraw.js"; import { selectWithdrawalDenominations } from "../util/coinSelection.js"; -import { constructTransactionIdentifier } from "./transactions.js"; +import { + constructTransactionIdentifier, + notifyTransition, + stopLongpolling, +} from "./transactions.js"; +import { PendingTaskType } from "../pending-types.js"; +import { assertUnreachable } from "../util/assertUnreachable.js"; const logger = new Logger("operations/tip.ts"); @@ -156,6 +164,7 @@ export async function prepareTip( const newTipRecord: TipRecord = { walletTipId: walletTipId, acceptedTimestamp: undefined, + status: TipRecordStatus.PendingPickup, tipAmountRaw: Amounts.stringify(amount), tipExpiration: tipPickupStatus.expiration, exchangeBaseUrl: tipPickupStatus.exchange_url, @@ -180,7 +189,7 @@ export async function prepareTip( const transactionId = constructTransactionIdentifier({ tag: TransactionType.Tip, walletTipId: tipRecord.walletTipId, - }) + }); const tipStatus: PrepareTipResult = { accepted: !!tipRecord && !!tipRecord.acceptedTimestamp, @@ -410,3 +419,98 @@ export async function acceptTip( next_url: found?.next_url, }; } + +export async function suspendTipTransaction( + ws: InternalWalletState, + walletTipId: string, +): Promise<void> { + const taskId = constructTaskIdentifier({ + tag: PendingTaskType.TipPickup, + walletTipId, + }); + const transactionId = constructTransactionIdentifier({ + tag: TransactionType.Tip, + walletTipId, + }); + stopLongpolling(ws, taskId); + const transitionInfo = await ws.db + .mktx((x) => [x.tips]) + .runReadWrite(async (tx) => { + const tipRec = await tx.tips.get(walletTipId); + if (!tipRec) { + logger.warn(`transaction tip ${walletTipId} not found`); + return; + } + let newStatus: TipRecordStatus | undefined = undefined; + switch (tipRec.status) { + case TipRecordStatus.Done: + case TipRecordStatus.SuspendidPickup: + break; + case TipRecordStatus.PendingPickup: + newStatus = TipRecordStatus.SuspendidPickup; + break; + default: + assertUnreachable(tipRec.status); + } + if (newStatus != null) { + const oldTxState = computeTipTransactionStatus(tipRec); + tipRec.status = newStatus; + const newTxState = computeTipTransactionStatus(tipRec); + await tx.tips.put(tipRec); + return { + oldTxState, + newTxState, + }; + } + return undefined; + }); + ws.workAvailable.trigger(); + notifyTransition(ws, transactionId, transitionInfo); +} + +export async function resumeTipTransaction( + ws: InternalWalletState, + walletTipId: string, +): Promise<void> { + const taskId = constructTaskIdentifier({ + tag: PendingTaskType.TipPickup, + walletTipId, + }); + const transactionId = constructTransactionIdentifier({ + tag: TransactionType.Tip, + walletTipId, + }); + stopLongpolling(ws, taskId); + const transitionInfo = await ws.db + .mktx((x) => [x.tips]) + .runReadWrite(async (tx) => { + const tipRec = await tx.tips.get(walletTipId); + if (!tipRec) { + logger.warn(`transaction tip ${walletTipId} not found`); + return; + } + let newStatus: TipRecordStatus | undefined = undefined; + switch (tipRec.status) { + case TipRecordStatus.Done: + case TipRecordStatus.SuspendidPickup: + newStatus = TipRecordStatus.PendingPickup; + break; + case TipRecordStatus.PendingPickup: + break; + default: + assertUnreachable(tipRec.status); + } + if (newStatus != null) { + const oldTxState = computeTipTransactionStatus(tipRec); + tipRec.status = newStatus; + const newTxState = computeTipTransactionStatus(tipRec); + await tx.tips.put(tipRec); + return { + oldTxState, + newTxState, + }; + } + return undefined; + }); + notifyTransition(ws, transactionId, transitionInfo); +} |