gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-merchant] 107/277: implement GET /transfers


From: gnunet
Subject: [taler-merchant] 107/277: implement GET /transfers
Date: Sun, 05 Jul 2020 20:50:20 +0200

This is an automated email from the git hooks/post-receive script.

grothoff pushed a commit to branch master
in repository merchant.

commit a48af85c36a3340ee9303b57428f2929b08995e4
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Wed May 13 15:43:07 2020 +0200

    implement GET /transfers
---
 src/include/taler_merchant_service.h |   2 +-
 src/lib/Makefile.am                  |   3 +-
 src/lib/merchant_api_get_transfers.c | 352 +++++++++++++++++++----------------
 3 files changed, 197 insertions(+), 160 deletions(-)

diff --git a/src/include/taler_merchant_service.h 
b/src/include/taler_merchant_service.h
index 7c51d1c..850bf15 100644
--- a/src/include/taler_merchant_service.h
+++ b/src/include/taler_merchant_service.h
@@ -2355,7 +2355,7 @@ TALER_MERCHANT_transfers_get (
   uint64_t offset,
   enum TALER_MERCHANT_YesNoAll verified,
   TALER_MERCHANT_GetTransfersCallback cb,
-  void *cls);
+  void *cb_cls);
 
 
 /**
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index e0d164d..ecb5e9a 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -20,9 +20,10 @@ libtalermerchant_la_SOURCES = \
   merchant_api_get_config.c \
   merchant_api_get_instance.c \
   merchant_api_get_instances.c \
+  merchant_api_get_orders.c \
   merchant_api_get_product.c \
   merchant_api_get_products.c \
-  merchant_api_get_orders.c \
+  merchant_api_get_transfers.c \
   merchant_api_lock_product.c \
   merchant_api_patch_instance.c \
   merchant_api_patch_product.c \
diff --git a/src/lib/merchant_api_get_transfers.c 
b/src/lib/merchant_api_get_transfers.c
index 5743f2f..ac8382c 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.
@@ -65,97 +64,11 @@ 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 */

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]