diff options
Diffstat (limited to 'packages/taler-wallet-core/src/operations')
4 files changed, 53 insertions, 16 deletions
diff --git a/packages/taler-wallet-core/src/operations/common.ts b/packages/taler-wallet-core/src/operations/common.ts index e29065390..f35556736 100644 --- a/packages/taler-wallet-core/src/operations/common.ts +++ b/packages/taler-wallet-core/src/operations/common.ts @@ -28,6 +28,7 @@ import { ExchangeTosStatus, j2s, Logger, + OperationErrorInfo, RefreshReason, TalerErrorCode, TalerErrorDetail, @@ -224,30 +225,37 @@ export async function storeOperationPending( }); } -export async function runOperationWithErrorReporting( +export async function runOperationWithErrorReporting<T1, T2>( ws: InternalWalletState, opId: string, - f: () => Promise<OperationAttemptResult>, -): Promise<void> { + f: () => Promise<OperationAttemptResult<T1, T2>>, +): Promise<OperationAttemptResult<T1, T2>> { let maybeError: TalerErrorDetail | undefined; try { const resp = await f(); switch (resp.type) { case OperationAttemptResultType.Error: - return await storeOperationError(ws, opId, resp.errorDetail); + await storeOperationError(ws, opId, resp.errorDetail); + return resp; case OperationAttemptResultType.Finished: - return await storeOperationFinished(ws, opId); + await storeOperationFinished(ws, opId); + return resp; case OperationAttemptResultType.Pending: - return await storeOperationPending(ws, opId); + await storeOperationPending(ws, opId); + return resp; case OperationAttemptResultType.Longpoll: - break; + return resp; } } catch (e) { if (e instanceof TalerError) { logger.warn("operation processed resulted in error"); logger.warn(`error was: ${j2s(e.errorDetail)}`); maybeError = e.errorDetail; - return await storeOperationError(ws, opId, maybeError!); + await storeOperationError(ws, opId, maybeError!); + return { + type: OperationAttemptResultType.Error, + errorDetail: e.errorDetail, + }; } else if (e instanceof Error) { // This is a bug, as we expect pending operations to always // do their own error handling and only throw WALLET_PENDING_OPERATION_FAILED @@ -261,7 +269,11 @@ export async function runOperationWithErrorReporting( }, `unexpected exception (message: ${e.message})`, ); - return await storeOperationError(ws, opId, maybeError); + await storeOperationError(ws, opId, maybeError); + return { + type: OperationAttemptResultType.Error, + errorDetail: maybeError, + }; } else { logger.error("Uncaught exception, value is not even an error."); maybeError = makeErrorDetail( @@ -269,7 +281,11 @@ export async function runOperationWithErrorReporting( {}, `unexpected exception (not even an error)`, ); - return await storeOperationError(ws, opId, maybeError); + await storeOperationError(ws, opId, maybeError); + return { + type: OperationAttemptResultType.Error, + errorDetail: maybeError, + }; } } } @@ -357,7 +373,13 @@ export function getExchangeTosStatus( export function makeExchangeListItem( r: ExchangeRecord, exchangeDetails: ExchangeDetailsRecord | undefined, + lastError: TalerErrorDetail | undefined, ): ExchangeListItem { + const lastUpdateErrorInfo: OperationErrorInfo | undefined = lastError + ? { + error: lastError, + } + : undefined; if (!exchangeDetails) { return { exchangeBaseUrl: r.baseUrl, @@ -367,6 +389,7 @@ export function makeExchangeListItem( exchangeStatus: ExchangeEntryStatus.Unknown, permanent: r.permanent, ageRestrictionOptions: [], + lastUpdateErrorInfo, }; } let exchangeStatus; @@ -381,5 +404,6 @@ export function makeExchangeListItem( ageRestrictionOptions: exchangeDetails.ageMask ? AgeRestriction.getAgeGroupsFromMask(exchangeDetails.ageMask) : [], + lastUpdateErrorInfo, }; } diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts b/packages/taler-wallet-core/src/operations/exchanges.ts index 41e63b956..23ff1479e 100644 --- a/packages/taler-wallet-core/src/operations/exchanges.ts +++ b/packages/taler-wallet-core/src/operations/exchanges.ts @@ -73,9 +73,11 @@ import { import { OperationAttemptResult, OperationAttemptResultType, - runOperationHandlerForResult, + RetryTags, + unwrapOperationHandlerResultOrThrow, } from "../util/retries.js"; import { WALLET_EXCHANGE_PROTOCOL_VERSION } from "../versions.js"; +import { runOperationWithErrorReporting } from "./common.js"; import { isWithdrawableDenom } from "./withdraw.js"; const logger = new Logger("exchanges.ts"); @@ -546,8 +548,13 @@ export async function updateExchangeFromUrl( exchange: ExchangeRecord; exchangeDetails: ExchangeDetailsRecord; }> { - return runOperationHandlerForResult( - await updateExchangeFromUrlHandler(ws, baseUrl, options), + const canonUrl = canonicalizeBaseUrl(baseUrl); + return unwrapOperationHandlerResultOrThrow( + await runOperationWithErrorReporting( + ws, + RetryTags.forExchangeUpdateFromUrl(canonUrl), + () => updateExchangeFromUrlHandler(ws, canonUrl, options), + ), ); } diff --git a/packages/taler-wallet-core/src/operations/recoup.ts b/packages/taler-wallet-core/src/operations/recoup.ts index c2df6115b..e92c805bd 100644 --- a/packages/taler-wallet-core/src/operations/recoup.ts +++ b/packages/taler-wallet-core/src/operations/recoup.ts @@ -54,7 +54,7 @@ import { checkDbInvariant } from "../util/invariants.js"; import { GetReadWriteAccess } from "../util/query.js"; import { OperationAttemptResult, - runOperationHandlerForResult, + unwrapOperationHandlerResultOrThrow, } from "../util/retries.js"; import { createRefreshGroup, processRefreshGroup } from "./refresh.js"; import { internalCreateWithdrawalGroup } from "./withdraw.js"; @@ -307,7 +307,7 @@ export async function processRecoupGroup( forceNow?: boolean; } = {}, ): Promise<void> { - await runOperationHandlerForResult( + await unwrapOperationHandlerResultOrThrow( await processRecoupGroupHandler(ws, recoupGroupId, options), ); return; diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts index 0e6bb8339..a9ecdf369 100644 --- a/packages/taler-wallet-core/src/operations/withdraw.ts +++ b/packages/taler-wallet-core/src/operations/withdraw.ts @@ -1385,6 +1385,7 @@ export async function getWithdrawalDetailsForUri( x.exchangeDetails, x.exchangeTos, x.denominations, + x.operationRetries, ]) .runReadOnly(async (tx) => { const exchangeRecords = await tx.exchanges.iter().toArray(); @@ -1396,8 +1397,13 @@ export async function getWithdrawalDetailsForUri( const denominations = await tx.denominations.indexes.byExchangeBaseUrl .iter(r.baseUrl) .toArray(); + const retryRecord = await tx.operationRetries.get( + RetryTags.forExchangeUpdate(r), + ); if (exchangeDetails && denominations) { - exchanges.push(makeExchangeListItem(r, exchangeDetails)); + exchanges.push( + makeExchangeListItem(r, exchangeDetails, retryRecord?.lastError), + ); } } }); |