aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2024-09-11 23:58:33 +0200
committerChristian Grothoff <christian@grothoff.org>2024-09-11 23:58:33 +0200
commitd12eb41bdf6af551c8af7c1c1fd2f6d2454a64e9 (patch)
treee60ee5d0c7cd193f4cdfe78bd4cd31e5725d157a /src
parentfad6728a3f36892bf3187fcddcabf5ae544bf56e (diff)
downloadexchange-d12eb41bdf6af551c8af7c1c1fd2f6d2454a64e9.tar.xz
implement long-polling on not kyc_ok for #9173
Diffstat (limited to 'src')
-rw-r--r--src/exchange/taler-exchange-httpd_deposits_get.c242
-rw-r--r--src/exchangedb/pg_lookup_transfer_by_deposit.c6
-rw-r--r--src/include/taler_util.h28
3 files changed, 149 insertions, 127 deletions
diff --git a/src/exchange/taler-exchange-httpd_deposits_get.c b/src/exchange/taler-exchange-httpd_deposits_get.c
index 174b428e0..014644f40 100644
--- a/src/exchange/taler-exchange-httpd_deposits_get.c
+++ b/src/exchange/taler-exchange-httpd_deposits_get.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2023 Taler Systems SA
+ Copyright (C) 2014-2024 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
@@ -25,6 +25,7 @@
#include <pthread.h>
#include "taler_dbevents.h"
#include "taler_json_lib.h"
+#include "taler_util.h"
#include "taler_mhd_lib.h"
#include "taler_signatures.h"
#include "taler-exchange-httpd_keys.h"
@@ -131,17 +132,16 @@ struct DepositWtidContext
struct TALER_EXCHANGEDB_KycStatus kyc;
/**
- * Set to #GNUNET_YES by #handle_wtid if the wire transfer is still pending
- * (and the above were not set).
- * Set to #GNUNET_SYSERR if there was a serious error.
- */
- enum GNUNET_GenericReturnValue pending;
-
- /**
* #GNUNET_YES if we were suspended, #GNUNET_SYSERR
* if we were woken up due to shutdown.
*/
enum GNUNET_GenericReturnValue suspended;
+
+ /**
+ * What do we long-poll for? Defaults to
+ * #TALER_DGLPT_OK if not given.
+ */
+ enum TALER_DepositGetLongPollTarget lpt;
};
@@ -180,15 +180,14 @@ TEH_deposits_get_cleanup ()
* A merchant asked for details about a deposit. Provide
* them. Generates the 200 reply.
*
- * @param connection connection to the client
* @param ctx details to respond with
* @return MHD result code
*/
static MHD_RESULT
reply_deposit_details (
- struct MHD_Connection *connection,
const struct DepositWtidContext *ctx)
{
+ struct MHD_Connection *connection = ctx->rc->connection;
struct TALER_ExchangePublicKeyP pub;
struct TALER_ExchangeSignatureP sig;
enum TALER_ErrorCode ec;
@@ -227,82 +226,6 @@ reply_deposit_details (
/**
- * Execute a "deposits" GET. Returns the transfer information
- * associated with the given deposit.
- *
- * If it returns a non-error code, the transaction logic MUST
- * NOT queue a MHD response. IF it returns an hard error, the
- * transaction logic MUST queue a MHD response and set @a mhd_ret. IF
- * it returns the soft error code, the function MAY be called again to
- * retry and MUST NOT queue a MHD response.
- *
- * @param cls closure of type `struct DepositWtidContext *`
- * @param connection MHD request which triggered the transaction
- * @param[out] mhd_ret set to MHD response status for @a connection,
- * if transaction failed (!)
- * @return transaction status
- */
-static enum GNUNET_DB_QueryStatus
-deposits_get_transaction (void *cls,
- struct MHD_Connection *connection,
- MHD_RESULT *mhd_ret)
-{
- struct DepositWtidContext *ctx = cls;
- enum GNUNET_DB_QueryStatus qs;
- bool pending;
- struct TALER_Amount fee;
-
- qs = TEH_plugin->lookup_transfer_by_deposit (
- TEH_plugin->cls,
- &ctx->h_contract_terms,
- &ctx->h_wire,
- &ctx->coin_pub,
- &ctx->merchant,
- &pending,
- &ctx->wtid,
- &ctx->execution_time,
- &ctx->coin_contribution,
- &fee,
- &ctx->kyc,
- &ctx->account_pub);
- if (0 > qs)
- {
- if (GNUNET_DB_STATUS_HARD_ERROR == qs)
- {
- GNUNET_break (0);
- *mhd_ret = TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_FETCH_FAILED,
- NULL);
- }
- return qs;
- }
- if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
- {
- *mhd_ret = TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_NOT_FOUND,
- TALER_EC_EXCHANGE_DEPOSITS_GET_NOT_FOUND,
- NULL);
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
-
- if (0 >
- TALER_amount_subtract (&ctx->coin_delta,
- &ctx->coin_contribution,
- &fee))
- {
- GNUNET_break (0);
- ctx->pending = GNUNET_SYSERR;
- return qs;
- }
- ctx->pending = (pending) ? GNUNET_YES : GNUNET_NO;
- return qs;
-}
-
-
-/**
* Function called on events received from Postgres.
* Wakes up long pollers.
*
@@ -349,55 +272,82 @@ handle_track_transaction_request (
struct DepositWtidContext *ctx)
{
struct MHD_Connection *connection = ctx->rc->connection;
+ enum GNUNET_DB_QueryStatus qs;
+ bool pending;
+ struct TALER_Amount fee;
- if ( (GNUNET_TIME_absolute_is_future (ctx->timeout)) &&
- (NULL == ctx->eh) )
+ qs = TEH_plugin->lookup_transfer_by_deposit (
+ TEH_plugin->cls,
+ &ctx->h_contract_terms,
+ &ctx->h_wire,
+ &ctx->coin_pub,
+ &ctx->merchant,
+ &pending,
+ &ctx->wtid,
+ &ctx->execution_time,
+ &ctx->coin_contribution,
+ &fee,
+ &ctx->kyc,
+ &ctx->account_pub);
+ if (0 > qs)
{
- struct TALER_CoinDepositEventP rep = {
- .header.size = htons (sizeof (rep)),
- .header.type = htons (TALER_DBEVENT_EXCHANGE_DEPOSIT_STATUS_CHANGED),
- .merchant_pub = ctx->merchant
- };
-
- ctx->eh = TEH_plugin->event_listen (
- TEH_plugin->cls,
- GNUNET_TIME_absolute_get_remaining (ctx->timeout),
- &rep.header,
- &db_event_cb,
- ctx);
- GNUNET_break (NULL != ctx->eh);
+ GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+ return TALER_MHD_reply_with_error (
+ connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "lookup_transfer_by_deposit");
}
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
{
- MHD_RESULT mhd_ret;
-
- if (GNUNET_OK !=
- TEH_DB_run_transaction (connection,
- "handle deposits GET",
- TEH_MT_REQUEST_OTHER,
- &mhd_ret,
- &deposits_get_transaction,
- ctx))
- return mhd_ret;
+ return TALER_MHD_reply_with_error (
+ connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_EXCHANGE_DEPOSITS_GET_NOT_FOUND,
+ NULL);
}
- if (GNUNET_SYSERR == ctx->pending)
+
+ if (0 >
+ TALER_amount_subtract (&ctx->coin_delta,
+ &ctx->coin_contribution,
+ &fee))
+ {
+ GNUNET_break (0);
return TALER_MHD_reply_with_error (
connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_INVARIANT_FAILURE,
"wire fees exceed aggregate in database");
- if (GNUNET_YES == ctx->pending)
+ }
+ if (pending)
{
- if ( (GNUNET_TIME_absolute_is_future (ctx->timeout)) &&
- (GNUNET_NO == ctx->suspended) )
+ if (GNUNET_TIME_absolute_is_future (ctx->timeout))
{
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Suspending request handling\n");
- GNUNET_CONTAINER_DLL_insert (dwc_head,
- dwc_tail,
- ctx);
- ctx->suspended = GNUNET_YES;
- MHD_suspend_connection (connection);
- return MHD_YES;
+ bool do_suspend = false;
+ switch (ctx->lpt)
+ {
+ case TALER_DGLPT_NONE:
+ break;
+ case TALER_DGLPT_KYC_REQUIRED_OR_OK:
+ do_suspend = ! ctx->kyc.ok;
+ break;
+ case TALER_DGLPT_OK:
+ do_suspend = true;
+ break;
+ }
+ if (do_suspend)
+ {
+ GNUNET_assert (GNUNET_NO == ctx->suspended);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Suspending request handling\n");
+ GNUNET_CONTAINER_DLL_insert (dwc_head,
+ dwc_tail,
+ ctx);
+ ctx->suspended = GNUNET_YES;
+ MHD_suspend_connection (connection);
+ return MHD_YES;
+ }
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"KYC required with row %llu\n",
@@ -422,8 +372,7 @@ handle_track_transaction_request (
GNUNET_JSON_pack_timestamp ("execution_time",
ctx->execution_time));
}
- return reply_deposit_details (connection,
- ctx);
+ return reply_deposit_details (ctx);
}
@@ -458,6 +407,7 @@ TEH_handler_deposits_get (struct TEH_RequestContext *rc,
{
ctx = GNUNET_new (struct DepositWtidContext);
ctx->rc = rc;
+ ctx->lpt = TALER_DGLPT_OK; /* default */
rc->rh_ctx = ctx;
rc->rh_cleaner = &dwc_cleaner;
@@ -518,6 +468,31 @@ TEH_handler_deposits_get (struct TEH_RequestContext *rc,
&ctx->merchant_sig);
TALER_MHD_parse_request_timeout (rc->connection,
&ctx->timeout);
+ {
+ uint64_t num = 0;
+ int val;
+
+ TALER_MHD_parse_request_number (rc->connection,
+ "lpt",
+ &num);
+ val = (int) num;
+ if ( (val < 0) ||
+ (val > TALER_DGLPT_MAX) )
+ {
+ /* Protocol violation, but we can be graceful and
+ just ignore the long polling! */
+ GNUNET_break_op (0);
+ val = TALER_DGLPT_NONE;
+ }
+ ctx->lpt = (enum TALER_DepositGetLongPollTarget) val;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Long polling for target %d with timeout %s\n",
+ val,
+ GNUNET_TIME_relative2s (
+ GNUNET_TIME_absolute_get_remaining (
+ ctx->timeout),
+ true));
+ }
TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++;
{
if (GNUNET_OK !=
@@ -535,6 +510,23 @@ TEH_handler_deposits_get (struct TEH_RequestContext *rc,
NULL);
}
}
+ if ( (GNUNET_TIME_absolute_is_future (ctx->timeout)) &&
+ (TALER_DGLPT_NONE != ctx->lpt) )
+ {
+ struct TALER_CoinDepositEventP rep = {
+ .header.size = htons (sizeof (rep)),
+ .header.type = htons (TALER_DBEVENT_EXCHANGE_DEPOSIT_STATUS_CHANGED),
+ .merchant_pub = ctx->merchant
+ };
+
+ ctx->eh = TEH_plugin->event_listen (
+ TEH_plugin->cls,
+ GNUNET_TIME_absolute_get_remaining (ctx->timeout),
+ &rep.header,
+ &db_event_cb,
+ ctx);
+ GNUNET_break (NULL != ctx->eh);
+ }
}
return handle_track_transaction_request (ctx);
diff --git a/src/exchangedb/pg_lookup_transfer_by_deposit.c b/src/exchangedb/pg_lookup_transfer_by_deposit.c
index e3c5cb737..d326feff7 100644
--- a/src/exchangedb/pg_lookup_transfer_by_deposit.c
+++ b/src/exchangedb/pg_lookup_transfer_by_deposit.c
@@ -107,6 +107,8 @@ TEH_PG_lookup_transfer_by_deposit (
"lookup_deposit_wtid",
params,
rs);
+ if (0 > qs)
+ return qs;
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
{
struct TALER_MerchantWireHashP wh;
@@ -126,8 +128,6 @@ TEH_PG_lookup_transfer_by_deposit (
qs = GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
GNUNET_PQ_cleanup_result (rs);
}
- if (0 > qs)
- return qs;
*pending = true;
memset (wtid,
0,
@@ -188,6 +188,8 @@ TEH_PG_lookup_transfer_by_deposit (
"get_deposit_without_wtid",
params,
rs2);
+ if (0 > qs)
+ return qs;
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
{
struct TALER_MerchantWireHashP wh;
diff --git a/src/include/taler_util.h b/src/include/taler_util.h
index b599ade76..3bb0b1c05 100644
--- a/src/include/taler_util.h
+++ b/src/include/taler_util.h
@@ -597,6 +597,34 @@ TALER_iban_validate (const char *iban);
/**
+ * Possible choices for long-polling for the deposit status.
+ */
+enum TALER_DepositGetLongPollTarget
+{
+ /**
+ * No long-polling.
+ */
+ TALER_DGLPT_NONE = 0,
+
+ /**
+ * Wait for KYC required/ACCEPTED state *or* for
+ * OK state.
+ */
+ TALER_DGLPT_KYC_REQUIRED_OR_OK = 1,
+
+ /**
+ * Wait for the OK-state only.
+ */
+ TALER_DGLPT_OK = 2,
+
+ /**
+ * Maximum allowed value.
+ */
+ TALER_DGLPT_MAX = 2
+};
+
+
+/**
* Possible choices for long-polling for the KYC status.
*/
enum TALER_EXCHANGE_KycLongPollTarget