[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] [taler-merchant] 02/02: clean up code duplication in checki
From: |
gnunet |
Subject: |
[GNUnet-SVN] [taler-merchant] 02/02: clean up code duplication in checking of tipping reserve status by moving shared logic to helper function |
Date: |
Thu, 04 Apr 2019 23:15:00 +0200 |
This is an automated email from the git hooks/post-receive script.
grothoff pushed a commit to branch master
in repository merchant.
commit 3a38124fa780be01a06bb7d3a3c7d51824f256cf
Author: Christian Grothoff <address@hidden>
AuthorDate: Thu Apr 4 23:14:52 2019 +0200
clean up code duplication in checking of tipping reserve status by moving
shared logic to helper function
---
src/backend/Makefile.am | 1 +
src/backend/taler-merchant-httpd_responses.c | 44 +--
src/backend/taler-merchant-httpd_tip-authorize.c | 226 ++---------
src/backend/taler-merchant-httpd_tip-query.c | 418 ++++-----------------
.../taler-merchant-httpd_tip-reserve-helper.c | 329 ++++++++++++++++
.../taler-merchant-httpd_tip-reserve-helper.h | 137 +++++++
src/lib/test_merchant_api_new.c | 4 +-
7 files changed, 582 insertions(+), 577 deletions(-)
diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am
index 960dc46..67ba825 100644
--- a/src/backend/Makefile.am
+++ b/src/backend/Makefile.am
@@ -25,6 +25,7 @@ taler_merchant_httpd_SOURCES = \
taler-merchant-httpd_tip-authorize.c taler-merchant-httpd_tip-authorize.h \
taler-merchant-httpd_tip-pickup.c taler-merchant-httpd_tip-pickup.h \
taler-merchant-httpd_tip-query.c taler-merchant-httpd_tip-query.h \
+ taler-merchant-httpd_tip-reserve-helper.c
taler-merchant-httpd_tip-reserve-helper.h \
taler-merchant-httpd_track-transaction.c
taler-merchant-httpd_track-transaction.h \
taler-merchant-httpd_track-transfer.c taler-merchant-httpd_track-transfer.h \
taler-merchant-httpd_refund.c taler-merchant-httpd_refund.h \
diff --git a/src/backend/taler-merchant-httpd_responses.c
b/src/backend/taler-merchant-httpd_responses.c
index 71d0406..19fa9fe 100644
--- a/src/backend/taler-merchant-httpd_responses.c
+++ b/src/backend/taler-merchant-httpd_responses.c
@@ -43,14 +43,14 @@ TMH_RESPONSE_make_json (const json_t *json)
char *json_str;
json_str = json_dumps (json,
- JSON_INDENT(2));
+ JSON_INDENT(2));
if (NULL == json_str)
{
GNUNET_break (0);
return NULL;
}
resp = MHD_create_response_from_buffer (strlen (json_str),
- json_str,
+ json_str,
MHD_RESPMEM_MUST_FREE);
if (NULL == resp)
{
@@ -152,9 +152,9 @@ TMH_RESPONSE_reply_json_pack (struct MHD_Connection
*connection,
va_start (argp, fmt);
json = json_vpack_ex (&jerror,
- 0,
- fmt,
- argp);
+ 0,
+ fmt,
+ argp);
va_end (argp);
if (NULL == json)
{
@@ -182,10 +182,10 @@ TMH_RESPONSE_reply_json_pack (struct MHD_Connection
*connection,
*/
struct MHD_Response *
TMH_RESPONSE_make_error (enum TALER_ErrorCode ec,
- const char *hint)
+ const char *hint)
{
return TMH_RESPONSE_make_json_pack ("{s:I, s:s}",
- "code", (json_int_t) ec,
+ "code", (json_int_t) ec,
"hint", hint);
}
@@ -200,13 +200,13 @@ TMH_RESPONSE_make_error (enum TALER_ErrorCode ec,
*/
int
TMH_RESPONSE_reply_internal_error (struct MHD_Connection *connection,
- enum TALER_ErrorCode ec,
+ enum TALER_ErrorCode ec,
const char *hint)
{
return TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
"{s:I, s:s}",
- "code", (json_int_t) ec,
+ "code", (json_int_t) ec,
"hint", hint);
}
@@ -255,7 +255,7 @@ TMH_RESPONSE_reply_rc (struct MHD_Connection *connection,
return TMH_RESPONSE_reply_json_pack (connection,
response_code,
"{s:I, s:s}",
- "code", (json_int_t) ec,
+ "code", (json_int_t) ec,
"error", msg);
}
@@ -272,7 +272,7 @@ TMH_RESPONSE_reply_invalid_json (struct MHD_Connection
*connection)
return TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:I, s:s}",
- "code", (json_int_t)
TALER_EC_JSON_INVALID,
+ "code", (json_int_t)
TALER_EC_JSON_INVALID,
"error", "invalid json");
}
@@ -288,13 +288,13 @@ TMH_RESPONSE_reply_invalid_json (struct MHD_Connection
*connection)
*/
int
TMH_RESPONSE_reply_not_found (struct MHD_Connection *connection,
- enum TALER_ErrorCode ec,
+ enum TALER_ErrorCode ec,
const char *object)
{
return TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_NOT_FOUND,
"{s:I, s:s}",
- "code", (json_int_t) ec,
+ "code", (json_int_t) ec,
"error", object);
}
@@ -309,13 +309,13 @@ TMH_RESPONSE_reply_not_found (struct MHD_Connection
*connection,
*/
int
TMH_RESPONSE_reply_bad_request (struct MHD_Connection *connection,
- enum TALER_ErrorCode ec,
+ enum TALER_ErrorCode ec,
const char *issue)
{
return TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:I, s:s}",
- "code", (json_int_t) ec,
+ "code", (json_int_t) ec,
"error", issue);
}
@@ -347,13 +347,13 @@ TMH_RESPONSE_add_global_headers (struct MHD_Response
*response)
*/
int
TMH_RESPONSE_reply_external_error (struct MHD_Connection *connection,
- enum TALER_ErrorCode ec,
+ enum TALER_ErrorCode ec,
const char *hint)
{
return TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:I, s:s}",
- "code", (json_int_t) ec,
+ "code", (json_int_t) ec,
"hint", hint);
}
@@ -368,14 +368,14 @@ TMH_RESPONSE_reply_external_error (struct MHD_Connection
*connection,
*/
int
TMH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection,
- enum TALER_ErrorCode ec,
+ enum TALER_ErrorCode ec,
const char *param_name)
{
return TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:s, s:I, s:s}",
"error", "missing parameter",
- "code", (json_int_t) ec,
+ "code", (json_int_t) ec,
"parameter", param_name);
}
@@ -390,14 +390,14 @@ TMH_RESPONSE_reply_arg_missing (struct MHD_Connection
*connection,
*/
int
TMH_RESPONSE_reply_arg_invalid (struct MHD_Connection *connection,
- enum TALER_ErrorCode ec,
- const char *param_name)
+ enum TALER_ErrorCode ec,
+ const char *param_name)
{
return TMH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
"{s:s, s:I, s:s}",
"error", "invalid parameter",
- "code", (json_int_t) ec,
+ "code", (json_int_t) ec,
"parameter", param_name);
}
diff --git a/src/backend/taler-merchant-httpd_tip-authorize.c
b/src/backend/taler-merchant-httpd_tip-authorize.c
index 9301df9..ad19616 100644
--- a/src/backend/taler-merchant-httpd_tip-authorize.c
+++ b/src/backend/taler-merchant-httpd_tip-authorize.c
@@ -28,6 +28,7 @@
#include "taler-merchant-httpd_exchanges.h"
#include "taler-merchant-httpd_responses.h"
#include "taler-merchant-httpd_tip-authorize.h"
+#include "taler-merchant-httpd_tip-reserve-helper.h"
struct TipAuthContext
@@ -44,11 +45,6 @@ struct TipAuthContext
void *json_parse_context;
/**
- * HTTP connection we are handling.
- */
- struct MHD_Connection *connection;
-
- /**
* Merchant instance to use.
*/
const char *instance;
@@ -74,20 +70,9 @@ struct TipAuthContext
json_t *root;
/**
- * Handle to pending /reserve/status request.
- */
- struct TALER_EXCHANGE_ReserveStatusHandle *rsh;
-
- /**
- * Handle for operation to obtain exchange handle.
- */
- struct TMH_EXCHANGES_FindOperation *fo;
-
- /**
- * Reserve expiration time as provided by the exchange.
- * Set in #exchange_cont.
+ * Context for checking the tipping reserve's status.
*/
- struct GNUNET_TIME_Relative idle_reserve_expiration_time;
+ struct CheckTipReserve ctr;
/**
* Tip amount requested.
@@ -95,11 +80,6 @@ struct TipAuthContext
struct TALER_Amount amount;
/**
- * Private key used by this merchant for the tipping reserve.
- */
- struct TALER_ReservePrivateKeyP reserve_priv;
-
- /**
* Flag set to #GNUNET_YES when we have tried /reserve/status of the
* tipping reserve already.
*/
@@ -110,10 +90,6 @@ struct TipAuthContext
*/
int parsed_json;
- /**
- * Error code witnessing what the Exchange complained about.
- */
- enum TALER_ErrorCode exchange_ec;
};
@@ -132,152 +108,13 @@ cleanup_tac (struct TM_HandlerContext *hc)
json_decref (tac->root);
tac->root = NULL;
}
- if (NULL != tac->rsh)
- {
- TALER_EXCHANGE_reserve_status_cancel (tac->rsh);
- tac->rsh = NULL;
- }
- if (NULL != tac->fo)
- {
- TMH_EXCHANGES_find_exchange_cancel (tac->fo);
- tac->fo = NULL;
- }
+ TMH_check_tip_reserve_cleanup (&tac->ctr);
TMH_PARSE_post_cleanup_callback (tac->json_parse_context);
GNUNET_free (tac);
}
/**
- * Function called with the result of the /reserve/status request
- * for the tipping reserve. Update our database balance with the
- * result.
- *
- * @param cls closure with a `struct TipAuthContext *'
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful
status request
- * 0 if the exchange's reply is bogus (fails to follow the
protocol)
- * @param ec taler-specific error code, #TALER_EC_NONE on success
- * @param[in] json original response in JSON format (useful only for
diagnostics)
- * @param balance current balance in the reserve, NULL on error
- * @param history_length number of entries in the transaction history, 0 on
error
- * @param history detailed transaction history, NULL on error
- */
-static void
-handle_status (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- const json_t *json,
- const struct TALER_Amount *balance,
- unsigned int history_length,
- const struct TALER_EXCHANGE_ReserveHistory *history)
-{
- struct TipAuthContext *tac = cls;
-
- tac->rsh = NULL;
- if (MHD_HTTP_OK != http_status)
- {
-
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Failed to obtain tipping reserve status from exchange
(%u/%d)\n"),
- http_status,
- ec);
- tac->exchange_ec = ec;
- MHD_resume_connection (tac->connection);
- TMH_trigger_daemon ();
- return;
- }
-
- /* Update DB based on status! */
- for (unsigned int i=0;i<history_length;i++)
- {
- switch (history[i].type)
- {
- case TALER_EXCHANGE_RTT_DEPOSIT:
- {
- enum GNUNET_DB_QueryStatus qs;
- struct GNUNET_HashCode uuid;
- struct GNUNET_TIME_Absolute expiration;
-
- expiration = GNUNET_TIME_absolute_add
(history[i].details.in_details.timestamp,
-
tac->idle_reserve_expiration_time);
- GNUNET_CRYPTO_hash (history[i].details.in_details.wire_reference,
- history[i].details.in_details.wire_reference_size,
- &uuid);
- qs = db->enable_tip_reserve_TR (db->cls,
- &tac->reserve_priv,
- &uuid,
- &history[i].amount,
- expiration);
- if (0 > qs)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Database error updating tipping reserve status:
%d\n"),
- qs);
- }
- }
- break;
- case TALER_EXCHANGE_RTT_WITHDRAWAL:
- /* expected */
- break;
- case TALER_EXCHANGE_RTT_PAYBACK:
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Encountered unsupported /payback operation on tipping
reserve\n"));
- break;
- case TALER_EXCHANGE_RTT_CLOSE:
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Exchange closed reserve (due to expiration), balance
calulation is likely wrong. Please create a fresh reserve.\n"));
- break;
- }
- }
- /* Finally, resume processing */
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Resuming HTTP processing\n");
- MHD_resume_connection (tac->connection);
- TMH_trigger_daemon ();
-}
-
-
-/**
- * Function called with the result of a #TMH_EXCHANGES_find_exchange()
- * operation.
- *
- * @param cls closure with a `struct TipAuthContext *'
- * @param eh handle to the exchange context
- * @param wire_fee current applicable wire fee for dealing with @a eh, NULL if
not available
- * @param exchange_trusted #GNUNET_YES if this exchange is trusted by config
- */
-static void
-exchange_cont (void *cls,
- struct TALER_EXCHANGE_Handle *eh,
- const struct TALER_Amount *wire_fee,
- int exchange_trusted)
-{
- struct TipAuthContext *tac = cls;
- struct TALER_ReservePublicKeyP reserve_pub;
- const struct TALER_EXCHANGE_Keys *keys;
-
- tac->fo = NULL;
- if (NULL == eh)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Failed to contact exchange configured for tipping!\n"));
- MHD_resume_connection (tac->connection);
- TMH_trigger_daemon ();
- return;
- }
- keys = TALER_EXCHANGE_get_keys (eh);
- GNUNET_assert (NULL != keys);
- tac->idle_reserve_expiration_time
- = keys->reserve_closing_delay;
- GNUNET_CRYPTO_eddsa_key_get_public (&tac->reserve_priv.eddsa_priv,
- &reserve_pub.eddsa_pub);
- tac->rsh = TALER_EXCHANGE_reserve_status (eh,
- &reserve_pub,
- &handle_status,
- tac);
-}
-
-
-/**
* Handle a "/tip-authorize" request.
*
* @param rh context of the handler
@@ -305,14 +142,22 @@ MH_handler_tip_authorize (struct TMH_RequestHandler *rh,
{
tac = GNUNET_new (struct TipAuthContext);
tac->hc.cc = &cleanup_tac;
- tac->connection = connection;
+ tac->ctr.connection = connection;
*connection_cls = tac;
}
else
{
tac = *connection_cls;
}
-
+ if (NULL != tac->ctr.response)
+ {
+ res = MHD_queue_response (connection,
+ tac->ctr.response_code,
+ tac->ctr.response);
+ MHD_destroy_response (tac->ctr.response);
+ tac->ctr.response = NULL;
+ return res;
+ }
if (GNUNET_NO == tac->parsed_json)
{
struct GNUNET_JSON_Specification spec[] = {
@@ -336,13 +181,16 @@ MH_handler_tip_authorize (struct TMH_RequestHandler *rh,
(NULL == tac->root) )
return MHD_YES;
- if (NULL == json_object_get (tac->root, "pickup_url"))
+ if (NULL == json_object_get (tac->root,
+ "pickup_url"))
{
char *pickup_url = TALER_url_absolute_mhd (connection,
"/public/tip-pickup",
NULL);
GNUNET_assert (NULL != pickup_url);
- json_object_set_new (tac->root, "pickup_url", json_string (pickup_url));
+ json_object_set_new (tac->root,
+ "pickup_url",
+ json_string (pickup_url));
GNUNET_free (pickup_url);
}
@@ -364,8 +212,8 @@ MH_handler_tip_authorize (struct TMH_RequestHandler *rh,
"Instance `%s' not configured\n",
tac->instance);
return TMH_RESPONSE_reply_not_found (connection,
-
TALER_EC_TIP_AUTHORIZE_INSTANCE_UNKNOWN,
- "unknown instance");
+
TALER_EC_TIP_AUTHORIZE_INSTANCE_UNKNOWN,
+ "unknown instance");
}
if (NULL == mi->tip_exchange)
{
@@ -373,10 +221,10 @@ MH_handler_tip_authorize (struct TMH_RequestHandler *rh,
"Instance `%s' not configured for tipping\n",
tac->instance);
return TMH_RESPONSE_reply_not_found (connection,
-
TALER_EC_TIP_AUTHORIZE_INSTANCE_DOES_NOT_TIP,
- "exchange for tipping not configured
for the instance");
+
TALER_EC_TIP_AUTHORIZE_INSTANCE_DOES_NOT_TIP,
+ "exchange for tipping not configured
for the instance");
}
- tac->reserve_priv = mi->tip_reserve;
+ tac->ctr.reserve_priv = mi->tip_reserve;
ec = db->authorize_tip_TR (db->cls,
tac->justification,
&tac->amount,
@@ -390,17 +238,15 @@ MH_handler_tip_authorize (struct TMH_RequestHandler *rh,
if ( (TALER_EC_TIP_AUTHORIZE_INSUFFICIENT_FUNDS == ec) &&
(GNUNET_NO == tac->checked_status) )
{
- MHD_suspend_connection (connection);
tac->checked_status = GNUNET_YES;
- tac->fo = TMH_EXCHANGES_find_exchange (mi->tip_exchange,
- NULL,
- &exchange_cont,
- tac);
+ tac->ctr.none_authorized = GNUNET_YES;
+ TMH_check_tip_reserve (&tac->ctr,
+ mi->tip_exchange);
return MHD_YES;
}
/* handle irrecoverable errors */
- if (TALER_EC_NONE != (ec | tac->exchange_ec))
+ if (TALER_EC_NONE != ec)
{
unsigned int rc;
const char *msg;
@@ -425,22 +271,6 @@ MH_handler_tip_authorize (struct TMH_RequestHandler *rh,
break;
}
- /* If the exchange complained earlier, we do
- * override what the database returned. */
- switch (tac->exchange_ec)
- {
- case TALER_EC_RESERVE_STATUS_UNKNOWN:
- rc = MHD_HTTP_NOT_FOUND;
- msg = "Exchange does not find any reserve having this key";
- /* We override what the DB returned, as an exchange error
- * is more important. */
- ec = TALER_EC_TIP_AUTHORIZE_RESERVE_UNKNOWN;
- break;
- default:
- /* This makes the compiler silent. */
- break;
- }
-
return TMH_RESPONSE_reply_rc (connection,
rc,
ec,
diff --git a/src/backend/taler-merchant-httpd_tip-query.c
b/src/backend/taler-merchant-httpd_tip-query.c
index 0f99e49..b63f3d2 100644
--- a/src/backend/taler-merchant-httpd_tip-query.c
+++ b/src/backend/taler-merchant-httpd_tip-query.c
@@ -29,6 +29,7 @@
#include "taler-merchant-httpd_exchanges.h"
#include "taler-merchant-httpd_responses.h"
#include "taler-merchant-httpd_tip-query.h"
+#include "taler-merchant-httpd_tip-reserve-helper.h"
/**
@@ -46,75 +47,15 @@ struct TipQueryContext
struct TM_HandlerContext hc;
/**
- * HTTP connection we are handling.
- */
- struct MHD_Connection *connection;
-
- /**
* Merchant instance to use.
*/
const char *instance;
/**
- * Handle to pending /reserve/status request.
- */
- struct TALER_EXCHANGE_ReserveStatusHandle *rsh;
-
- /**
- * Handle for operation to obtain exchange handle.
- */
- struct TMH_EXCHANGES_FindOperation *fo;
-
- /**
- * Reserve expiration time as provided by the exchange.
- * Set in #exchange_cont.
- */
- struct GNUNET_TIME_Relative idle_reserve_expiration_time;
-
- /**
- * Tip amount requested.
- */
- struct TALER_Amount amount_deposited;
-
- /**
- * Tip amount requested.
- */
- struct TALER_Amount amount_withdrawn;
-
- /**
- * Amount authorized.
- */
- struct TALER_Amount amount_authorized;
-
- /**
- * Private key used by this merchant for the tipping reserve.
- */
- struct TALER_ReservePrivateKeyP reserve_priv;
-
- /**
- * No tips were authorized yet.
- */
- int none_authorized;
-
- /**
- * Response to return, NULL if we don't have one yet.
- */
- struct MHD_Response *response;
-
- /**
- * HTTP status code to use for the reply, i.e 200 for "OK".
- * Special value UINT_MAX is used to indicate hard errors
- * (no reply, return #MHD_NO).
+ * Context for checking the tipping reserve's status.
*/
- unsigned int response_code;
+ struct CheckTipReserve ctr;
- /**
- * #GNUNET_NO if the @e connection was not suspended,
- * #GNUNET_YES if the @e connection was suspended,
- * #GNUNET_SYSERR if @e connection was resumed to as
- * part of #MH_force_pc_resume during shutdown.
- */
- int suspended;
};
@@ -128,288 +69,52 @@ cleanup_tqc (struct TM_HandlerContext *hc)
{
struct TipQueryContext *tqc = (struct TipQueryContext *) hc;
- if (NULL != tqc->rsh)
- {
- TALER_EXCHANGE_reserve_status_cancel (tqc->rsh);
- tqc->rsh = NULL;
- }
- if (NULL != tqc->fo)
- {
- TMH_EXCHANGES_find_exchange_cancel (tqc->fo);
- tqc->fo = NULL;
- }
+ TMH_check_tip_reserve_cleanup (&tqc->ctr);
GNUNET_free (tqc);
}
/**
- * Resume the given context and send the given response. Stores the response
- * in the @a pc and signals MHD to resume the connection. Also ensures MHD
- * runs immediately.
+ * We've been resumed after processing the reserve data from the
+ * exchange without error. Generate the final response.
*
- * @param pc payment context
- * @param response_code response code to use
- * @param response response data to send back
+ * @param tqc context for which to generate the response.
*/
-static void
-resume_with_response (struct TipQueryContext *tqc,
- unsigned int response_code,
- struct MHD_Response *response)
+static int
+generate_final_response (struct TipQueryContext *tqc)
{
- tqc->response_code = response_code;
- tqc->response = response;
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Resuming /tip-query response (%u)\n",
- response_code);
- GNUNET_assert (GNUNET_YES == tqc->suspended);
- tqc->suspended = GNUNET_NO;
- MHD_resume_connection (tqc->connection);
- TMH_trigger_daemon (); /* we resumed, kick MHD */
-}
-
-
-/**
- * Function called with the result of the /reserve/status request
- * for the tipping reserve. Update our database balance with the
- * result.
- *
- * @param cls closure with a `struct TipAuthContext *'
- * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful
status request
- * 0 if the exchange's reply is bogus (fails to follow the
protocol)
- * @param ec taler-specific error code, #TALER_EC_NONE on success
- * @param[in] json original response in JSON format (useful only for
diagnostics)
- * @param balance current balance in the reserve, NULL on error
- * @param history_length number of entries in the transaction history, 0 on
error
- * @param history detailed transaction history, NULL on error
- */
-static void
-handle_status (void *cls,
- unsigned int http_status,
- enum TALER_ErrorCode ec,
- const json_t *json,
- const struct TALER_Amount *balance,
- unsigned int history_length,
- const struct TALER_EXCHANGE_ReserveHistory *history)
-{
- struct TipQueryContext *tqc = cls;
- struct GNUNET_TIME_Absolute reserve_expiration = GNUNET_TIME_UNIT_ZERO_ABS;
-
- tqc->rsh = NULL;
- if (MHD_HTTP_OK != http_status)
- {
- GNUNET_break_op (0);
- resume_with_response (tqc,
- MHD_HTTP_SERVICE_UNAVAILABLE,
- TMH_RESPONSE_make_error
(TALER_EC_TIP_QUERY_RESERVE_STATUS_FAILED_EXCHANGE_DOWN,
- "Unable to obtain reserve
status from exchange"));
- return;
- }
-
- if (0 == history_length)
- {
- GNUNET_break_op (0);
- resume_with_response (tqc,
- MHD_HTTP_SERVICE_UNAVAILABLE,
- TMH_RESPONSE_make_error
(TALER_EC_TIP_QUERY_RESERVE_HISTORY_FAILED_EMPTY,
- "Exchange returned empty
reserve history"));
- return;
- }
-
- if (TALER_EXCHANGE_RTT_DEPOSIT != history[0].type)
- {
- GNUNET_break_op (0);
- resume_with_response (tqc,
- MHD_HTTP_SERVICE_UNAVAILABLE,
- TMH_RESPONSE_make_error
(TALER_EC_TIP_QUERY_RESERVE_HISTORY_INVALID_NO_DEPOSIT,
- "Exchange returned invalid
reserve history"));
- return;
- }
+ struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
+ struct TALER_Amount amount_available;
- if (GNUNET_OK !=
- TALER_amount_get_zero (history[0].amount.currency,
- &tqc->amount_withdrawn))
+ GNUNET_CRYPTO_eddsa_key_get_public (&tqc->ctr.reserve_priv.eddsa_priv,
+ &reserve_pub);
+ if (GNUNET_SYSERR ==
+ TALER_amount_subtract (&amount_available,
+ &tqc->ctr.amount_deposited,
+ &tqc->ctr.amount_withdrawn))
{
GNUNET_break_op (0);
- resume_with_response (tqc,
- MHD_HTTP_SERVICE_UNAVAILABLE,
- TMH_RESPONSE_make_error
(TALER_EC_TIP_QUERY_RESERVE_HISTORY_INVALID_CURRENCY,
- "Exchange returned invalid
reserve history"));
- return;
- }
-
- if (0 != strcasecmp (TMH_currency,
- history[0].amount.currency))
- {
- GNUNET_break_op (0);
- resume_with_response (tqc,
- MHD_HTTP_SERVICE_UNAVAILABLE,
- TMH_RESPONSE_make_error
(TALER_EC_TIP_QUERY_RESERVE_CURRENCY_MISSMATCH,
- "Exchange currency
unexpected"));
- return;
- }
-
- if (GNUNET_YES == tqc->none_authorized)
- tqc->amount_authorized = tqc->amount_withdrawn;
- tqc->amount_deposited = tqc->amount_withdrawn;
-
- /* Update DB based on status! */
- for (unsigned int i=0;i<history_length;i++)
- {
- switch (history[i].type)
- {
- case TALER_EXCHANGE_RTT_DEPOSIT:
- {
- enum GNUNET_DB_QueryStatus qs;
- struct GNUNET_HashCode uuid;
- struct GNUNET_TIME_Absolute deposit_expiration;
-
- deposit_expiration = GNUNET_TIME_absolute_add
(history[i].details.in_details.timestamp,
-
tqc->idle_reserve_expiration_time);
- /* We're interested in the latest DEPOSIT timestamp, since this
determines the
- * reserve's expiration date. Note that the history isn't
chronologically ordered. */
- reserve_expiration = GNUNET_TIME_absolute_max (reserve_expiration,
deposit_expiration);
- GNUNET_CRYPTO_hash (history[i].details.in_details.wire_reference,
- history[i].details.in_details.wire_reference_size,
- &uuid);
- qs = db->enable_tip_reserve_TR (db->cls,
- &tqc->reserve_priv,
- &uuid,
- &history[i].amount,
- deposit_expiration);
- if (GNUNET_OK !=
- TALER_amount_add (&tqc->amount_deposited,
- &tqc->amount_deposited,
- &history[i].amount))
- {
- GNUNET_break_op (0);
- resume_with_response (tqc,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TMH_RESPONSE_make_error
(TALER_EC_TIP_QUERY_RESERVE_HISTORY_ARITHMETIC_ISSUE_DEPOSIT,
- "Exchange returned
invalid reserve history (amount overflow)"));
- return;
- }
-
- if (0 > qs)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Database error updating tipping reserve status:
%d\n"),
- qs);
- }
- }
- break;
- case TALER_EXCHANGE_RTT_WITHDRAWAL:
- if (GNUNET_OK !=
- TALER_amount_add (&tqc->amount_withdrawn,
- &tqc->amount_withdrawn,
- &history[i].amount))
- {
- GNUNET_break_op (0);
- resume_with_response (tqc,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TMH_RESPONSE_make_error
(TALER_EC_TIP_QUERY_RESERVE_HISTORY_ARITHMETIC_ISSUE_WITHDRAW,
- "Exchange returned
invalid reserve history (amount overflow)"));
- return;
- }
- break;
- case TALER_EXCHANGE_RTT_PAYBACK:
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Encountered unsupported /payback operation on tipping
reserve\n"));
- break;
- case TALER_EXCHANGE_RTT_CLOSE:
- /* We count 'closing' amounts just like withdrawals */
- if (GNUNET_OK !=
- TALER_amount_add (&tqc->amount_withdrawn,
- &tqc->amount_withdrawn,
- &history[i].amount))
- {
- GNUNET_break_op (0);
- resume_with_response (tqc,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TMH_RESPONSE_make_error
(TALER_EC_TIP_QUERY_RESERVE_HISTORY_ARITHMETIC_ISSUE_CLOSED,
- "Exchange returned
invalid reserve history (amount overflow)"));
- return;
- }
- break;
- }
- }
-
- {
- struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
- struct TALER_Amount amount_available;
-
- GNUNET_CRYPTO_eddsa_key_get_public (&tqc->reserve_priv.eddsa_priv,
- &reserve_pub);
- if (GNUNET_SYSERR ==
- TALER_amount_subtract (&amount_available,
- &tqc->amount_deposited,
- &tqc->amount_withdrawn))
- {
- GNUNET_break_op (0);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "amount overflow, deposited %s but withdrawn %s\n",
- TALER_amount_to_string (&tqc->amount_deposited),
- TALER_amount_to_string (&tqc->amount_withdrawn));
-
- resume_with_response (tqc,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TMH_RESPONSE_make_error
(TALER_EC_TIP_QUERY_RESERVE_HISTORY_ARITHMETIC_ISSUE_INCONSISTENT,
- "Exchange returned
invalid reserve history (amount overflow)"));
- }
- resume_with_response (tqc,
- MHD_HTTP_OK,
- TMH_RESPONSE_make_json_pack ("{s:o, s:o, s:o, s:o,
s:o}",
- "reserve_pub",
-
GNUNET_JSON_from_data_auto (&reserve_pub),
- "reserve_expiration",
-
GNUNET_JSON_from_time_abs (reserve_expiration),
- "amount_authorized",
- TALER_JSON_from_amount
(&tqc->amount_authorized),
- "amount_picked_up",
- TALER_JSON_from_amount
(&tqc->amount_withdrawn),
- "amount_available",
- TALER_JSON_from_amount
(&amount_available)));
- }
-}
-
-
-/**
- * Function called with the result of a #TMH_EXCHANGES_find_exchange()
- * operation.
- *
- * @param cls closure with a `struct TipQueryContext *`
- * @param eh handle to the exchange context
- * @param wire_fee current applicable wire fee for dealing with @a eh, NULL if
not available
- * @param exchange_trusted #GNUNET_YES if this exchange is trusted by config
- */
-static void
-exchange_cont (void *cls,
- struct TALER_EXCHANGE_Handle *eh,
- const struct TALER_Amount *wire_fee,
- int exchange_trusted)
-{
- struct TipQueryContext *tqc = cls;
- struct TALER_ReservePublicKeyP reserve_pub;
- const struct TALER_EXCHANGE_Keys *keys;
-
- tqc->fo = NULL;
- if (NULL == eh)
- {
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- _("Failed to contact exchange configured for tipping!\n"));
- MHD_resume_connection (tqc->connection);
- TMH_trigger_daemon ();
- return;
- }
- keys = TALER_EXCHANGE_get_keys (eh);
- GNUNET_assert (NULL != keys);
- tqc->idle_reserve_expiration_time
- = keys->reserve_closing_delay;
- GNUNET_CRYPTO_eddsa_key_get_public (&tqc->reserve_priv.eddsa_priv,
- &reserve_pub.eddsa_pub);
- tqc->rsh = TALER_EXCHANGE_reserve_status (eh,
- &reserve_pub,
- &handle_status,
- tqc);
+ "amount overflow, deposited %s but withdrawn %s\n",
+ TALER_amount_to_string (&tqc->ctr.amount_deposited),
+ TALER_amount_to_string (&tqc->ctr.amount_withdrawn));
+ return TMH_RESPONSE_reply_internal_error (tqc->ctr.connection,
+
TALER_EC_TIP_QUERY_RESERVE_HISTORY_ARITHMETIC_ISSUE_INCONSISTENT,
+ "Exchange returned invalid
reserve history (amount overflow)");
+ }
+ return TMH_RESPONSE_reply_json_pack (tqc->ctr.connection,
+ MHD_HTTP_OK,
+ "{s:o, s:o, s:o, s:o, s:o}",
+ "reserve_pub",
+ GNUNET_JSON_from_data_auto
(&reserve_pub),
+ "reserve_expiration",
+ GNUNET_JSON_from_time_abs
(tqc->ctr.reserve_expiration),
+ "amount_authorized",
+ TALER_JSON_from_amount
(&tqc->ctr.amount_authorized),
+ "amount_picked_up",
+ TALER_JSON_from_amount
(&tqc->ctr.amount_withdrawn),
+ "amount_available",
+ TALER_JSON_from_amount
(&amount_available));
}
@@ -438,7 +143,7 @@ MH_handler_tip_query (struct TMH_RequestHandler *rh,
{
tqc = GNUNET_new (struct TipQueryContext);
tqc->hc.cc = &cleanup_tqc;
- tqc->connection = connection;
+ tqc->ctr.connection = connection;
*connection_cls = tqc;
}
else
@@ -446,26 +151,34 @@ MH_handler_tip_query (struct TMH_RequestHandler *rh,
tqc = *connection_cls;
}
- if (0 != tqc->response_code)
+ if (0 != tqc->ctr.response_code)
{
/* We are *done* processing the request, just queue the response (!) */
- if (UINT_MAX == tqc->response_code)
+ if (UINT_MAX == tqc->ctr.response_code)
{
GNUNET_break (0);
return MHD_NO; /* hard error */
}
res = MHD_queue_response (connection,
- tqc->response_code,
- tqc->response);
- MHD_destroy_response (tqc->response);
- tqc->response = NULL;
+ tqc->ctr.response_code,
+ tqc->ctr.response);
+ MHD_destroy_response (tqc->ctr.response);
+ tqc->ctr.response = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Queueing response (%u) for /tip-query (%s).\n",
- (unsigned int) tqc->response_code,
- res ? "OK" : "FAILED");
+ "Queueing response (%u) for /tip-query (%s).\n",
+ (unsigned int) tqc->ctr.response_code,
+ res ? "OK" : "FAILED");
return res;
}
+ if (NULL != tqc->instance)
+ {
+ /* We've been here before, so TMH_check_tip_reserve() must have
+ finished and left the result for us. Finish processing. */
+ return generate_final_response (tqc);
+ }
+
+ /* No error yet, so first time here, let's query the exchange */
tqc->instance = MHD_lookup_connection_value (connection,
MHD_GET_ARGUMENT_KIND,
"instance");
@@ -481,8 +194,8 @@ MH_handler_tip_query (struct TMH_RequestHandler *rh,
"Instance `%s' not configured\n",
tqc->instance);
return TMH_RESPONSE_reply_not_found (connection,
-
TALER_EC_TIP_AUTHORIZE_INSTANCE_UNKNOWN,
- "unknown instance");
+
TALER_EC_TIP_AUTHORIZE_INSTANCE_UNKNOWN,
+ "unknown instance");
}
if (NULL == mi->tip_exchange)
{
@@ -493,7 +206,7 @@ MH_handler_tip_query (struct TMH_RequestHandler *rh,
TALER_EC_TIP_AUTHORIZE_INSTANCE_DOES_NOT_TIP,
"exchange for tipping not configured
for the instance");
}
- tqc->reserve_priv = mi->tip_reserve;
+ tqc->ctr.reserve_priv = mi->tip_reserve;
{
int qs;
@@ -501,8 +214,8 @@ MH_handler_tip_query (struct TMH_RequestHandler *rh,
{
db->preflight (db->cls);
qs = db->get_authorized_tip_amount (db->cls,
- &tqc->reserve_priv,
- &tqc->amount_authorized);
+ &tqc->ctr.reserve_priv,
+ &tqc->ctr.amount_authorized);
if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
break;
}
@@ -518,17 +231,12 @@ MH_handler_tip_query (struct TMH_RequestHandler *rh,
{
/* we'll set amount_authorized to zero later once
we know the currency */
- tqc->none_authorized = GNUNET_YES;
+ tqc->ctr.none_authorized = GNUNET_YES;
}
}
- MHD_suspend_connection (connection);
- tqc->suspended = GNUNET_YES;
-
- tqc->fo = TMH_EXCHANGES_find_exchange (mi->tip_exchange,
- NULL,
- &exchange_cont,
- tqc);
+ TMH_check_tip_reserve (&tqc->ctr,
+ mi->tip_exchange);
return MHD_YES;
}
diff --git a/src/backend/taler-merchant-httpd_tip-reserve-helper.c
b/src/backend/taler-merchant-httpd_tip-reserve-helper.c
new file mode 100644
index 0000000..dc16195
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_tip-reserve-helper.c
@@ -0,0 +1,329 @@
+/*
+ This file is part of TALER
+ (C) 2018--2019 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file backend/taler-merchant-httpd_tip-reserve-helper.c
+ * @brief helper functions to check the status of a tipping reserve
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler-merchant-httpd_tip-reserve-helper.h"
+
+
+/**
+ * Resume the given context and send the given response. Stores the response
+ * in the @a ctr and signals MHD to resume the connection. Also ensures MHD
+ * runs immediately.
+ *
+ * @param ctr tip reserve query helper context
+ * @param response_code response code to use
+ * @param response response data to send back
+ */
+static void
+resume_with_response (struct CheckTipReserve *ctr,
+ unsigned int response_code,
+ struct MHD_Response *response)
+{
+ ctr->response_code = response_code;
+ ctr->response = response;
+ GNUNET_assert (GNUNET_YES == ctr->suspended);
+ ctr->suspended = GNUNET_NO;
+ MHD_resume_connection (ctr->connection);
+ TMH_trigger_daemon (); /* we resumed, kick MHD */
+}
+
+
+/**
+ * Function called with the result of the /reserve/status request
+ * for the tipping reserve. Update our database balance with the
+ * result.
+ *
+ * @param cls closure with a `struct CheckTipReserve *'
+ * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful
status request
+ * 0 if the exchange's reply is bogus (fails to follow the
protocol)
+ * @param ec taler-specific error code, #TALER_EC_NONE on success
+ * @param[in] json original response in JSON format (useful only for
diagnostics)
+ * @param balance current balance in the reserve, NULL on error
+ * @param history_length number of entries in the transaction history, 0 on
error
+ * @param history detailed transaction history, NULL on error
+ */
+static void
+handle_status (void *cls,
+ unsigned int http_status,
+ enum TALER_ErrorCode ec,
+ const json_t *json,
+ const struct TALER_Amount *balance,
+ unsigned int history_length,
+ const struct TALER_EXCHANGE_ReserveHistory *history)
+{
+ struct CheckTipReserve *ctr = cls;
+
+ ctr->rsh = NULL;
+ ctr->reserve_expiration = GNUNET_TIME_UNIT_ZERO_ABS;
+ if (MHD_HTTP_NOT_FOUND == http_status)
+ {
+ resume_with_response (ctr,
+ MHD_HTTP_NOT_FOUND,
+ TMH_RESPONSE_make_error (ec,
+ "Reserve unknown at
exchange"));
+ return;
+ }
+ if (MHD_HTTP_OK != http_status)
+ {
+ GNUNET_break_op (0);
+ resume_with_response (ctr,
+ MHD_HTTP_SERVICE_UNAVAILABLE,
+ TMH_RESPONSE_make_error (ec,
+ "Exchange returned error
code for reserve status"));
+ return;
+ }
+
+ if (0 == history_length)
+ {
+ GNUNET_break_op (0);
+ resume_with_response (ctr,
+ MHD_HTTP_SERVICE_UNAVAILABLE,
+ TMH_RESPONSE_make_error
(TALER_EC_TIP_QUERY_RESERVE_HISTORY_FAILED_EMPTY,
+ "Exchange returned empty
reserve history"));
+ return;
+ }
+
+ if (TALER_EXCHANGE_RTT_DEPOSIT != history[0].type)
+ {
+ GNUNET_break_op (0);
+ resume_with_response (ctr,
+ MHD_HTTP_SERVICE_UNAVAILABLE,
+ TMH_RESPONSE_make_error
(TALER_EC_TIP_QUERY_RESERVE_HISTORY_INVALID_NO_DEPOSIT,
+ "Exchange returned invalid
reserve history"));
+ return;
+ }
+
+ if (GNUNET_OK !=
+ TALER_amount_get_zero (history[0].amount.currency,
+ &ctr->amount_withdrawn))
+ {
+ GNUNET_break_op (0);
+ resume_with_response (ctr,
+ MHD_HTTP_SERVICE_UNAVAILABLE,
+ TMH_RESPONSE_make_error
(TALER_EC_TIP_QUERY_RESERVE_HISTORY_INVALID_CURRENCY,
+ "Exchange returned invalid
reserve history"));
+ return;
+ }
+
+ if (0 != strcasecmp (TMH_currency,
+ history[0].amount.currency))
+ {
+ GNUNET_break_op (0);
+ resume_with_response (ctr,
+ MHD_HTTP_SERVICE_UNAVAILABLE,
+ TMH_RESPONSE_make_error
(TALER_EC_TIP_QUERY_RESERVE_CURRENCY_MISSMATCH,
+ "Exchange currency
unexpected"));
+ return;
+ }
+
+ if (GNUNET_YES == ctr->none_authorized)
+ ctr->amount_authorized = ctr->amount_withdrawn;
+ ctr->amount_deposited = ctr->amount_withdrawn;
+
+ /* Update DB based on status! */
+ for (unsigned int i=0;i<history_length;i++)
+ {
+ switch (history[i].type)
+ {
+ case TALER_EXCHANGE_RTT_DEPOSIT:
+ {
+ enum GNUNET_DB_QueryStatus qs;
+ struct GNUNET_HashCode uuid;
+ struct GNUNET_TIME_Absolute deposit_expiration;
+
+ deposit_expiration = GNUNET_TIME_absolute_add
(history[i].details.in_details.timestamp,
+
ctr->idle_reserve_expiration_time);
+ /* We're interested in the latest DEPOSIT timestamp, since this
determines the
+ * reserve's expiration date. Note that the history isn't
chronologically ordered. */
+ ctr->reserve_expiration = GNUNET_TIME_absolute_max
(ctr->reserve_expiration,
+
deposit_expiration);
+ GNUNET_CRYPTO_hash (history[i].details.in_details.wire_reference,
+ history[i].details.in_details.wire_reference_size,
+ &uuid);
+ qs = db->enable_tip_reserve_TR (db->cls,
+ &ctr->reserve_priv,
+ &uuid,
+ &history[i].amount,
+ deposit_expiration);
+ if (GNUNET_OK !=
+ TALER_amount_add (&ctr->amount_deposited,
+ &ctr->amount_deposited,
+ &history[i].amount))
+ {
+ GNUNET_break_op (0);
+ resume_with_response (ctr,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TMH_RESPONSE_make_error
(TALER_EC_TIP_QUERY_RESERVE_HISTORY_ARITHMETIC_ISSUE_DEPOSIT,
+ "Exchange returned
invalid reserve history (amount overflow)"));
+ return;
+ }
+
+ if (0 > qs)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Database error updating tipping reserve status:
%d\n"),
+ qs);
+ }
+ }
+ break;
+ case TALER_EXCHANGE_RTT_WITHDRAWAL:
+ if (GNUNET_OK !=
+ TALER_amount_add (&ctr->amount_withdrawn,
+ &ctr->amount_withdrawn,
+ &history[i].amount))
+ {
+ GNUNET_break_op (0);
+ resume_with_response (ctr,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TMH_RESPONSE_make_error
(TALER_EC_TIP_QUERY_RESERVE_HISTORY_ARITHMETIC_ISSUE_WITHDRAW,
+ "Exchange returned
invalid reserve history (amount overflow)"));
+ return;
+ }
+ break;
+ case TALER_EXCHANGE_RTT_PAYBACK:
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Encountered unsupported /payback operation on tipping
reserve\n"));
+ /* FIXME: probably should count these like deposits!? */
+ break;
+ case TALER_EXCHANGE_RTT_CLOSE:
+ /* We count 'closing' amounts just like withdrawals */
+ if (GNUNET_OK !=
+ TALER_amount_add (&ctr->amount_withdrawn,
+ &ctr->amount_withdrawn,
+ &history[i].amount))
+ {
+ GNUNET_break_op (0);
+ resume_with_response (ctr,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TMH_RESPONSE_make_error
(TALER_EC_TIP_QUERY_RESERVE_HISTORY_ARITHMETIC_ISSUE_CLOSED,
+ "Exchange returned
invalid reserve history (amount overflow)"));
+ return;
+ }
+ break;
+ }
+ }
+
+ /* normal, non-error continuation */
+ resume_with_response (ctr,
+ 0,
+ NULL);
+}
+
+
+/**
+ * Function called with the result of a #TMH_EXCHANGES_find_exchange()
+ * operation. Given the exchange handle, we will then interrogate
+ * the exchange about the status of the tipping reserve.
+ *
+ * @param cls closure with a `struct CheckTipReserve *`
+ * @param eh handle to the exchange context
+ * @param wire_fee current applicable wire fee for dealing with @a eh, NULL if
not available
+ * @param exchange_trusted #GNUNET_YES if this exchange is trusted by config
+ */
+static void
+exchange_cont (void *cls,
+ struct TALER_EXCHANGE_Handle *eh,
+ const struct TALER_Amount *wire_fee,
+ int exchange_trusted)
+{
+ struct CheckTipReserve *ctr = cls;
+ struct TALER_ReservePublicKeyP reserve_pub;
+ const struct TALER_EXCHANGE_Keys *keys;
+
+ ctr->fo = NULL;
+ if (NULL == eh)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Failed to contact exchange configured for tipping!\n"));
+ resume_with_response (ctr,
+ MHD_HTTP_SERVICE_UNAVAILABLE,
+ TMH_RESPONSE_make_error
(TALER_EC_TIP_QUERY_RESERVE_STATUS_FAILED_EXCHANGE_DOWN,
+ "Unable to obtain /keys
from exchange"));
+ return;
+ }
+ keys = TALER_EXCHANGE_get_keys (eh);
+ GNUNET_assert (NULL != keys);
+ ctr->idle_reserve_expiration_time
+ = keys->reserve_closing_delay;
+ GNUNET_CRYPTO_eddsa_key_get_public (&ctr->reserve_priv.eddsa_priv,
+ &reserve_pub.eddsa_pub);
+ ctr->rsh = TALER_EXCHANGE_reserve_status (eh,
+ &reserve_pub,
+ &handle_status,
+ ctr);
+}
+
+
+/**
+ * Check the status of the given reserve at the given exchange.
+ * Suspends the MHD connection while this is happening and resumes
+ * processing once we know the reserve status (or once an error
+ * code has been determined).
+ *
+ * @param[in,out] ctr context for checking the reserve status
+ * @param tip_exchange the URL of the exchange to query
+ */
+void
+TMH_check_tip_reserve (struct CheckTipReserve *ctr,
+ const char *tip_exchange)
+{
+ MHD_suspend_connection (ctr->connection);
+ ctr->suspended = GNUNET_YES;
+ ctr->fo = TMH_EXCHANGES_find_exchange (tip_exchange,
+ NULL,
+ &exchange_cont,
+ ctr);
+ if (NULL == ctr->fo)
+ {
+ GNUNET_break (0);
+ resume_with_response (ctr,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TMH_RESPONSE_make_error
(TALER_EC_INTERNAL_INVARIANT_FAILURE,
+ "Unable to find exchange
handle"));
+ }
+}
+
+
+/**
+ * Clean up any state that might be left in @a ctr.
+ *
+ * @param[in] context to clean up
+ */
+void
+TMH_check_tip_reserve_cleanup (struct CheckTipReserve *ctr)
+{
+ if (NULL != ctr->rsh)
+ {
+ TALER_EXCHANGE_reserve_status_cancel (ctr->rsh);
+ ctr->rsh = NULL;
+ }
+ if (NULL != ctr->fo)
+ {
+ TMH_EXCHANGES_find_exchange_cancel (ctr->fo);
+ ctr->fo = NULL;
+ }
+ if (NULL != ctr->response)
+ {
+ MHD_destroy_response (ctr->response);
+ ctr->response = NULL;
+ }
+}
+
+/* end of taler-merchant-httpd_tip-reserve-helper.c */
diff --git a/src/backend/taler-merchant-httpd_tip-reserve-helper.h
b/src/backend/taler-merchant-httpd_tip-reserve-helper.h
new file mode 100644
index 0000000..8726b54
--- /dev/null
+++ b/src/backend/taler-merchant-httpd_tip-reserve-helper.h
@@ -0,0 +1,137 @@
+/*
+ This file is part of TALER
+ (C) 2018--2019 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file backend/taler-merchant-httpd_tip-reserve-helper.h
+ * @brief helper functions to check the status of a tipping reserve
+ * @author Christian Grothoff
+ */
+#ifndef TALER_MERCHANT_HTTPD_TIP_RESERVE_HELPER_H
+#define TALER_MERCHANT_HTTPD_TIP_RESERVE_HELPER_H
+#include <jansson.h>
+#include <taler/taler_util.h>
+#include <taler/taler_json_lib.h>
+#include "taler-merchant-httpd.h"
+#include "taler-merchant-httpd_mhd.h"
+#include "taler-merchant-httpd_parsing.h"
+#include "taler-merchant-httpd_exchanges.h"
+#include "taler-merchant-httpd_responses.h"
+#include "taler-merchant-httpd_tip-reserve-helper.h"
+
+
+/**
+ * Context with input, output and internal state for
+ * #TMH_check_tip_reserve() and #TMH_check_tip_reserve_cleanup().
+ */
+struct CheckTipReserve
+{
+ /**
+ * Input: MHD connection we should resume when finished
+ */
+ struct MHD_Connection *connection;
+
+ /**
+ * Input: private key of the reserve.
+ */
+ struct TALER_ReservePrivateKeyP reserve_priv;
+
+ /**
+ * Output: Set to delay after which the reserve will expire if idle.
+ */
+ struct GNUNET_TIME_Relative idle_reserve_expiration_time;
+
+ /**
+ * Internal: exchange find operation.
+ */
+ struct TMH_EXCHANGES_FindOperation *fo;
+
+ /**
+ * Internal: reserve status operation.
+ */
+ struct TALER_EXCHANGE_ReserveStatusHandle *rsh;
+
+ /**
+ * Output: response object to return (on error only)
+ */
+ struct MHD_Response *response;
+
+ /**
+ * Output: Total amount deposited into the reserve.
+ */
+ struct TALER_Amount amount_deposited;
+
+ /**
+ * Output: total tip amount requested.
+ */
+ struct TALER_Amount amount_withdrawn;
+
+ /**
+ * Input: total amount authorized.
+ */
+ struct TALER_Amount amount_authorized;
+
+ /**
+ * Output: set to the time when the reserve will expire
+ */
+ struct GNUNET_TIME_Absolute reserve_expiration;
+
+ /**
+ * Output: HTTP status code to return (on error only)
+ */
+ unsigned int response_code;
+
+ /**
+ * Input: Set to #GNUNET_NO if no tips were authorized yet.
+ * Used to know that @e amount_authorized is not yet initialized
+ * and in that case the helper will set it to zero (once we know
+ * the currency).
+ */
+ int none_authorized;
+
+ /**
+ * Internal: Is the @e connection currently suspended?
+ * #GNUNET_NO if the @e connection was not suspended,
+ * #GNUNET_YES if the @e connection was suspended,
+ * #GNUNET_SYSERR if @e connection was resumed to as
+ * part of #MH_force_pc_resume during shutdown.
+ */
+ int suspended;
+
+};
+
+
+/**
+ * Check the status of the given reserve at the given exchange.
+ * Suspends the MHD connection while this is happening and resumes
+ * processing once we know the reserve status (or once an error
+ * code has been determined).
+ *
+ * @param[in,out] ctr context for checking the reserve status
+ * @param tip_exchange the URL of the exchange to query
+ */
+void
+TMH_check_tip_reserve (struct CheckTipReserve *ctr,
+ const char *tip_exchange);
+
+
+/**
+ * Clean up any state that might be left in @a ctr.
+ *
+ * @param[in] context to clean up
+ */
+void
+TMH_check_tip_reserve_cleanup (struct CheckTipReserve *ctr);
+
+#endif
diff --git a/src/lib/test_merchant_api_new.c b/src/lib/test_merchant_api_new.c
index 94aafac..67df2b9 100644
--- a/src/lib/test_merchant_api_new.c
+++ b/src/lib/test_merchant_api_new.c
@@ -511,7 +511,7 @@ run (void *cls,
/**
* The following block will (1) create a new
* reserve, then (2) a proposal, then (3) pay for
- * it, and finally (4) attempt to pick up a refund
+ * it, and finally (4) attempt to pick up a refund
* from it without any increasing taking place
* in the first place.
**/
@@ -641,7 +641,7 @@ run (void *cls,
"nulltip",
"tip 2",
"EUR:5.01",
- TALER_EC_TIP_AUTHORIZE_RESERVE_UNKNOWN),
+ TALER_EC_RESERVE_STATUS_UNKNOWN),
TALER_TESTING_cmd_tip_query ("query-tip-1",
merchant_url,
--
To stop receiving notification emails like this one, please contact
address@hidden