summaryrefslogtreecommitdiff
path: root/src/lib/merchant_api_get_transfers.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2020-05-13 15:43:07 +0200
committerChristian Grothoff <christian@grothoff.org>2020-05-13 15:43:07 +0200
commita48af85c36a3340ee9303b57428f2929b08995e4 (patch)
tree11b5552e86068fecc681b4c887e97289ad0972b7 /src/lib/merchant_api_get_transfers.c
parent8919c5664bd46cba5952f34f4914d5ccb01e452a (diff)
downloadmerchant-a48af85c36a3340ee9303b57428f2929b08995e4.tar.gz
merchant-a48af85c36a3340ee9303b57428f2929b08995e4.tar.bz2
merchant-a48af85c36a3340ee9303b57428f2929b08995e4.zip
implement GET /transfers
Diffstat (limited to 'src/lib/merchant_api_get_transfers.c')
-rw-r--r--src/lib/merchant_api_get_transfers.c352
1 files changed, 194 insertions, 158 deletions
diff --git a/src/lib/merchant_api_get_transfers.c b/src/lib/merchant_api_get_transfers.c
index 5743f2fe..ac8382ca 100644
--- a/src/lib/merchant_api_get_transfers.c
+++ b/src/lib/merchant_api_get_transfers.c
@@ -15,9 +15,8 @@
<http://www.gnu.org/licenses/>
*/
/**
- * @file lib/merchant_api_track_transfer.c
- * @brief Implementation of the /track/transfer request of the
- * merchant's HTTP API
+ * @file lib/merchant_api_get_transfers.c
+ * @brief Implementation of the GET /transfers request of the merchant's HTTP API
* @author Marcello Stanisci
* @author Christian Grothoff
*/
@@ -35,7 +34,7 @@
/**
* @brief A Handle for tracking wire transfers.
*/
-struct TALER_MERCHANT_TrackTransferHandle
+struct TALER_MERCHANT_GetTransfersHandle
{
/**
@@ -51,7 +50,7 @@ struct TALER_MERCHANT_TrackTransferHandle
/**
* Function to call with the result.
*/
- TALER_MERCHANT_TrackTransferCallback cb;
+ TALER_MERCHANT_GetTransfersCallback cb;
/**
* Closure for @a cb.
@@ -66,96 +65,10 @@ struct TALER_MERCHANT_TrackTransferHandle
/**
- * We got a #MHD_HTTP_OK response for the /track/transfer request.
- * Check that the response is well-formed and if it is, call the
- * callback. If not, return an error code.
- *
- * This code is very similar to
- * exchange_api_transfers_get.c::check_transfers_get_response_ok.
- * (Except we do not check the signature, as that was done by the
- * backend which we trust already.)
- * Any changes should likely be reflected there as well.
- *
- * @param wdh handle to the operation
- * @param json response we got
- * @return #GNUNET_OK if we are done and all is well,
- * #GNUNET_SYSERR if the response was bogus
- */
-static int
-check_transfers_get_response_ok (
- struct TALER_MERCHANT_TrackTransferHandle *wdh,
- const json_t *json)
-{
- json_t *deposits;
- struct GNUNET_HashCode h_wire;
- struct TALER_Amount total_amount;
- struct TALER_MerchantPublicKeyP merchant_pub;
- unsigned int num_details;
- struct TALER_ExchangePublicKeyP exchange_pub;
- struct GNUNET_JSON_Specification inner_spec[] = {
- TALER_JSON_spec_amount ("total", &total_amount),
- GNUNET_JSON_spec_fixed_auto ("merchant_pub", &merchant_pub),
- GNUNET_JSON_spec_fixed_auto ("h_wire", &h_wire),
- GNUNET_JSON_spec_json ("deposits_sums", &deposits),
- GNUNET_JSON_spec_fixed_auto ("exchange_pub", &exchange_pub),
- GNUNET_JSON_spec_end ()
- };
- struct TALER_MERCHANT_HttpResponse hr = {
- .http_status = MHD_HTTP_OK,
- .reply = json
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (json,
- inner_spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- num_details = json_array_size (deposits);
- {
- struct TALER_MERCHANT_TrackTransferDetails details[num_details];
-
- for (unsigned int i = 0; i<num_details; i++)
- {
- struct TALER_MERCHANT_TrackTransferDetails *detail = &details[i];
- json_t *deposit = json_array_get (deposits, i);
- struct GNUNET_JSON_Specification spec_detail[] = {
- GNUNET_JSON_spec_string ("order_id", &detail->order_id),
- TALER_JSON_spec_amount ("deposit_value", &detail->deposit_value),
- TALER_JSON_spec_amount ("deposit_fee", &detail->deposit_fee),
- GNUNET_JSON_spec_end ()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (deposit,
- spec_detail,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (inner_spec);
- return GNUNET_SYSERR;
- }
- }
- wdh->cb (wdh->cb_cls,
- &hr,
- &exchange_pub,
- &h_wire,
- &total_amount,
- num_details,
- details);
- }
- GNUNET_JSON_parse_free (inner_spec);
- return GNUNET_OK;
-}
-
-
-/**
* Function called when we're done processing the
- * HTTP /track/transfer request.
+ * HTTP GET /transfers request.
*
- * @param cls the `struct TALER_MERCHANT_TrackTransferHandle`
+ * @param cls the `struct TALER_MERCHANT_GetTransfersHandle`
* @param response_code HTTP response code, 0 on error
* @param json response body, NULL if not in JSON
*/
@@ -164,37 +77,110 @@ handle_transfers_get_finished (void *cls,
long response_code,
const void *response)
{
- struct TALER_MERCHANT_TrackTransferHandle *tdo = cls;
+ struct TALER_MERCHANT_GetTransfersHandle *gth = cls;
const json_t *json = response;
struct TALER_MERCHANT_HttpResponse hr = {
.http_status = (unsigned int) response_code,
.reply = json
};
- tdo->job = NULL;
+ gth->job = NULL;
switch (response_code)
{
case 0:
hr.ec = TALER_EC_INVALID_RESPONSE;
break;
case MHD_HTTP_OK:
- if (GNUNET_OK ==
- check_transfers_get_response_ok (tdo,
- json))
{
- TALER_MERCHANT_track_transfer_cancel (tdo);
- return;
+ json_t *transfers;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_json ("transfers",
+ &transfers),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ hr.http_status = 0;
+ hr.ec = TALER_EC_INVALID_RESPONSE;
+ break;
+ }
+ else
+ {
+ size_t tds_length;
+ struct TALER_MERCHANT_TransferData *tds;
+ json_t *transfer;
+ unsigned int i;
+ bool ok;
+
+ if (! json_is_array (transfers))
+ {
+ GNUNET_break_op (0);
+ GNUNET_JSON_parse_free (spec);
+ hr.http_status = 0;
+ hr.ec = TALER_EC_INVALID_RESPONSE;
+ break;
+ }
+ tds_length = json_array_size (transfers);
+ tds = GNUNET_new_array (tds_length,
+ struct TALER_MERCHANT_TransferData);
+ ok = true;
+ json_array_foreach (transfers, i, transfer) {
+ struct TALER_MERCHANT_TransferData *td = &tds[i];
+ struct GNUNET_JSON_Specification ispec[] = {
+ TALER_JSON_spec_amount ("credit_amount",
+ &td->credit_amount),
+ GNUNET_JSON_spec_fixed_auto ("wtid",
+ &td->wtid),
+ GNUNET_JSON_spec_string ("payto_uri",
+ &td->payto_uri),
+ GNUNET_JSON_spec_string ("exchange_url",
+ &td->exchange_url),
+ GNUNET_JSON_spec_uint64 ("credit_serial",
+ &td->credit_serial),
+ GNUNET_JSON_spec_absolute_time ("execution_time",
+ &td->execution_time),
+ GNUNET_JSON_spec_bool ("verified",
+ &td->verified),
+ GNUNET_JSON_spec_bool ("confirmed",
+ &td->confirmed),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (transfer,
+ ispec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ ok = false;
+ break;
+ }
+ }
+
+ if (! ok)
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (tds);
+ GNUNET_JSON_parse_free (spec);
+ hr.http_status = 0;
+ hr.ec = TALER_EC_INVALID_RESPONSE;
+ break;
+ }
+ gth->cb (gth->cb_cls,
+ &hr,
+ tds_length,
+ tds);
+ GNUNET_free (tds);
+ GNUNET_JSON_parse_free (spec);
+ TALER_MERCHANT_transfers_get_cancel (gth);
+ return;
+ }
}
- GNUNET_break_op (0);
- hr.http_status = 0;
- hr.ec = TALER_EC_INVALID_RESPONSE; // TODO: use more specific code!
- break;
- case MHD_HTTP_FAILED_DEPENDENCY:
- /* Not a reason to break execution. */
- TALER_MERCHANT_parse_error_details_ (json,
- response_code,
- &hr);
- break;
case MHD_HTTP_NOT_FOUND:
/* Nothing really to verify, this should never
happen, we should pass the JSON reply to the application */
@@ -220,95 +206,145 @@ handle_transfers_get_finished (void *cls,
response_code = 0;
break;
}
- tdo->cb (tdo->cb_cls,
+ gth->cb (gth->cb_cls,
&hr,
- NULL,
- NULL,
- NULL,
0,
NULL);
- TALER_MERCHANT_track_transfer_cancel (tdo);
+ TALER_MERCHANT_transfers_get_cancel (gth);
}
/**
- * Request backend to return transfers associated with a given wtid.
+ * Request backend to return list of all wire transfers that
+ * we received (or that the exchange claims we should have received).
+ *
+ * Note that when filtering by timestamp (using “before” and/or “after”), we
+ * use the time reported by the exchange and thus will ONLY return results for
+ * which we already have a response from the exchange. This should be
+ * virtually all transfers, however it is conceivable that for some transfer
+ * the exchange responded with a temporary error (i.e. HTTP status 500+) and
+ * then we do not yet have an execution time to filter by. Thus, IF timestamp
+ * filters are given, transfers for which we have no response from the
+ * exchange yet are automatically excluded.
*
* @param ctx execution context
* @param backend_url base URL of the backend
- * @param wire_method wire method used for the wire transfer
- * @param wtid base32 string indicating a wtid
- * @param exchange_url base URL of the exchange in charge of returning the wanted information
- * @param track_transfer_cb the callback to call when a reply for this request is available
- * @param track_transfer_cb_cls closure for @a contract_cb
+ * @param payto_uri filter by this credit account of the merchant
+ * @param before limit to transactions before this timestamp, use
+ * #GNUNET_TIME_UNIT_FOREVER_ABS to not filter by @a before
+ * @param after limit to transactions after this timestamp, use
+ * #GNUNET_TIME_UNIT_ZERO_ABS to not filter by @a after
+ * @param limit return at most ths number of results; negative to descend in execution time
+ * @param offset start at this "credit serial" number (exclusive)
+ * @param verified filter results by verification status
+ * @param cb the callback to call when a reply for this request is available
+ * @param cb_cls closure for @a cb
* @return a handle for this request
*/
-struct TALER_MERCHANT_TrackTransferHandle *
-TALER_MERCHANT_track_transfer (
+struct TALER_MERCHANT_GetTransfersHandle *
+TALER_MERCHANT_transfers_get (
struct GNUNET_CURL_Context *ctx,
const char *backend_url,
- const char *wire_method,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- const char *exchange_url,
- TALER_MERCHANT_TrackTransferCallback track_transfer_cb,
- void *track_transfer_cb_cls)
+ const char *payto_uri,
+ const struct GNUNET_TIME_Absolute before,
+ const struct GNUNET_TIME_Absolute after,
+ int64_t limit,
+ uint64_t offset,
+ enum TALER_MERCHANT_YesNoAll verified,
+ TALER_MERCHANT_GetTransfersCallback cb,
+ void *cb_cls)
{
- struct TALER_MERCHANT_TrackTransferHandle *tdo;
+ struct TALER_MERCHANT_GetTransfersHandle *gth;
CURL *eh;
- char *wtid_str;
+ const char *verified_s = NULL;
+ char limit_s[30];
+ char offset_s[30];
+ char *before_s;
+ char *after_s;
- wtid_str = GNUNET_STRINGS_data_to_string_alloc (
- wtid,
- sizeof (struct TALER_WireTransferIdentifierRawP));
- tdo = GNUNET_new (struct TALER_MERCHANT_TrackTransferHandle);
- tdo->ctx = ctx;
- tdo->cb = track_transfer_cb; // very last to be called
- tdo->cb_cls = track_transfer_cb_cls;
- tdo->url = TALER_url_join (backend_url, "track/transfer",
- "wtid", wtid_str,
- "exchange", exchange_url,
- "wire_method", wire_method,
+ gth = GNUNET_new (struct TALER_MERCHANT_GetTransfersHandle);
+ gth->ctx = ctx;
+ gth->cb = cb;
+ gth->cb_cls = cb_cls;
+ if (TALER_MERCHANT_YNA_YES == verified)
+ verified_s = "yes";
+ if (TALER_MERCHANT_YNA_NO == verified)
+ verified_s = "no";
+ GNUNET_snprintf (limit_s,
+ sizeof (limit_s),
+ "%lld",
+ (long long) limit);
+ GNUNET_snprintf (offset_s,
+ sizeof (offset_s),
+ "%lld",
+ (unsigned long long) offset);
+ before_s = GNUNET_strdup (GNUNET_STRINGS_absolute_time_to_string (before));
+ after_s = GNUNET_strdup (GNUNET_STRINGS_absolute_time_to_string (after));
+ gth->url = TALER_url_join (backend_url,
+ "transfers",
+ "payto_uri",
+ payto_uri,
+ "verified",
+ verified_s,
+ "limit",
+ 0 != limit
+ ? limit_s
+ : NULL,
+ "offset",
+ ((0 != offset) && (UINT64_MAX != offset))
+ ? offset_s
+ : NULL,
+ "before",
+ before.abs_value_us !=
+ GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us
+ ? before_s
+ : NULL,
+ "after",
+ after.abs_value_us != 0
+ ? after_s
+ : NULL,
NULL);
- GNUNET_free (wtid_str);
- if (NULL == tdo->url)
+ GNUNET_free (before_s);
+ GNUNET_free (after_s);
+ if (NULL == gth->url)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Could not construct request URL.\n");
- GNUNET_free (tdo);
+ GNUNET_free (gth);
return NULL;
}
eh = curl_easy_init ();
GNUNET_assert (CURLE_OK ==
curl_easy_setopt (eh,
CURLOPT_URL,
- tdo->url));
- tdo->job = GNUNET_CURL_job_add (ctx,
+ gth->url));
+ gth->job = GNUNET_CURL_job_add (ctx,
eh,
GNUNET_YES,
&handle_transfers_get_finished,
- tdo);
- return tdo;
+ gth);
+ return gth;
}
/**
- * Cancel a /track/transfer request. This function cannot be used
+ * Cancel a GET /transfers request. This function cannot be used
* on a request handle if a response is already served for it.
*
- * @param tdo handle to the tracking operation being cancelled
+ * @param gth handle to the tracking operation being cancelled
*/
void
-TALER_MERCHANT_track_transfer_cancel (
- struct TALER_MERCHANT_TrackTransferHandle *tdo)
+TALER_MERCHANT_transfers_get_cancel (
+ struct TALER_MERCHANT_GetTransfersHandle *gth)
{
- if (NULL != tdo->job)
+ if (NULL != gth->job)
{
- GNUNET_CURL_job_cancel (tdo->job);
- tdo->job = NULL;
+ GNUNET_CURL_job_cancel (gth->job);
+ gth->job = NULL;
}
- GNUNET_free (tdo->url);
- GNUNET_free (tdo);
+ GNUNET_free (gth->url);
+ GNUNET_free (gth);
}
-/* end of merchant_api_track_transfer.c */
+/* end of merchant_api_get_transfers.c */