gnunet-svn
[Top][All Lists]
Advanced

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

[taler-exchange] 02/02: first cut for API to get coin history


From: gnunet
Subject: [taler-exchange] 02/02: first cut for API to get coin history
Date: Sun, 17 Sep 2023 11:27:40 +0200

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

grothoff pushed a commit to branch master
in repository exchange.

commit 9ae46f367e606f9b3866b361459e05a71be9f310
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Sun Sep 17 11:27:33 2023 +0200

    first cut for API to get coin history
---
 src/auditor/taler-helper-auditor-aggregation.c     |   5 +
 src/auditor/taler-helper-auditor-coins.c           |   5 +
 src/exchange/Makefile.am                           |   5 +-
 src/exchange/taler-exchange-httpd.c                |  53 +++++++-
 src/exchange/taler-exchange-httpd_coins_get.c      | 150 +++++++++++++++++++++
 ...tpd_link.h => taler-exchange-httpd_coins_get.h} |  34 +++--
 src/exchange/taler-exchange-httpd_keys.c           |  55 ++------
 src/exchange/taler-exchange-httpd_link.c           |  25 +---
 src/exchange/taler-exchange-httpd_link.h           |   4 +-
 src/exchange/taler-exchange-httpd_responses.c      |  30 +++++
 src/exchange/taler-exchange-httpd_responses.h      |  31 ++++-
 src/exchangedb/pg_get_coin_transactions.c          |   2 +
 src/exchangedb/pg_get_coin_transactions.h          |   9 +-
 src/exchangedb/test_exchangedb.c                   |  13 +-
 src/include/taler_exchangedb_plugin.h              |   6 +
 15 files changed, 344 insertions(+), 83 deletions(-)

diff --git a/src/auditor/taler-helper-auditor-aggregation.c 
b/src/auditor/taler-helper-auditor-aggregation.c
index 72498ee0..81892c16 100644
--- a/src/auditor/taler-helper-auditor-aggregation.c
+++ b/src/auditor/taler-helper-auditor-aggregation.c
@@ -767,6 +767,7 @@ wire_transfer_information_cb (
   struct TALER_CoinPublicInfo coin;
   enum GNUNET_DB_QueryStatus qs;
   struct TALER_PaytoHashP hpt;
+  uint64_t etag = 0;
 
   TALER_payto_hash (account_pay_uri,
                     &hpt);
@@ -779,8 +780,12 @@ wire_transfer_information_cb (
                               "h-payto does not match payto URI");
   }
   /* Obtain coin's transaction history */
+  /* TODO: could use 'etag' mechanism to only fetch transactions
+     we did not yet process, instead of going over them
+     again and again.*/
   qs = TALER_ARL_edb->get_coin_transactions (TALER_ARL_edb->cls,
                                              coin_pub,
+                                             &etag,
                                              &tl);
   if ( (qs < 0) ||
        (NULL == tl) )
diff --git a/src/auditor/taler-helper-auditor-coins.c 
b/src/auditor/taler-helper-auditor-coins.c
index bfdc11c7..8c3d66b9 100644
--- a/src/auditor/taler-helper-auditor-coins.c
+++ b/src/auditor/taler-helper-auditor-coins.c
@@ -435,9 +435,14 @@ check_coin_history (const struct TALER_CoinSpendPublicKeyP 
*coin_pub,
   struct TALER_Amount refunded;
   struct TALER_Amount deposit_fee;
   bool have_refund;
+  uint64_t etag = 0;
 
+  /* TODO: could use 'etag' mechanism to only fetch transactions
+     we did not yet process, instead of going over them
+     again and again. */
   qs = TALER_ARL_edb->get_coin_transactions (TALER_ARL_edb->cls,
                                              coin_pub,
+                                             &etag,
                                              &tl);
   if (0 >= qs)
     return qs;
diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am
index 607ea919..dded2b1f 100644
--- a/src/exchange/Makefile.am
+++ b/src/exchange/Makefile.am
@@ -124,14 +124,15 @@ taler_exchange_wirewatch_LDADD = \
 
 taler_exchange_httpd_SOURCES = \
   taler-exchange-httpd.c taler-exchange-httpd.h \
+  taler-exchange-httpd_age-withdraw.c taler-exchange-httpd_age-withdraw.h \
+  taler-exchange-httpd_age-withdraw_reveal.c 
taler-exchange-httpd_age-withdraw_reveal.h \
   taler-exchange-httpd_auditors.c taler-exchange-httpd_auditors.h \
   taler-exchange-httpd_aml-decision.c taler-exchange-httpd_aml-decision.h \
   taler-exchange-httpd_aml-decision-get.c \
   taler-exchange-httpd_aml-decisions-get.c \
   taler-exchange-httpd_batch-deposit.c taler-exchange-httpd_batch-deposit.h \
   taler-exchange-httpd_batch-withdraw.c taler-exchange-httpd_batch-withdraw.h \
-  taler-exchange-httpd_age-withdraw.c taler-exchange-httpd_age-withdraw.h \
-  taler-exchange-httpd_age-withdraw_reveal.c 
taler-exchange-httpd_age-withdraw_reveal.h \
+  taler-exchange-httpd_coins_get.c taler-exchange-httpd_coins_get.h \
   taler-exchange-httpd_common_deposit.c taler-exchange-httpd_common_deposit.h \
   taler-exchange-httpd_common_kyc.c taler-exchange-httpd_common_kyc.h \
   taler-exchange-httpd_config.c taler-exchange-httpd_config.h \
diff --git a/src/exchange/taler-exchange-httpd.c 
b/src/exchange/taler-exchange-httpd.c
index 149c60ca..ad4b50d2 100644
--- a/src/exchange/taler-exchange-httpd.c
+++ b/src/exchange/taler-exchange-httpd.c
@@ -36,6 +36,7 @@
 #include "taler-exchange-httpd_auditors.h"
 #include "taler-exchange-httpd_batch-deposit.h"
 #include "taler-exchange-httpd_batch-withdraw.h"
+#include "taler-exchange-httpd_coins_get.h"
 #include "taler-exchange-httpd_config.h"
 #include "taler-exchange-httpd_contract.h"
 #include "taler-exchange-httpd_csr.h"
@@ -368,6 +369,55 @@ handle_post_coins (struct TEH_RequestContext *rc,
 }
 
 
+/**
+ * Handle a GET "/coins/$COIN_PUB[/$OP]" request.  Parses the "coin_pub"
+ * EdDSA key of the coin and demultiplexes based on $OP.
+ *
+ * @param rc request context
+ * @param root uploaded JSON data
+ * @param args array of additional options
+ * @return MHD result code
+ */
+static MHD_RESULT
+handle_get_coins (struct TEH_RequestContext *rc,
+                  const char *const args[2])
+{
+  struct TALER_CoinSpendPublicKeyP coin_pub;
+
+  if (NULL == args[0])
+  {
+    return TALER_MHD_reply_with_error (rc->connection,
+                                       MHD_HTTP_NOT_FOUND,
+                                       TALER_EC_GENERIC_ENDPOINT_UNKNOWN,
+                                       rc->url);
+  }
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_string_to_data (args[0],
+                                     strlen (args[0]),
+                                     &coin_pub,
+                                     sizeof (coin_pub)))
+  {
+    GNUNET_break_op (0);
+    return TALER_MHD_reply_with_error (rc->connection,
+                                       MHD_HTTP_BAD_REQUEST,
+                                       
TALER_EC_EXCHANGE_GENERIC_COINS_INVALID_COIN_PUB,
+                                       args[0]);
+  }
+
+  if (NULL == args[1])
+    return TEH_handler_coins_get (rc,
+                                  &coin_pub);
+  if (0 == strcmp (args[1],
+                   "link"))
+    return TEH_handler_link (rc,
+                             &coin_pub);
+  return TALER_MHD_reply_with_error (rc->connection,
+                                     MHD_HTTP_NOT_FOUND,
+                                     TALER_EC_GENERIC_ENDPOINT_UNKNOWN,
+                                     rc->url);
+}
+
+
 /**
  * Signature of functions that handle operations
  * authorized by AML officers.
@@ -1537,8 +1587,9 @@ handle_mhd_request (void *cls,
     {
       .url = "coins",
       .method = MHD_HTTP_METHOD_GET,
-      .handler.get = TEH_handler_link,
+      .handler.get = &handle_get_coins,
       .nargs = 2,
+      .nargs_is_upper_bound = true
     },
     /* refreshes/$RCH/reveal */
     {
diff --git a/src/exchange/taler-exchange-httpd_coins_get.c 
b/src/exchange/taler-exchange-httpd_coins_get.c
new file mode 100644
index 00000000..f7f0409c
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_coins_get.c
@@ -0,0 +1,150 @@
+/*
+  This file is part of TALER
+  Copyright (C) 2014-2023 Taler Systems SA
+
+  TALER is free software; you can redistribute it and/or modify it under the
+  terms of the GNU Affero General Public License as published by the Free 
Software
+  Foundation; either version 3, or (at your option) any later version.
+
+  TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more 
details.
+
+  You should have received a copy of the GNU Affero General Public License 
along with
+  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_coins_get.c
+ * @brief Handle GET /coins/$COIN_PUB requests
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <jansson.h>
+#include "taler_mhd_lib.h"
+#include "taler_json_lib.h"
+#include "taler_dbevents.h"
+#include "taler-exchange-httpd_keys.h"
+#include "taler-exchange-httpd_coins_get.h"
+#include "taler-exchange-httpd_responses.h"
+
+
+/**
+ * Add the headers we want to set for every /keys response.
+ *
+ * @param cls the key state to use
+ * @param[in,out] response the response to modify
+ */
+static void
+add_response_headers (void *cls,
+                      struct MHD_Response *response)
+{
+  (void) cls;
+  TALER_MHD_add_global_headers (response);
+}
+
+
+MHD_RESULT
+TEH_handler_coins_get (struct TEH_RequestContext *rc,
+                       const struct TALER_CoinSpendPublicKeyP *coin_pub)
+{
+  enum GNUNET_DB_QueryStatus qs;
+  struct TALER_EXCHANGEDB_TransactionList *tl;
+  const char *etags;
+  uint64_t etag = 0;
+
+  etags = MHD_lookup_connection_value (rc->connection,
+                                       MHD_HEADER_KIND,
+                                       MHD_HTTP_HEADER_IF_NONE_MATCH);
+  if (NULL != etags)
+  {
+    char dummy;
+    unsigned long long ev;
+
+    if (1 != sscanf (etags,
+                     "%llu%c",
+                     &ev,
+                     &dummy))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                  "Client send malformed `If-None-Match' header `%s'\n",
+                  etags);
+    }
+    else
+    {
+      etag = (uint64_t) ev;
+    }
+  }
+  qs = TEH_plugin->get_coin_transactions (TEH_plugin->cls,
+                                          coin_pub,
+                                          &etag,
+                                          &tl);
+  switch (qs)
+  {
+  case GNUNET_DB_STATUS_HARD_ERROR:
+    GNUNET_break (0);
+    return TALER_MHD_reply_with_error (rc->connection,
+                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                       TALER_EC_GENERIC_DB_FETCH_FAILED,
+                                       "get_coin_history");
+  case GNUNET_DB_STATUS_SOFT_ERROR:
+    GNUNET_break (0);   /* single-shot query should never have soft-errors */
+    return TALER_MHD_reply_with_error (rc->connection,
+                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                       TALER_EC_GENERIC_DB_SOFT_FAILURE,
+                                       "get_coin_history");
+  case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+    if (0 == etag)
+      return TALER_MHD_reply_with_error (rc->connection,
+                                         MHD_HTTP_NOT_FOUND,
+                                         
TALER_EC_EXCHANGE_GENERIC_COIN_UNKNOWN,
+                                         NULL);
+    return TEH_RESPONSE_reply_not_modified (rc->connection,
+                                            etags,
+                                            &add_response_headers,
+                                            NULL);
+  case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+    {
+      json_t *history;
+      char etagp[24];
+      MHD_RESULT ret;
+      struct MHD_Response *resp;
+
+      GNUNET_snprintf (etagp,
+                       sizeof (etagp),
+                       "%llu",
+                       (unsigned long long) etag);
+      history = TEH_RESPONSE_compile_transaction_history (coin_pub,
+                                                          tl);
+      TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
+                                              tl);
+      tl = NULL;
+      if (NULL == history)
+      {
+        GNUNET_break (0);
+        return TALER_MHD_reply_with_error (rc->connection,
+                                           MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                           
TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE,
+                                           "Failed to compile coin history");
+      }
+      resp = TALER_MHD_MAKE_JSON_PACK (
+        GNUNET_JSON_pack_array_steal ("history",
+                                      history));
+      GNUNET_break (MHD_YES ==
+                    MHD_add_response_header (resp,
+                                             MHD_HTTP_HEADER_ETAG,
+                                             etagp));
+      ret = MHD_queue_response (rc->connection,
+                                MHD_HTTP_OK,
+                                resp);
+      GNUNET_break (MHD_YES == ret);
+      MHD_destroy_response (resp);
+      return ret;
+    }
+  }
+  GNUNET_break (0);
+  return MHD_NO;
+}
+
+
+/* end of taler-exchange-httpd_coins_get.c */
diff --git a/src/exchange/taler-exchange-httpd_link.h 
b/src/exchange/taler-exchange-httpd_coins_get.h
similarity index 54%
copy from src/exchange/taler-exchange-httpd_link.h
copy to src/exchange/taler-exchange-httpd_coins_get.h
index 01679e87..712269c3 100644
--- a/src/exchange/taler-exchange-httpd_link.h
+++ b/src/exchange/taler-exchange-httpd_coins_get.h
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014-2017 Taler Systems SA
+  Copyright (C) 2023 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU Affero General Public License as published by the Free 
Software
@@ -14,30 +14,40 @@
   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */
 /**
- * @file taler-exchange-httpd_link.h
- * @brief Handle /coins/$COIN_PUB/link requests
+ * @file taler-exchange-httpd_coins_get.h
+ * @brief Handle GET /coins/$COIN_PUB requests
  * @author Florian Dold
  * @author Benedikt Mueller
  * @author Christian Grothoff
  */
-#ifndef TALER_EXCHANGE_HTTPD_LINK_H
-#define TALER_EXCHANGE_HTTPD_LINK_H
+#ifndef TALER_EXCHANGE_HTTPD_COINS_GET_H
+#define TALER_EXCHANGE_HTTPD_COINS_GET_H
 
-#include <gnunet/gnunet_util_lib.h>
 #include <microhttpd.h>
 #include "taler-exchange-httpd.h"
 
 
 /**
- * Handle a "/coins/$COIN_PUB/link" request.
+ * Shutdown reserves-get subsystem.  Resumes all
+ * suspended long-polling clients and cleans up
+ * data structures.
+ */
+void
+TEH_reserves_get_cleanup (void);
+
+
+/**
+ * Handle a GET "/coins/$COIN_PUB" request.  Parses the
+ * given "coins_pub" in @a args (which should contain the
+ * EdDSA public key of a reserve) and then respond with the
+ * transaction history of the coin.
  *
  * @param rc request context
- * @param args array of additional options (length: 2, first is the coin_pub, 
second must be "link")
+ * @param coin_pub public key of the coin
  * @return MHD result code
-  */
+ */
 MHD_RESULT
-TEH_handler_link (struct TEH_RequestContext *rc,
-                  const char *const args[2]);
-
+TEH_handler_coins_get (struct TEH_RequestContext *rc,
+                       const struct TALER_CoinSpendPublicKeyP *coin_pub);
 
 #endif
diff --git a/src/exchange/taler-exchange-httpd_keys.c 
b/src/exchange/taler-exchange-httpd_keys.c
index 2389a21d..b9194d89 100644
--- a/src/exchange/taler-exchange-httpd_keys.c
+++ b/src/exchange/taler-exchange-httpd_keys.c
@@ -2317,16 +2317,14 @@ add_denom_key_cb (void *cls,
 /**
  * Add the headers we want to set for every /keys response.
  *
- * @param ksh the key state to use
- * @param wsh wire state to use
+ * @param cls the key state to use
  * @param[in,out] response the response to modify
- * @return #GNUNET_OK on success
  */
-static enum GNUNET_GenericReturnValue
-setup_general_response_headers (struct TEH_KeyStateHandle *ksh,
-                                struct WireStateHandle *wsh,
+static void
+setup_general_response_headers (void *cls,
                                 struct MHD_Response *response)
 {
+  struct TEH_KeyStateHandle *ksh = cls;
   char dat[128];
 
   TALER_MHD_add_global_headers (response);
@@ -2352,7 +2350,7 @@ setup_general_response_headers (struct TEH_KeyStateHandle 
*ksh,
                                   ksh->rekey_frequency);
     a = GNUNET_TIME_relative_to_absolute (r);
     km = GNUNET_TIME_absolute_to_timestamp (a);
-    we = GNUNET_TIME_absolute_to_timestamp (wsh->cache_expiration);
+    we = GNUNET_TIME_absolute_to_timestamp (wire_state->cache_expiration);
     m = GNUNET_TIME_timestamp_min (we,
                                    km);
     TALER_MHD_get_date_string (m.abs_time,
@@ -2380,7 +2378,6 @@ setup_general_response_headers (struct TEH_KeyStateHandle 
*ksh,
                 MHD_add_response_header (response,
                                          MHD_HTTP_HEADER_CACHE_CONTROL,
                                          "public,max-age=3600"));
-  return GNUNET_OK;
 }
 
 
@@ -2688,10 +2685,8 @@ create_krd (struct TEH_KeyStateHandle *ksh,
                                          keys_json,
                                          MHD_RESPMEM_MUST_FREE);
     GNUNET_assert (NULL != krd.response_uncompressed);
-    GNUNET_assert (GNUNET_OK ==
-                   setup_general_response_headers (ksh,
-                                                   wsh,
-                                                   krd.response_uncompressed));
+    setup_general_response_headers (ksh,
+                                    krd.response_uncompressed);
     GNUNET_break (MHD_YES ==
                   MHD_add_response_header (krd.response_uncompressed,
                                            MHD_HTTP_HEADER_ETAG,
@@ -2711,10 +2706,8 @@ create_krd (struct TEH_KeyStateHandle *ksh,
                      MHD_add_response_header (krd.response_compressed,
                                               MHD_HTTP_HEADER_CONTENT_ENCODING,
                                               "deflate")) );
-    GNUNET_assert (GNUNET_OK ==
-                   setup_general_response_headers (ksh,
-                                                   wsh,
-                                                   krd.response_compressed));
+    setup_general_response_headers (ksh,
+                                    krd.response_compressed);
     /* Set cache control headers: our response varies depending on these 
headers */
     GNUNET_break (MHD_YES ==
                   MHD_add_response_header (wsh->wire_reply,
@@ -3877,9 +3870,7 @@ TEH_keys_get_handler (struct TEH_RequestContext *rc,
 {
   struct GNUNET_TIME_Timestamp last_issue_date;
   const char *etag;
-  struct WireStateHandle *wsh;
 
-  wsh = get_wire_state ();
   etag = MHD_lookup_connection_value (rc->connection,
                                       MHD_HEADER_KIND,
                                       MHD_HTTP_HEADER_IF_NONE_MATCH);
@@ -3967,29 +3958,11 @@ TEH_keys_get_handler (struct TEH_RequestContext *rc,
     if ( (NULL != etag) &&
          (0 == strcmp (etag,
                        krd->etag)) )
-    {
-      MHD_RESULT ret;
-      struct MHD_Response *resp;
-
-      resp = MHD_create_response_from_buffer (0,
-                                              NULL,
-                                              MHD_RESPMEM_PERSISTENT);
-      TALER_MHD_add_global_headers (resp);
-      GNUNET_break (GNUNET_OK ==
-                    setup_general_response_headers (ksh,
-                                                    wsh,
-                                                    resp));
-      GNUNET_break (MHD_YES ==
-                    MHD_add_response_header (resp,
-                                             MHD_HTTP_HEADER_ETAG,
-                                             krd->etag));
-      ret = MHD_queue_response (rc->connection,
-                                MHD_HTTP_NOT_MODIFIED,
-                                resp);
-      GNUNET_break (MHD_YES == ret);
-      MHD_destroy_response (resp);
-      return ret;
-    }
+      return TEH_RESPONSE_reply_not_modified (rc->connection,
+                                              krd->etag,
+                                              &setup_general_response_headers,
+                                              ksh);
+
     return MHD_queue_response (rc->connection,
                                MHD_HTTP_OK,
                                (MHD_YES ==
diff --git a/src/exchange/taler-exchange-httpd_link.c 
b/src/exchange/taler-exchange-httpd_link.c
index 9b7e297b..3d92a11a 100644
--- a/src/exchange/taler-exchange-httpd_link.c
+++ b/src/exchange/taler-exchange-httpd_link.c
@@ -39,7 +39,7 @@ struct HTD_Context
   /**
    * Public key of the coin for which we are running link.
    */
-  struct TALER_CoinSpendPublicKeyP coin_pub;
+  const struct TALER_CoinSpendPublicKeyP *coin_pub;
 
   /**
    * Json array with transfer data we collect.
@@ -153,7 +153,7 @@ link_transaction (void *cls,
   enum GNUNET_DB_QueryStatus qs;
 
   qs = TEH_plugin->get_link_data (TEH_plugin->cls,
-                                  &ctx->coin_pub,
+                                  ctx->coin_pub,
                                   &handle_link_data,
                                   ctx);
   if (NULL == ctx->mlist)
@@ -178,26 +178,13 @@ link_transaction (void *cls,
 
 MHD_RESULT
 TEH_handler_link (struct TEH_RequestContext *rc,
-                  const char *const args[2])
+                  const struct TALER_CoinSpendPublicKeyP *coin_pub)
 {
-  struct HTD_Context ctx;
+  struct HTD_Context ctx = {
+    .coin_pub = coin_pub
+  };
   MHD_RESULT mhd_ret;
 
-  memset (&ctx,
-          0,
-          sizeof (ctx));
-  if (GNUNET_OK !=
-      GNUNET_STRINGS_string_to_data (args[0],
-                                     strlen (args[0]),
-                                     &ctx.coin_pub,
-                                     sizeof (ctx.coin_pub)))
-  {
-    GNUNET_break_op (0);
-    return TALER_MHD_reply_with_error (rc->connection,
-                                       MHD_HTTP_BAD_REQUEST,
-                                       
TALER_EC_EXCHANGE_GENERIC_COINS_INVALID_COIN_PUB,
-                                       args[0]);
-  }
   ctx.mlist = json_array ();
   GNUNET_assert (NULL != ctx.mlist);
   if (GNUNET_OK !=
diff --git a/src/exchange/taler-exchange-httpd_link.h 
b/src/exchange/taler-exchange-httpd_link.h
index 01679e87..255c0ca5 100644
--- a/src/exchange/taler-exchange-httpd_link.h
+++ b/src/exchange/taler-exchange-httpd_link.h
@@ -32,12 +32,12 @@
  * Handle a "/coins/$COIN_PUB/link" request.
  *
  * @param rc request context
- * @param args array of additional options (length: 2, first is the coin_pub, 
second must be "link")
+ * @param coin_pub the coin public key
  * @return MHD result code
   */
 MHD_RESULT
 TEH_handler_link (struct TEH_RequestContext *rc,
-                  const char *const args[2]);
+                  const struct TALER_CoinSpendPublicKeyP *coin_pub);
 
 
 #endif
diff --git a/src/exchange/taler-exchange-httpd_responses.c 
b/src/exchange/taler-exchange-httpd_responses.c
index 7d2d7a9b..5ae232c3 100644
--- a/src/exchange/taler-exchange-httpd_responses.c
+++ b/src/exchange/taler-exchange-httpd_responses.c
@@ -653,6 +653,7 @@ TEH_RESPONSE_reply_coin_insufficient_funds (
   struct TALER_EXCHANGEDB_TransactionList *tl;
   enum GNUNET_DB_QueryStatus qs;
   json_t *history;
+  uint64_t etag = 0;
 
   TEH_plugin->rollback (TEH_plugin->cls);
   if (GNUNET_OK !=
@@ -667,6 +668,7 @@ TEH_RESPONSE_reply_coin_insufficient_funds (
   }
   qs = TEH_plugin->get_coin_transactions (TEH_plugin->cls,
                                           coin_pub,
+                                          &etag,
                                           &tl);
   TEH_plugin->rollback (TEH_plugin->cls);
   if (0 > qs)
@@ -1187,4 +1189,32 @@ TEH_RESPONSE_reply_aml_blocked (struct MHD_Connection 
*connection,
 }
 
 
+MHD_RESULT
+TEH_RESPONSE_reply_not_modified (
+  struct MHD_Connection *connection,
+  const char *etags,
+  TEH_RESPONSE_SetHeaders cb,
+  void *cb_cls)
+{
+  MHD_RESULT ret;
+  struct MHD_Response *resp;
+
+  resp = MHD_create_response_from_buffer (0,
+                                          NULL,
+                                          MHD_RESPMEM_PERSISTENT);
+  cb (cb_cls,
+      resp);
+  GNUNET_break (MHD_YES ==
+                MHD_add_response_header (resp,
+                                         MHD_HTTP_HEADER_ETAG,
+                                         etags));
+  ret = MHD_queue_response (connection,
+                            MHD_HTTP_NOT_MODIFIED,
+                            resp);
+  GNUNET_break (MHD_YES == ret);
+  MHD_destroy_response (resp);
+  return ret;
+}
+
+
 /* end of taler-exchange-httpd_responses.c */
diff --git a/src/exchange/taler-exchange-httpd_responses.h 
b/src/exchange/taler-exchange-httpd_responses.h
index a57fa495..9b525929 100644
--- a/src/exchange/taler-exchange-httpd_responses.h
+++ b/src/exchange/taler-exchange-httpd_responses.h
@@ -1,6 +1,6 @@
 /*
   This file is part of TALER
-  Copyright (C) 2014-2022 Taler Systems SA
+  Copyright (C) 2014-2023 Taler Systems SA
 
   TALER is free software; you can redistribute it and/or modify it under the
   terms of the GNU Affero General Public License as published by the Free 
Software
@@ -226,4 +226,33 @@ TEH_RESPONSE_compile_transaction_history (
   const struct TALER_EXCHANGEDB_TransactionList *tl);
 
 
+/**
+ * Callback used to set headers in a response.
+ *
+ * @param cls closure
+ * @param[in,out] resp response to modify
+ */
+typedef void
+(*TEH_RESPONSE_SetHeaders)(void *cls,
+                           struct MHD_Response *resp);
+
+
+/**
+ * Generate a HTTP "Not modified" response with the
+ * given @a etags.
+ *
+ * @param connection connection to queue response on
+ * @param etags ETag header to set
+ * @param cb callback to modify response headers
+ * @param cb_cls closure for @a cb
+ * @return MHD result code
+ */
+MHD_RESULT
+TEH_RESPONSE_reply_not_modified (
+  struct MHD_Connection *connection,
+  const char *etags,
+  TEH_RESPONSE_SetHeaders cb,
+  void *cb_cls);
+
+
 #endif
diff --git a/src/exchangedb/pg_get_coin_transactions.c 
b/src/exchangedb/pg_get_coin_transactions.c
index 4f431792..704e7c5c 100644
--- a/src/exchangedb/pg_get_coin_transactions.c
+++ b/src/exchangedb/pg_get_coin_transactions.c
@@ -684,6 +684,7 @@ enum GNUNET_DB_QueryStatus
 TEH_PG_get_coin_transactions (
   void *cls,
   const struct TALER_CoinSpendPublicKeyP *coin_pub,
+  uint64_t *etag,
   struct TALER_EXCHANGEDB_TransactionList **tlp)
 {
   struct PostgresClosure *pg = cls;
@@ -729,6 +730,7 @@ TEH_PG_get_coin_transactions (
     .db_cls = cls
   };
 
+  *etag = 0;  // FIXME: etag not yet implemented!
   PREPARE (pg, // done!
            "get_deposit_with_coin_pub",
            "SELECT"
diff --git a/src/exchangedb/pg_get_coin_transactions.h 
b/src/exchangedb/pg_get_coin_transactions.h
index c95fd094..d49b97bc 100644
--- a/src/exchangedb/pg_get_coin_transactions.h
+++ b/src/exchangedb/pg_get_coin_transactions.h
@@ -1,6 +1,6 @@
 /*
    This file is part of TALER
-   Copyright (C) 2022 Taler Systems SA
+   Copyright (C) 2022, 2023 Taler Systems SA
 
    TALER is free software; you can redistribute it and/or modify it under the
    terms of the GNU General Public License as published by the Free Software
@@ -29,16 +29,21 @@
 /**
  * Compile a list of all (historic) transactions performed with the given coin
  * (/refresh/melt, /deposit, /refund and /recoup operations).
+ * Should return 0 if @a etag is already current, otherwise
+ * return the full history and update @a etag. @a etag
+ * should be set to the last row ID of the given coin
+ * in the coin history table.
  *
  * @param cls the `struct PostgresClosure` with the plugin-specific state
  * @param coin_pub coin to investigate
- * @param[out] tlp set to list of transactions, NULL if coin is fresh
+ * @param[in,out] etag known etag, updated to current etag * @param[out] tlp 
set to list of transactions, NULL if coin is fresh
  * @return database transaction status
  */
 enum GNUNET_DB_QueryStatus
 TEH_PG_get_coin_transactions (
   void *cls,
   const struct TALER_CoinSpendPublicKeyP *coin_pub,
+  uint64_t *etag,
   struct TALER_EXCHANGEDB_TransactionList **tlp);
 
 #endif
diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c
index 56925acf..217df2bb 100644
--- a/src/exchangedb/test_exchangedb.c
+++ b/src/exchangedb/test_exchangedb.c
@@ -1723,9 +1723,11 @@ run (void *cls)
       /* Just to test fetching a coin with melt history */
       struct TALER_EXCHANGEDB_TransactionList *tl;
       enum GNUNET_DB_QueryStatus qs;
+      uint64_t etag = 0;
 
       qs = plugin->get_coin_transactions (plugin->cls,
                                           &refresh.coin.coin_pub,
+                                          &etag,
                                           &tl);
       FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs);
       plugin->free_coin_transaction_list (plugin->cls,
@@ -1972,9 +1974,14 @@ run (void *cls)
                                                   &audit_refund_cb,
                                                   NULL));
   FAILIF (1 != auditor_row_cnt);
-  qs = plugin->get_coin_transactions (plugin->cls,
-                                      &refund.coin.coin_pub,
-                                      &tl);
+  {
+    uint64_t etag = 0;
+
+    qs = plugin->get_coin_transactions (plugin->cls,
+                                        &refund.coin.coin_pub,
+                                        &etag,
+                                        &tl);
+  }
   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs);
   GNUNET_assert (NULL != tl);
   matched = 0;
diff --git a/src/include/taler_exchangedb_plugin.h 
b/src/include/taler_exchangedb_plugin.h
index ee382ebe..8fd9ce19 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -4696,15 +4696,21 @@ struct TALER_EXCHANGEDB_Plugin
   /**
    * Compile a list of all (historic) transactions performed
    * with the given coin (melt, refund, recoup and deposit operations).
+   * Should return 0 if @a etag is already current, otherwise
+   * return the full history and update @a etag. @a etag
+   * should be set to the last row ID of the given coin
+   * in the coin history table.
    *
    * @param cls the @e cls of this struct with the plugin-specific state
    * @param coin_pub coin to investigate
+   * @param[in,out] etag known etag, updated to current etag
    * @param[out] tlp set to list of transactions, NULL if coin is fresh
    * @return database transaction status
    */
   enum GNUNET_DB_QueryStatus
   (*get_coin_transactions)(void *cls,
                            const struct TALER_CoinSpendPublicKeyP *coin_pub,
+                           uint64_t *etag,
                            struct TALER_EXCHANGEDB_TransactionList **tlp);
 
 

-- 
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]