merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

commit c6a10b52461f7781ac3e9c6aeb467ecbd7bdad38
parent da5f393967e9a4e6b7c78b72f1c9f74a49bb52c6
Author: Christian Grothoff <christian@grothoff.org>
Date:   Sat, 20 Jun 2020 19:46:32 +0200

finish taler-merchant-httpd_reserves implementation

Diffstat:
Msrc/backend/taler-merchant-httpd_reserves.c | 228+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 212 insertions(+), 16 deletions(-)

diff --git a/src/backend/taler-merchant-httpd_reserves.c b/src/backend/taler-merchant-httpd_reserves.c @@ -21,6 +21,7 @@ #include "platform.h" #include <taler/taler_json_lib.h> #include "taler-merchant-httpd.h" +#include "taler-merchant-httpd_exchanges.h" #include "taler-merchant-httpd_reserves.h" @@ -29,6 +30,17 @@ */ struct Reserve { + + /** + * Kept in a DLL. + */ + struct Reserve *next; + + /** + * Kept in a DLL. + */ + struct Reserve *prev; + /** * Reserve's public key. */ @@ -49,15 +61,207 @@ struct Reserve * Instance this reserve belongs with. */ char *instance_id; + + /** + * Active find operation for this reserve. + */ + struct TMH_EXCHANGES_FindOperation *fo; + + /** + * Task scheduled waiting for a timeout for this reserve. + */ + struct GNUNET_SCHEDULER_Task *tt; + + /** + * Get operation with the exchange. + */ + struct TALER_EXCHANGE_ReservesGetHandle *gh; + + /** + * How long do we wait before trying this reserve again? + */ + struct GNUNET_TIME_Relative delay; + }; /** + * Head of DLL of pending reserves. + */ +static struct Reserve *reserves_head; + +/** + * Tail of DLL of pending reserves. + */ +static struct Reserve *reserves_tail; + + +/** + * Function called to probe a reserve now. + * + * @param cls a `struct Reserve` to query + */ +static void +try_now (void *cls); + + +/** + * Free reserve data structure. + * + * @param r reserve to free + */ +static void +free_reserve (struct Reserve *r) +{ + GNUNET_CONTAINER_DLL_remove (reserves_head, + reserves_tail, + r); + if (NULL != r->fo) + { + TMH_EXCHANGES_find_exchange_cancel (r->fo); + r->fo = NULL; + } + if (NULL != r->gh) + { + TALER_EXCHANGE_reserves_get_cancel (r->gh); + r->gh = NULL; + } + if (NULL != r->tt) + { + GNUNET_SCHEDULER_cancel (r->tt); + r->tt = NULL; + } + GNUNET_free (r->exchange_url); + GNUNET_free (r->instance_id); + GNUNET_free (r); +} + + +/** + * Schedule a job to probe a reserve later again. + * + * @param r reserve to try again later + */ +static void +try_later (struct Reserve *r) +{ + r->delay = GNUNET_TIME_STD_BACKOFF (r->delay); + r->tt = GNUNET_SCHEDULER_add_delayed (r->delay, + &try_now, + r); +} + + +/** + * Callbacks of this type are used to serve the result of submitting a + * reserve status request to a exchange. + * + * @param cls closure with a `struct Reserve *` + * @param hr HTTP response data + * @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 +reserve_cb (void *cls, + const struct TALER_EXCHANGE_HttpResponse *hr, + const struct TALER_Amount *balance, + unsigned int history_length, + const struct TALER_EXCHANGE_ReserveHistory *history) +{ + struct Reserve *r = cls; + enum GNUNET_DB_QueryStatus qs; + + r->gh = NULL; + if ( (NULL == hr) || + (MHD_HTTP_OK != hr->http_status) ) + { + try_later (r); + return; + } + qs = TMH_db->activate_reserve (TMH_db->cls, + r->instance_id, + &r->reserve_pub, + balance); + if (qs <= 0) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to commit reserve activation to database (%d)\n", + (int) qs); + } + free_reserve (r); +} + + +/** + * Function called with the result of a #TMH_EXCHANGES_find_exchange() + * operation. + * + * @param cls closure + * @param hr HTTP response details + * @param eh handle to the exchange context + * @param payto_uri payto://-URI of the exchange + * @param wire_fee current applicable wire fee for dealing with @a eh, NULL if not available + * @param exchange_trusted true if this exchange is trusted by config + */ +static void +find_cb (void *cls, + const struct TALER_EXCHANGE_HttpResponse *hr, + struct TALER_EXCHANGE_Handle *eh, + const char *payto_uri, + const struct TALER_Amount *wire_fee, + bool exchange_trusted) +{ + struct Reserve *r = cls; + + r->fo = NULL; + if (NULL == eh) + { + try_later (r); + return; + } + r->gh = TALER_EXCHANGE_reserves_get (eh, + &r->reserve_pub, + &reserve_cb, + r); + if (NULL == r->gh) + { + try_later (r); + return; + } +} + + +/** + * Function called to probe a reserve now. + * + * @param cls a `struct Reserve` to query + */ +static void +try_now (void *cls) +{ + struct Reserve *r = cls; + + r->tt = NULL; + r->fo = TMH_EXCHANGES_find_exchange (r->exchange_url, + NULL, + GNUNET_NO, + &find_cb, + r); + if (NULL == r->fo) + { + try_later (r); + return; + } +} + + +/** * Function called with information about a reserve that we need * to check the status from at the exchange to see if/when it has * been filled (and with what amount). * - * @param cls closure + * @param cls closure, NULL * @param instance_id for which instance is this reserve * @param exchange_url base URL of the exchange at which the reserve lives * @param reserve_pub public key of the reserve @@ -72,12 +276,16 @@ add_reserve (void *cls, { struct Reserve *r; + (void) cls; r = GNUNET_new (struct Reserve); r->exchange_url = GNUNET_strdup (exchange_url); r->instance_id = GNUNET_strdup (instance_id); r->reserve_pub = *reserve_pub; r->expected_amount = *expected_amount; - // .... + GNUNET_CONTAINER_DLL_insert (reserves_head, + reserves_tail, + r); + try_now (r); } @@ -108,25 +316,11 @@ TMH_RESERVES_check (const char *instance_id, const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_Amount *expected_amount) { - enum GNUNET_DB_QueryStatus qs; - add_reserve (NULL, instance_id, exchange_url, reserve_pub, expected_amount); - - // Do this temporarily for testing - qs = TMH_db->activate_reserve (TMH_db->cls, - instance_id, - reserve_pub, - expected_amount); // FIXME: change to REAL amount later! - if (qs <= 0) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to commit reserve activation to database (%d)\n", - (int) qs); - } } @@ -136,6 +330,8 @@ TMH_RESERVES_check (const char *instance_id, void TMH_RESERVES_done (void) { + while (NULL != reserves_head) + free_reserve (reserves_head); }