gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated: wallet: cancellation for depo


From: gnunet
Subject: [taler-wallet-core] branch master updated: wallet: cancellation for deposit
Date: Mon, 28 Mar 2022 23:59:23 +0200

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new f5d194df wallet: cancellation for deposit
f5d194df is described below

commit f5d194dfc61ae0d358a27b994861dc20b83cf98e
Author: Florian Dold <florian@dold.me>
AuthorDate: Mon Mar 28 23:59:16 2022 +0200

    wallet: cancellation for deposit
---
 packages/taler-wallet-core/src/db.ts               |  2 +-
 .../taler-wallet-core/src/internal-wallet-state.ts |  8 ++-
 .../taler-wallet-core/src/operations/deposits.ts   | 40 +++++++++++----
 .../taler-wallet-core/src/operations/exchanges.ts  | 60 ++++++++++++++++++----
 .../src/operations/transactions.ts                 |  4 +-
 packages/taler-wallet-core/src/wallet.ts           | 15 +++++-
 6 files changed, 103 insertions(+), 26 deletions(-)

diff --git a/packages/taler-wallet-core/src/db.ts 
b/packages/taler-wallet-core/src/db.ts
index 69606b8f..e3da3597 100644
--- a/packages/taler-wallet-core/src/db.ts
+++ b/packages/taler-wallet-core/src/db.ts
@@ -550,7 +550,7 @@ export interface ExchangeRecord {
   /**
    * Retry status for fetching updated information about the exchange.
    */
-  retryInfo: RetryInfo;
+  retryInfo?: RetryInfo;
 }
 
 /**
diff --git a/packages/taler-wallet-core/src/internal-wallet-state.ts 
b/packages/taler-wallet-core/src/internal-wallet-state.ts
index 5ecf796e..6b964cdf 100644
--- a/packages/taler-wallet-core/src/internal-wallet-state.ts
+++ b/packages/taler-wallet-core/src/internal-wallet-state.ts
@@ -35,6 +35,7 @@ import {
   AmountJson,
   DenominationPubKey,
   TalerProtocolTimestamp,
+  CancellationToken,
 } from "@gnu-taler/taler-util";
 import { CryptoDispatcher } from "./crypto/workers/cryptoDispatcher.js";
 import { TalerCryptoInterface } from "./crypto/cryptoImplementation.js";
@@ -200,9 +201,14 @@ export interface InternalWalletState {
   memoGetBalance: AsyncOpMemoSingle<BalancesResponse>;
   memoProcessRefresh: AsyncOpMemoMap<void>;
   memoProcessRecoup: AsyncOpMemoMap<void>;
-  memoProcessDeposit: AsyncOpMemoMap<void>;
   cryptoApi: TalerCryptoInterface;
 
+  /**
+   * Cancellation token for the currently running
+   * deposit operation, if any.
+   */
+  taskCancellationSourceForDeposit?: CancellationToken.Source;
+
   timerGroup: TimerGroup;
   stopped: boolean;
 
diff --git a/packages/taler-wallet-core/src/operations/deposits.ts 
b/packages/taler-wallet-core/src/operations/deposits.ts
index 501e9b76..c11c45dc 100644
--- a/packages/taler-wallet-core/src/operations/deposits.ts
+++ b/packages/taler-wallet-core/src/operations/deposits.ts
@@ -21,6 +21,7 @@ import {
   AbsoluteTime,
   AmountJson,
   Amounts,
+  CancellationToken,
   canonicalJson,
   codecForDepositSuccess,
   ContractTerms,
@@ -125,23 +126,34 @@ async function reportDepositGroupError(
 export async function processDepositGroup(
   ws: InternalWalletState,
   depositGroupId: string,
-  forceNow = false,
+  options: {
+    forceNow?: boolean;
+    cancellationToken?: CancellationToken;
+  } = {},
 ): Promise<void> {
-  await ws.memoProcessDeposit.memo(depositGroupId, async () => {
-    const onOpErr = (err: TalerErrorDetail): Promise<void> =>
-      reportDepositGroupError(ws, depositGroupId, err);
-    return await guardOperationException(
-      async () => await processDepositGroupImpl(ws, depositGroupId, forceNow),
-      onOpErr,
-    );
-  });
+  if (ws.taskCancellationSourceForDeposit) {
+    ws.taskCancellationSourceForDeposit.cancel();
+  }
+  const onOpErr = (err: TalerErrorDetail): Promise<void> =>
+    reportDepositGroupError(ws, depositGroupId, err);
+  return await guardOperationException(
+    async () => await processDepositGroupImpl(ws, depositGroupId, options),
+    onOpErr,
+  );
 }
 
+/**
+ * @see {processDepositGroup}
+ */
 async function processDepositGroupImpl(
   ws: InternalWalletState,
   depositGroupId: string,
-  forceNow = false,
+  options: {
+    forceNow?: boolean;
+    cancellationToken?: CancellationToken;
+  } = {},
 ): Promise<void> {
+  const forceNow = options.forceNow ?? false;
   const depositGroup = await ws.db
     .mktx((x) => ({
       depositGroups: x.depositGroups,
@@ -170,6 +182,8 @@ async function processDepositGroupImpl(
     "",
   );
 
+  // Check for cancellation before expensive operations.
+  options.cancellationToken?.throwIfCancelled();
   const depositPermissions = await generateDepositPermissions(
     ws,
     depositGroup.payCoinSelection,
@@ -196,9 +210,13 @@ async function processDepositGroupImpl(
       denom_pub_hash: perm.h_denom,
       merchant_pub: depositGroup.merchantPub,
     };
+    // Check for cancellation before making network request.
+    options.cancellationToken?.throwIfCancelled();
     const url = new URL(`coins/${perm.coin_pub}/deposit`, perm.exchange_url);
     logger.info(`depositing to ${url}`);
-    const httpResp = await ws.http.postJson(url.href, requestBody);
+    const httpResp = await ws.http.postJson(url.href, requestBody, {
+      cancellationToken: options.cancellationToken,
+    });
     await readSuccessResponseJsonOrThrow(httpResp, codecForDepositSuccess());
     await ws.db
       .mktx((x) => ({ depositGroups: x.depositGroups }))
diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts 
b/packages/taler-wallet-core/src/operations/exchanges.ts
index 09449c87..fe1c9ef3 100644
--- a/packages/taler-wallet-core/src/operations/exchanges.ts
+++ b/packages/taler-wallet-core/src/operations/exchanges.ts
@@ -61,7 +61,11 @@ import {
   readSuccessResponseTextOrThrow,
 } from "../util/http.js";
 import { DbAccess, GetReadOnlyAccess } from "../util/query.js";
-import { initRetryInfo, updateRetryInfoTimeout } from "../util/retries.js";
+import {
+  initRetryInfo,
+  RetryInfo,
+  updateRetryInfoTimeout,
+} from "../util/retries.js";
 import {
   WALLET_CACHE_BREAKER_CLIENT_VERSION,
   WALLET_EXCHANGE_PROTOCOL_VERSION,
@@ -102,7 +106,7 @@ function denominationRecordFromKeys(
   return d;
 }
 
-async function handleExchangeUpdateError(
+async function reportExchangeUpdateError(
   ws: InternalWalletState,
   baseUrl: string,
   err: TalerErrorDetail,
@@ -114,14 +118,44 @@ async function handleExchangeUpdateError(
       if (!exchange) {
         return;
       }
-      exchange.retryInfo.retryCounter++;
-      updateRetryInfoTimeout(exchange.retryInfo);
       exchange.lastError = err;
       await tx.exchanges.put(exchange);
     });
-  if (err) {
-    ws.notify({ type: NotificationType.ExchangeOperationError, error: err });
-  }
+  ws.notify({ type: NotificationType.ExchangeOperationError, error: err });
+}
+
+async function resetExchangeUpdateRetry(
+  ws: InternalWalletState,
+  baseUrl: string,
+): Promise<void> {
+  await ws.db
+    .mktx((x) => ({ exchanges: x.exchanges }))
+    .runReadWrite(async (tx) => {
+      const exchange = await tx.exchanges.get(baseUrl);
+      if (!exchange) {
+        return;
+      }
+      delete exchange.lastError;
+      exchange.retryInfo = initRetryInfo();
+      await tx.exchanges.put(exchange);
+    });
+}
+
+async function incrementExchangeUpdateRetry(
+  ws: InternalWalletState,
+  baseUrl: string,
+): Promise<void> {
+  await ws.db
+    .mktx((x) => ({ exchanges: x.exchanges }))
+    .runReadWrite(async (tx) => {
+      const exchange = await tx.exchanges.get(baseUrl);
+      if (!exchange) {
+        return;
+      }
+      delete exchange.lastError;
+      exchange.retryInfo = RetryInfo.increment(exchange.retryInfo);
+      await tx.exchanges.put(exchange);
+    });
 }
 
 export function getExchangeRequestTimeout(): Duration {
@@ -349,7 +383,7 @@ export async function updateExchangeFromUrl(
   exchangeDetails: ExchangeDetailsRecord;
 }> {
   const onOpErr = (e: TalerErrorDetail): Promise<void> =>
-    handleExchangeUpdateError(ws, baseUrl, e);
+    reportExchangeUpdateError(ws, baseUrl, e);
   return await guardOperationException(
     () => updateExchangeFromUrlImpl(ws, baseUrl, acceptedFormat, forceNow),
     onOpErr,
@@ -543,6 +577,12 @@ async function updateExchangeFromUrlImpl(
     return { exchange, exchangeDetails };
   }
 
+  if (forceNow) {
+    await resetExchangeUpdateRetry(ws, baseUrl);
+  } else {
+    await incrementExchangeUpdateRetry(ws, baseUrl);
+  }
+
   logger.info("updating exchange /keys info");
 
   const timeout = getExchangeRequestTimeout();
@@ -624,8 +664,8 @@ async function updateExchangeFromUrlImpl(
         termsOfServiceAcceptedTimestamp: TalerProtocolTimestamp.now(),
       };
       // FIXME: only update if pointer got updated
-      r.lastError = undefined;
-      r.retryInfo = initRetryInfo();
+      delete r.lastError;
+      delete r.retryInfo;
       r.lastUpdate = TalerProtocolTimestamp.now();
       r.nextUpdate = keysInfo.expiry;
       // New denominations might be available.
diff --git a/packages/taler-wallet-core/src/operations/transactions.ts 
b/packages/taler-wallet-core/src/operations/transactions.ts
index cb312154..bb530618 100644
--- a/packages/taler-wallet-core/src/operations/transactions.ts
+++ b/packages/taler-wallet-core/src/operations/transactions.ts
@@ -444,7 +444,9 @@ export async function retryTransaction(
   switch (type) {
     case TransactionType.Deposit:
       const depositGroupId = rest[0];
-      processDepositGroup(ws, depositGroupId, true);
+      processDepositGroup(ws, depositGroupId, {
+        forceNow: true,
+      });
       break;
     case TransactionType.Withdrawal:
       const withdrawalGroupId = rest[0];
diff --git a/packages/taler-wallet-core/src/wallet.ts 
b/packages/taler-wallet-core/src/wallet.ts
index 94305115..abd11faa 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -78,6 +78,7 @@ import {
   URL,
   WalletNotification,
   Duration,
+  CancellationToken,
 } from "@gnu-taler/taler-util";
 import { timeStamp } from "console";
 import {
@@ -271,9 +272,19 @@ async function processOnePendingOperation(
     case PendingTaskType.ExchangeCheckRefresh:
       await autoRefresh(ws, pending.exchangeBaseUrl);
       break;
-    case PendingTaskType.Deposit:
-      await processDepositGroup(ws, pending.depositGroupId);
+    case PendingTaskType.Deposit: {
+      const cts = CancellationToken.create();
+      ws.taskCancellationSourceForDeposit = cts;
+      try {
+        await processDepositGroup(ws, pending.depositGroupId, {
+          cancellationToken: cts.token,
+        });
+      } finally {
+        cts.dispose();
+        delete ws.taskCancellationSourceForDeposit;
+      }
       break;
+    }
     case PendingTaskType.Backup:
       await processBackupForProvider(ws, pending.backupProviderBaseUrl);
       break;

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]