[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.