diff options
author | Christian Grothoff <christian@grothoff.org> | 2023-09-17 11:27:33 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2023-09-17 11:27:33 +0200 |
commit | 9ae46f367e606f9b3866b361459e05a71be9f310 (patch) | |
tree | 8ebc0edf84cc745a75b9c8ff4b550a40a08c9ca8 | |
parent | 535c57b2f9660e4178b31e2a0c47444b00348b71 (diff) |
first cut for API to get coin history
-rw-r--r-- | src/auditor/taler-helper-auditor-aggregation.c | 5 | ||||
-rw-r--r-- | src/auditor/taler-helper-auditor-coins.c | 5 | ||||
-rw-r--r-- | src/exchange/Makefile.am | 5 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd.c | 53 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_coins_get.c | 150 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_coins_get.h | 53 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_keys.c | 55 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_link.c | 25 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_link.h | 4 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_responses.c | 30 | ||||
-rw-r--r-- | src/exchange/taler-exchange-httpd_responses.h | 31 | ||||
-rw-r--r-- | src/exchangedb/pg_get_coin_transactions.c | 2 | ||||
-rw-r--r-- | src/exchangedb/pg_get_coin_transactions.h | 9 | ||||
-rw-r--r-- | src/exchangedb/test_exchangedb.c | 13 | ||||
-rw-r--r-- | src/include/taler_exchangedb_plugin.h | 6 |
15 files changed, 375 insertions, 71 deletions
diff --git a/src/auditor/taler-helper-auditor-aggregation.c b/src/auditor/taler-helper-auditor-aggregation.c index 72498ee07..81892c16c 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 bfdc11c7e..8c3d66b98 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 607ea919e..dded2b1f0 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 149c60ca3..ad4b50d23 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" @@ -369,6 +370,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 000000000..f7f0409c8 --- /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_coins_get.h b/src/exchange/taler-exchange-httpd_coins_get.h new file mode 100644 index 000000000..712269c3b --- /dev/null +++ b/src/exchange/taler-exchange-httpd_coins_get.h @@ -0,0 +1,53 @@ +/* + This file is part of TALER + 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 + 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.h + * @brief Handle GET /coins/$COIN_PUB requests + * @author Florian Dold + * @author Benedikt Mueller + * @author Christian Grothoff + */ +#ifndef TALER_EXCHANGE_HTTPD_COINS_GET_H +#define TALER_EXCHANGE_HTTPD_COINS_GET_H + +#include <microhttpd.h> +#include "taler-exchange-httpd.h" + + +/** + * 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 coin_pub public key of the coin + * @return MHD result code + */ +MHD_RESULT +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 2389a21dd..b9194d894 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 9b7e297bc..3d92a11a3 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 01679e877..255c0ca57 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 7d2d7a9b5..5ae232c36 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 a57fa495e..9b525929b 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 4f4317920..704e7c5c5 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 c95fd0947..d49b97bc6 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 56925acf0..217df2bb4 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 ee382ebe8..8fd9ce19f 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); |