From 60c96242e10b3e2bab8c4a75565767795f79cbd3 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 23 Jul 2022 21:02:26 +0200 Subject: -improve get tip API, note: long-polling not actually implemented --- src/include/taler_merchant_service.h | 83 ++++++++++++--- src/lib/merchant_api_merchant_get_tip.c | 137 ++++++++++--------------- src/testing/testing_api_cmd_merchant_get_tip.c | 56 ++++------ 3 files changed, 146 insertions(+), 130 deletions(-) (limited to 'src') diff --git a/src/include/taler_merchant_service.h b/src/include/taler_merchant_service.h index e22e84f0..25ce2a44 100644 --- a/src/include/taler_merchant_service.h +++ b/src/include/taler_merchant_service.h @@ -3548,30 +3548,77 @@ struct TALER_MERCHANT_PickupDetail }; +/** + * Details returned about a tip by the merchant. + */ +struct TALER_MERCHANT_TipStatusResponse +{ + /** + * HTTP status of the response. + */ + struct TALER_MERCHANT_HttpResponse hr; + + /** + * Details depending on the HTTP status. + */ + union { + + /** + * Details on #MHD_HTTP_OK. + */ + struct { + + /** + * Amount that was authorized under this tip + */ + struct TALER_Amount total_authorized; + + /** + * Amount that has been picked up + */ + struct TALER_Amount total_picked_up; + + /** + * The reason given for the tip + */ + const char *reason; + + /** + * Time when the tip will expire + */ + struct GNUNET_TIME_Timestamp expiration; + + /** + * reserve which is funding this tip + */ + struct TALER_ReservePublicKeyP reserve_pub; + + /** + * Length of the @e pickups array + */ + unsigned int pickups_length; + + /** + * array of pickup operations performed for this tip + */ + struct TALER_MERCHANT_PickupDetail *pickups; + } success; + + } details; + +}; + + /** * Callback to process a GET /private/tips/$TIP_ID request * * @param cls closure - * @param hr HTTP response details - * @param total_authorized how many tips were authorized under this tip - * @param total_picked_up how many tips have been picked up - * @param reason what was the reason given for the tip - * @param expiration when the tip will expire - * @param reserve_pub which reserve is funding this tip - * @param pickups_length length of the @a pickups array - * @param pickups array of pickup operations performed for this tip + * @param tsr response details */ typedef void (*TALER_MERCHANT_TipMerchantGetCallback) ( void *cls, - const struct TALER_MERCHANT_HttpResponse *hr, - const struct TALER_Amount *total_authorized, - const struct TALER_Amount *total_picked_up, - const char *reason, - struct GNUNET_TIME_Timestamp expiration, - const struct TALER_ReservePublicKeyP *reserve_pub, - unsigned int pickups_length, - const struct TALER_MERCHANT_PickupDetail pickups[]); + const struct TALER_MERCHANT_TipStatusResponse *tsr); /** @@ -3581,6 +3628,8 @@ typedef void * @param ctx execution context * @param backend_url base URL of the merchant backend * @param tip_id which tip should we query + * @param min_pick_up minimum amount picked up to notify about + * @param lp_timeout how long to wait for @a min_pick_up to be exceeded * @param pickups whether to fetch associated pickups * @param cb function to call with the result * @param cb_cls closure for @a cb @@ -3590,6 +3639,8 @@ struct TALER_MERCHANT_TipMerchantGetHandle * TALER_MERCHANT_merchant_tip_get (struct GNUNET_CURL_Context *ctx, const char *backend_url, const struct TALER_TipIdentifierP *tip_id, + const struct TALER_Amount *min_pick_up, + struct GNUNET_TIME_Relative lp_timeout, bool pickups, TALER_MERCHANT_TipMerchantGetCallback cb, void *cb_cls); diff --git a/src/lib/merchant_api_merchant_get_tip.c b/src/lib/merchant_api_merchant_get_tip.c index 020167c4..9c21377e 100644 --- a/src/lib/merchant_api_merchant_get_tip.c +++ b/src/lib/merchant_api_merchant_get_tip.c @@ -60,20 +60,15 @@ struct TALER_MERCHANT_TipMerchantGetHandle }; -static int +static enum GNUNET_GenericReturnValue parse_pickups (const json_t *pa, - const struct TALER_Amount *total_authorized, - const struct TALER_Amount *total_picked_up, - const char *reason, - struct GNUNET_TIME_Timestamp expiration, - const struct TALER_ReservePublicKeyP *reserve_pub, + struct TALER_MERCHANT_TipStatusResponse *tsr, struct TALER_MERCHANT_TipMerchantGetHandle *tgh) { unsigned int pa_len = json_array_size (pa); struct TALER_MERCHANT_PickupDetail pickups[pa_len]; size_t index; json_t *value; - int ret = GNUNET_OK; json_array_foreach (pa, index, value) { @@ -95,27 +90,14 @@ parse_pickups (const json_t *pa, NULL)) { GNUNET_break_op (0); - ret = GNUNET_SYSERR; - break; + return GNUNET_SYSERR; } } - if (GNUNET_OK == ret) - { - struct TALER_MERCHANT_HttpResponse hr = { - .http_status = MHD_HTTP_OK - }; - - tgh->cb (tgh->cb_cls, - &hr, - total_authorized, - total_picked_up, - reason, - expiration, - reserve_pub, - pa_len, - pickups); - } - return ret; + tsr->details.success.pickups_length = pa_len; + tsr->details.success.pickups = pickups; + tgh->cb (tgh->cb_cls, + tsr); + return GNUNET_OK; } @@ -134,9 +116,9 @@ handle_merchant_tip_get_finished (void *cls, { struct TALER_MERCHANT_TipMerchantGetHandle *tgh = cls; const json_t *json = response; - struct TALER_MERCHANT_HttpResponse hr = { - .http_status = (unsigned int) response_code, - .reply = json + struct TALER_MERCHANT_TipStatusResponse tsr = { + .hr.http_status = (unsigned int) response_code, + .hr.reply = json }; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, @@ -147,22 +129,17 @@ handle_merchant_tip_get_finished (void *cls, { case MHD_HTTP_OK: { - struct TALER_Amount total_authorized; - struct TALER_Amount total_picked_up; - const char *reason; - struct GNUNET_TIME_Timestamp expiration; - struct TALER_ReservePublicKeyP reserve_pub; struct GNUNET_JSON_Specification spec[] = { TALER_JSON_spec_amount_any ("total_authorized", - &total_authorized), + &tsr.details.success.total_authorized), TALER_JSON_spec_amount_any ("total_picked_up", - &total_picked_up), + &tsr.details.success.total_picked_up), GNUNET_JSON_spec_string ("reason", - &reason), + &tsr.details.success.reason), GNUNET_JSON_spec_timestamp ("expiration", - &expiration), + &tsr.details.success.expiration), GNUNET_JSON_spec_fixed_auto ("reserve_pub", - &reserve_pub), + &tsr.details.success.reserve_pub), GNUNET_JSON_spec_end () }; @@ -171,8 +148,8 @@ handle_merchant_tip_get_finished (void *cls, spec, NULL, NULL)) { - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + tsr.hr.http_status = 0; + tsr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; } else { @@ -181,75 +158,55 @@ handle_merchant_tip_get_finished (void *cls, if (! json_is_array (pickups)) { tgh->cb (tgh->cb_cls, - &hr, - &total_authorized, - &total_picked_up, - reason, - expiration, - &reserve_pub, - 0, - NULL); + &tsr); TALER_MERCHANT_merchant_tip_get_cancel (tgh); return; } - else if (GNUNET_OK == parse_pickups (pickups, - &total_authorized, - &total_picked_up, - reason, - expiration, - &reserve_pub, - tgh)) + if (GNUNET_OK == + parse_pickups (pickups, + &tsr, + tgh)) { GNUNET_JSON_parse_free (spec); TALER_MERCHANT_merchant_tip_get_cancel (tgh); return; } - else - { - hr.http_status = 0; - hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - } + tsr.hr.http_status = 0; + tsr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; } GNUNET_JSON_parse_free (spec); break; } case MHD_HTTP_UNAUTHORIZED: - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + tsr.hr.ec = TALER_JSON_get_error_code (json); + tsr.hr.hint = TALER_JSON_get_error_hint (json); /* Nothing really to verify, merchant says we need to authenticate. */ break; case MHD_HTTP_NOT_FOUND: /* legal, can happen if instance or tip reserve is unknown */ - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + tsr.hr.ec = TALER_JSON_get_error_code (json); + tsr.hr.hint = TALER_JSON_get_error_hint (json); break; case MHD_HTTP_INTERNAL_SERVER_ERROR: /* Server had an internal issue; we should retry, but this API leaves this to the application */ - hr.ec = TALER_JSON_get_error_code (json); - hr.hint = TALER_JSON_get_error_hint (json); + tsr.hr.ec = TALER_JSON_get_error_code (json); + tsr.hr.hint = TALER_JSON_get_error_hint (json); break; default: /* unexpected response code */ GNUNET_break_op (0); TALER_MERCHANT_parse_error_details_ (json, response_code, - &hr); + &tsr.hr); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d\n", (unsigned int) response_code, - (int) hr.ec); + (int) tsr.hr.ec); break; } tgh->cb (tgh->cb_cls, - &hr, - NULL, - NULL, - NULL, - GNUNET_TIME_UNIT_ZERO_TS, - NULL, - 0, - NULL); + &tsr); TALER_MERCHANT_merchant_tip_get_cancel (tgh); } @@ -258,6 +215,8 @@ struct TALER_MERCHANT_TipMerchantGetHandle * TALER_MERCHANT_merchant_tip_get (struct GNUNET_CURL_Context *ctx, const char *backend_url, const struct TALER_TipIdentifierP *tip_id, + const struct TALER_Amount *min_pick_up, + struct GNUNET_TIME_Relative lp_timeout, bool pickups, TALER_MERCHANT_TipMerchantGetCallback cb, void *cb_cls) @@ -274,6 +233,7 @@ TALER_MERCHANT_merchant_tip_get (struct GNUNET_CURL_Context *ctx, { char res_str[sizeof (*tip_id) * 2]; char arg_str[sizeof (res_str) + 48]; + char timeout_str[32]; char *end; end = GNUNET_STRINGS_data_to_string (tip_id, @@ -285,9 +245,26 @@ TALER_MERCHANT_merchant_tip_get (struct GNUNET_CURL_Context *ctx, sizeof (arg_str), "private/tips/%s", res_str); + GNUNET_snprintf (timeout_str, + sizeof (timeout_str), + "%llu", + ((unsigned long long) + lp_timeout.rel_value_us / + GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us)); tgh->url = TALER_url_join (backend_url, arg_str, - "pickups", pickups ? "yes" : NULL, + "pickups", + pickups + ? "yes" + : NULL, + "min_amount", + min_pick_up + ? TALER_amount2s (min_pick_up) + : NULL, + "timeout_ms", + GNUNET_TIME_relative_is_zero (lp_timeout) + ? NULL + : timeout_str, NULL); } if (NULL == tgh->url) @@ -308,8 +285,8 @@ TALER_MERCHANT_merchant_tip_get (struct GNUNET_CURL_Context *ctx, void -TALER_MERCHANT_merchant_tip_get_cancel (struct - TALER_MERCHANT_TipMerchantGetHandle *tgh) +TALER_MERCHANT_merchant_tip_get_cancel ( + struct TALER_MERCHANT_TipMerchantGetHandle *tgh) { if (NULL != tgh->job) { diff --git a/src/testing/testing_api_cmd_merchant_get_tip.c b/src/testing/testing_api_cmd_merchant_get_tip.c index 1ea5229d..a8e7a67e 100644 --- a/src/testing/testing_api_cmd_merchant_get_tip.c +++ b/src/testing/testing_api_cmd_merchant_get_tip.c @@ -79,25 +79,11 @@ struct MerchantTipGetState * Callback for a GET /private/tips/$TIP_ID operation. * * @param cls closure for this function - * @param hr http response - * @param total_authorized the total amount authorized for the tip - * @param total_picked_up the total amount of the tip that has been picked up - * @param reason why the tip was authorized - * @param expiration when the tip will expire - * @param reserve_pub public key of the reserve the tip is drawing from - * @param pickups_length number of pickups associated with the tip - * @param pickups the array of pickups associated with the tip + * @param tsr response */ static void merchant_get_tip_cb (void *cls, - const struct TALER_MERCHANT_HttpResponse *hr, - const struct TALER_Amount *total_authorized, - const struct TALER_Amount *total_picked_up, - const char *reason, - struct GNUNET_TIME_Timestamp expiration, - const struct TALER_ReservePublicKeyP *reserve_pub, - unsigned int pickups_length, - const struct TALER_MERCHANT_PickupDetail pickups[]) + const struct TALER_MERCHANT_TipStatusResponse *tsr) { struct MerchantTipGetState *gts = cls; const struct TALER_TESTING_Command *authorize_cmd; @@ -107,33 +93,33 @@ merchant_get_tip_cb (void *cls, gts->tip_reference); gts->tgh = NULL; - GNUNET_assert (GNUNET_OK == - TALER_amount_set_zero (total_picked_up->currency, - &expected_total_picked_up)); - if (gts->http_status != hr->http_status) + if (gts->http_status != tsr->hr.http_status) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u (%d) to command %s\n", - hr->http_status, - (int) hr->ec, + tsr->hr.http_status, + (int) tsr->hr.ec, TALER_TESTING_interpreter_get_current_label (gts->is)); TALER_TESTING_interpreter_fail (gts->is); return; } - switch (hr->http_status) + switch (tsr->hr.http_status) { case MHD_HTTP_OK: { const struct TALER_Amount *initial_amount; + GNUNET_assert (GNUNET_OK == + TALER_amount_set_zero (tsr->details.success.total_picked_up.currency, + &expected_total_picked_up)); if (GNUNET_OK != TALER_TESTING_get_trait_amount (authorize_cmd, &initial_amount)) TALER_TESTING_FAIL (gts->is); if ((GNUNET_OK != - TALER_amount_cmp_currency (total_authorized, + TALER_amount_cmp_currency (&tsr->details.success.total_authorized, initial_amount)) || - (0 != TALER_amount_cmp (total_authorized, + (0 != TALER_amount_cmp (&tsr->details.success.total_authorized, initial_amount))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, @@ -149,7 +135,7 @@ merchant_get_tip_cb (void *cls, TALER_TESTING_get_trait_reason (authorize_cmd, &justification)) TALER_TESTING_FAIL (gts->is); - if (0 != strcmp (reason, + if (0 != strcmp (tsr->details.success.reason, *justification)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, @@ -168,7 +154,7 @@ merchant_get_tip_cb (void *cls, TALER_TESTING_FAIL (gts->is); if (GNUNET_TIME_timestamp_cmp (*tip_expiration, !=, - expiration)) + tsr->details.success.expiration)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Tip authorized expiration does not match\n"); @@ -176,7 +162,7 @@ merchant_get_tip_cb (void *cls, return; } } - if (pickups_length != gts->pickups_length) + if (tsr->details.success.pickups_length != gts->pickups_length) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Length of pickups array does not match\n"); @@ -184,7 +170,7 @@ merchant_get_tip_cb (void *cls, return; } { - for (unsigned int i = 0; i < pickups_length; ++i) + for (unsigned int i = 0; i < gts->pickups_length; ++i) { const struct TALER_TESTING_Command *pickup_cmd; @@ -198,7 +184,7 @@ merchant_get_tip_cb (void *cls, &num_planchets)) TALER_TESTING_FAIL (gts->is); - if (*num_planchets != pickups[i].num_planchets) + if (*num_planchets != tsr->details.success.pickups[i].num_planchets) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Pickup planchet count does not match\n"); @@ -216,9 +202,9 @@ merchant_get_tip_cb (void *cls, if ( (GNUNET_OK != TALER_amount_cmp_currency (total, - &pickups[i].requested_amount)) || + &tsr->details.success.pickups[i].requested_amount)) || (0 != TALER_amount_cmp (total, - &pickups[i].requested_amount))) + &tsr->details.success.pickups[i].requested_amount))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Pickup planchet sum does not match\n"); @@ -232,10 +218,10 @@ merchant_get_tip_cb (void *cls, } if ( (GNUNET_OK != TALER_amount_cmp_currency (&expected_total_picked_up, - total_picked_up)) || + &tsr->details.success.total_picked_up)) || (0 != TALER_amount_cmp (&expected_total_picked_up, - total_picked_up)) ) + &tsr->details.success.total_picked_up)) ) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Tip picked up amount does not match\n"); @@ -280,6 +266,8 @@ merchant_get_tip_run (void *cls, tgs->tgh = TALER_MERCHANT_merchant_tip_get (is->ctx, tgs->merchant_url, tip_id, + NULL, + GNUNET_TIME_UNIT_ZERO, tgs->fetch_pickups, &merchant_get_tip_cb, tgs); -- cgit v1.2.3