diff options
author | Jonathan Buchanan <jonathan.russ.buchanan@gmail.com> | 2020-08-19 03:28:38 -0400 |
---|---|---|
committer | Jonathan Buchanan <jonathan.russ.buchanan@gmail.com> | 2020-08-19 03:28:38 -0400 |
commit | b77ef665b0f3876f2c27db2d5a9b154fa1a9ba0d (patch) | |
tree | 37f482c473bf00f78218bdc1305d0980f5486895 /src/backend/taler-merchant-httpd_get-orders-ID.c | |
parent | 807b6e0b125100b1dd8ec56521517522a0cbfd4f (diff) | |
download | merchant-b77ef665b0f3876f2c27db2d5a9b154fa1a9ba0d.tar.gz merchant-b77ef665b0f3876f2c27db2d5a9b154fa1a9ba0d.tar.bz2 merchant-b77ef665b0f3876f2c27db2d5a9b154fa1a9ba0d.zip |
long poll for pending refunds
Diffstat (limited to 'src/backend/taler-merchant-httpd_get-orders-ID.c')
-rw-r--r-- | src/backend/taler-merchant-httpd_get-orders-ID.c | 472 |
1 files changed, 14 insertions, 458 deletions
diff --git a/src/backend/taler-merchant-httpd_get-orders-ID.c b/src/backend/taler-merchant-httpd_get-orders-ID.c index d6a52f40..142ba999 100644 --- a/src/backend/taler-merchant-httpd_get-orders-ID.c +++ b/src/backend/taler-merchant-httpd_get-orders-ID.c @@ -35,97 +35,6 @@ */ #define MAX_RETRIES 5 -/** - * Information we keep for each coin to be refunded. - */ -struct CoinRefund -{ - - /** - * Kept in a DLL. - */ - struct CoinRefund *next; - - /** - * Kept in a DLL. - */ - struct CoinRefund *prev; - - /** - * Request to connect to the target exchange. - */ - struct TMH_EXCHANGES_FindOperation *fo; - - /** - * Handle for the refund operation with the exchange. - */ - struct TALER_EXCHANGE_RefundHandle *rh; - - /** - * Request this operation is part of. - */ - struct GetOrderData *god; - - /** - * URL of the exchange for this @e coin_pub. - */ - char *exchange_url; - - /** - * Fully reply from the exchange, only possibly set if - * we got a JSON reply and a non-#MHD_HTTP_OK error code - */ - json_t *exchange_reply; - - /** - * When did the merchant grant the refund. To be used to group events - * in the wallet. - */ - struct GNUNET_TIME_Absolute execution_time; - - /** - * Coin to refund. - */ - struct TALER_CoinSpendPublicKeyP coin_pub; - - /** - * Refund transaction ID to use. - */ - uint64_t rtransaction_id; - - /** - * Unique serial number identifying the refund. - */ - uint64_t refund_serial; - - /** - * Amount to refund. - */ - struct TALER_Amount refund_amount; - - /** - * Public key of the exchange affirming the refund. - */ - struct TALER_ExchangePublicKeyP exchange_pub; - - /** - * Signature of the exchange affirming the refund. - */ - struct TALER_ExchangeSignatureP exchange_sig; - - /** - * HTTP status from the exchange, #MHD_HTTP_OK if - * @a exchange_pub and @a exchange_sig are valid. - */ - unsigned int exchange_status; - - /** - * HTTP error code from the exchange. - */ - enum TALER_ErrorCode exchange_code; - -}; - /** * Context for the operation. @@ -156,16 +65,6 @@ struct GetOrderData struct GetOrderData *prev; /** - * Refunds for this order. Head of DLL. - */ - struct CoinRefund *cr_head; - - /** - * Refunds for this order. Tail of DLL. - */ - struct CoinRefund *cr_tail; - - /** * Context of the request. */ struct TMH_HandlerContext *hc; @@ -653,144 +552,6 @@ send_pay_request (struct GetOrderData *god, /** - * Check if @a god has sub-activities still pending. - * - * @param god request to check - * @return true if activities are still pending - */ -static bool -god_pending (struct GetOrderData *god) -{ - for (struct CoinRefund *cr = god->cr_head; - NULL != cr; - cr = cr->next) - { - if ( (NULL != cr->fo) || - (NULL != cr->rh) ) - return true; - } - return false; -} - - -/** - * Check if @a god is ready to be resumed, and if so, do it. - * - * @param god refund request to be possibly ready - */ -static void -check_resume_god (struct GetOrderData *god) -{ - if (god_pending (god)) - return; - GNUNET_CONTAINER_DLL_remove (god_head, - god_tail, - god); - GNUNET_assert (god->suspended); - god->suspended = false; - MHD_resume_connection (god->sc.con); - TMH_trigger_daemon (); -} - - -//#if 0 -/** - * Callbacks of this type are used to serve the result of submitting a - * refund request to an exchange. - * - * @param cls a `struct CoinRefund` - * @param hr HTTP response data - * @param exchange_pub exchange key used to sign refund confirmation - * @param exchange_sig exchange's signature over refund - */ -static void -refund_cb (void *cls, - const struct TALER_EXCHANGE_HttpResponse *hr, - const struct TALER_ExchangePublicKeyP *exchange_pub, - const struct TALER_ExchangeSignatureP *exchange_sig) -{ - struct CoinRefund *cr = cls; - - cr->rh = NULL; - cr->exchange_status = hr->http_status; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Exchange refund status for coin %s is %u\n", - TALER_B2S (&cr->coin_pub), - hr->http_status); - if (MHD_HTTP_OK != hr->http_status) - { - cr->exchange_code = hr->ec; - cr->exchange_reply = json_incref ((json_t*) hr->reply); - } - else - { - enum GNUNET_DB_QueryStatus qs; - - cr->exchange_pub = *exchange_pub; - cr->exchange_sig = *exchange_sig; - qs = TMH_db->insert_refund_proof (TMH_db->cls, - cr->refund_serial, - exchange_sig, - exchange_pub); - if (0 >= qs) - { - /* generally, this is relatively harmless for the merchant, but let's at - least log this. */ - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Failed to persist exchange response to /refund in database: %d\n", - qs); - } - } - check_resume_god (cr->god); -} -//#endif - - -//#if 0 -/** - * Function called with the result of a #TMH_EXCHANGES_find_exchange() - * operation. - * - * @param cls a `struct CoinRefund *` - * @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 -exchange_found_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 CoinRefund *cr = cls; - - (void) payto_uri; - cr->fo = NULL; - if (TALER_EC_NONE == hr->ec) - { - cr->rh = TALER_EXCHANGE_refund (eh, - &cr->refund_amount, - &cr->god->h_contract_terms, - &cr->coin_pub, - cr->rtransaction_id, - &cr->god->hc->instance->merchant_priv, - &refund_cb, - cr); - return; - } - cr->exchange_status = hr->http_status; - cr->exchange_code = hr->ec; - cr->exchange_reply = json_incref ((json_t*) hr->reply); - check_resume_god (cr->god); -} -//#endif - - -/** * Function called with detailed information about a refund. * It is responsible for packing up the data to return. * @@ -816,24 +577,12 @@ process_refunds_cb (void *cls, bool pending) { struct GetOrderData *god = cls; - struct CoinRefund *cr; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found refund of %s for coin %s with reason `%s' in database\n", TALER_amount2s (refund_amount), TALER_B2S (coin_pub), reason); - cr = GNUNET_new (struct CoinRefund); - cr->refund_serial = refund_serial; - cr->exchange_url = GNUNET_strdup (exchange_url); - cr->god = god; - cr->coin_pub = *coin_pub; - cr->rtransaction_id = rtransaction_id; - cr->refund_amount = *refund_amount; - cr->execution_time = timestamp; - GNUNET_CONTAINER_DLL_insert (god->cr_head, - god->cr_tail, - cr); if (god->refunded) { GNUNET_assert (0 <= @@ -849,42 +598,6 @@ process_refunds_cb (void *cls, /** - * Clean up refund processing. - * - * @param god handle to clean up refund processing for - */ -static void -rf_cleanup (struct GetOrderData *god) -{ - struct CoinRefund *cr; - - while (NULL != (cr = god->cr_head)) - { - GNUNET_CONTAINER_DLL_remove (god->cr_head, - god->cr_tail, - cr); - if (NULL != cr->fo) - { - TMH_EXCHANGES_find_exchange_cancel (cr->fo); - cr->fo = NULL; - } - if (NULL != cr->rh) - { - TALER_EXCHANGE_refund_cancel (cr->rh); - cr->rh = NULL; - } - if (NULL != cr->exchange_reply) - { - json_decref (cr->exchange_reply); - cr->exchange_reply = NULL; - } - GNUNET_free (cr->exchange_url); - GNUNET_free (cr); - } -} - - -/** * Clean up the session state for a GET /orders/$ID request. * * @param cls must be a `struct GetOrderData *` @@ -894,7 +607,6 @@ god_cleanup (void *cls) { struct GetOrderData *god = cls; - rf_cleanup (god); if (NULL != god->contract_terms) json_decref (god->contract_terms); GNUNET_free (god); @@ -1005,7 +717,6 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh, } } -#if 0 { const char *await_refund_obtained_s; @@ -1019,7 +730,6 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh, ? 0 == strcasecmp (await_refund_obtained_s, "yes") : false; } -#endif { const char *min_refund; @@ -1302,19 +1012,8 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh, } } - /* Before we reset the refunds, make sure we notify the client in the case - of a non-200 status from the exchange. */ - for (struct CoinRefund *cr = god->cr_head; - NULL != cr; - cr = cr->next) - { - if (MHD_HTTP_OK != cr->exchange_status) - goto REPLY; - } - /* At this point, we know the contract was paid. Let's check for refunds. First, clear away refunds found from previous invocations. */ - rf_cleanup (god); GNUNET_assert (GNUNET_OK == TALER_amount_get_zero (TMH_currency, &god->refund_amount)); qs = TMH_db->lookup_refunds_detailed (TMH_db->cls, @@ -1331,66 +1030,12 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh, "Failed to lookup refunds for contract"); } -//#if 0 - /* Now launch exchange interactions, unless we already have the - response in the database! */ - for (struct CoinRefund *cr = god->cr_head; - NULL != cr; - cr = cr->next) - { - enum GNUNET_DB_QueryStatus qs; - - qs = TMH_db->lookup_refund_proof (TMH_db->cls, - cr->refund_serial, - &cr->exchange_sig, - &cr->exchange_pub); - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - case GNUNET_DB_STATUS_SOFT_ERROR: - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GET_ORDERS_DB_LOOKUP_ERROR, - "Merchant database error"); - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - /* We need to talk to the exchange */ - cr->fo = TMH_EXCHANGES_find_exchange (cr->exchange_url, - NULL, - GNUNET_NO, - &exchange_found_cb, - cr); - break; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - /* We got a reply earlier, set status accordingly */ - cr->exchange_status = MHD_HTTP_OK; - break; - } - } -//#endif -#if 0 - if ( (god->sc.awaiting_refund_obtained) && - (god->refund_available)) - { - /* Client is waiting for pending refunds to be picked up, suspend - until timeout */ - struct GNUNET_TIME_Relative remaining; - - remaining = GNUNET_TIME_absolute_get_remaining (god->sc.long_poll_timeout); - if (0 != remaining.rel_value_us) - { - /* yes, indeed suspend */ - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Awaiting pending refunds\n"); - suspend_god (god); - return MHD_YES; - } - } -#endif - - if ( (god->sc.awaiting_refund) && - ( (! god->refunded) || - (1 != TALER_amount_cmp (&god->refund_amount, - &god->sc.refund_expected)) ) ) + if ( ((god->sc.awaiting_refund) && + ( (! god->refunded) || + (1 != TALER_amount_cmp (&god->refund_amount, + &god->sc.refund_expected)) )) || + ((god->sc.awaiting_refund_obtained) && + (god->refund_available)) ) { /* Client is waiting for a refund larger than what we have, suspend until timeout */ @@ -1400,106 +1045,21 @@ TMH_get_orders_ID (const struct TMH_RequestHandler *rh, if (0 != remaining.rel_value_us) { /* yes, indeed suspend */ + if (god->sc.awaiting_refund) + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Awaiting refund exceeding %s\n", + TALER_amount2s (&god->sc.refund_expected)); + if (god->sc.awaiting_refund_obtained) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Awaiting refund exceeding %s\n", + "Awaiting pending refunds\n", TALER_amount2s (&god->sc.refund_expected)); suspend_god (god); return MHD_YES; } } - /* Check if there are still exchange operations pending */ - if (god_pending (god)) - { - if (! god->suspended) - { - god->suspended = true; - MHD_suspend_connection (connection); - GNUNET_CONTAINER_DLL_insert (god_head, - god_tail, - god); - } - return MHD_YES; /* we're still talking to the exchange */ - } - /* All operations done, build final response */ -REPLY: { - json_t *ra; - - ra = json_array (); - GNUNET_assert (NULL != ra); - for (struct CoinRefund *cr = god->cr_head; - NULL != cr; - cr = cr->next) - { - json_t *refund; - - if (MHD_HTTP_OK != cr->exchange_status) - { - if (NULL == cr->exchange_reply) - { - refund = json_pack ("{s:s, s:I,s:I,s:o,s:o,s:o}" - "type", - "failure", - "exchange_status", - (json_int_t) cr->exchange_status, - "rtransaction_id", - (json_int_t) cr->rtransaction_id, - "coin_pub", - GNUNET_JSON_from_data_auto (&cr->coin_pub), - "refund_amount", - TALER_JSON_from_amount (&cr->refund_amount), - "execution_time", - GNUNET_JSON_from_time_abs (cr->execution_time)); - } - else - { - refund = json_pack ("{s:s,s:I,s:I,s:O,s:I,s:o,s:o,s:o}" - "type", - "failure", - "exchange_status", - (json_int_t) cr->exchange_status, - "exchange_code", - (json_int_t) cr->exchange_code, - "exchange_reply", - cr->exchange_reply, - "rtransaction_id", - (json_int_t) cr->rtransaction_id, - "coin_pub", - GNUNET_JSON_from_data_auto (&cr->coin_pub), - "refund_amount", - TALER_JSON_from_amount (&cr->refund_amount), - "execution_time", - GNUNET_JSON_from_time_abs (cr->execution_time)); - } - } - else - { - refund = json_pack ("{s:s,s:I,s:o,s:o,s:I,s:o,s:o,s:o}", - "type", - "success", - "exchange_status", - (json_int_t) cr->exchange_status, - "exchange_sig", - GNUNET_JSON_from_data_auto (&cr->exchange_sig), - "exchange_pub", - GNUNET_JSON_from_data_auto (&cr->exchange_pub), - "rtransaction_id", - (json_int_t) cr->rtransaction_id, - "coin_pub", - GNUNET_JSON_from_data_auto (&cr->coin_pub), - "refund_amount", - TALER_JSON_from_amount (&cr->refund_amount), - "execution_time", - GNUNET_JSON_from_time_abs (cr->execution_time)); - } - GNUNET_assert ( - 0 == - json_array_append_new (ra, - refund)); - } - if (god->generate_html) { enum GNUNET_GenericReturnValue res; @@ -1587,15 +1147,11 @@ REPLY: return TALER_MHD_reply_json_pack ( connection, MHD_HTTP_OK, - "{s:b, s:b, s:o, s:o, s:o}", + "{s:b, s:b, s:o}", "refunded", god->refunded, "refund_pending", god->refund_available, "refund_amount", - TALER_JSON_from_amount (&god->refund_amount), - "refunds", - ra, - "merchant_pub", - GNUNET_JSON_from_data_auto (&hc->instance->merchant_pub)); + TALER_JSON_from_amount (&god->refund_amount)); } } } |