gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant] 103/277: towards GET /transfers


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

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

grothoff pushed a commit to branch master
in repository merchant.

commit 47811a60b692e575274305d4cac429220d27a328
Author: Christian Grothoff <christian@grothoff.org>
AuthorDate: Sat May 9 17:13:47 2020 +0200

    towards GET /transfers
---
 .../taler-merchant-httpd_private-get-transfers.c   | 1164 +++-----------------
 1 file changed, 157 insertions(+), 1007 deletions(-)

diff --git a/src/backend/taler-merchant-httpd_private-get-transfers.c 
b/src/backend/taler-merchant-httpd_private-get-transfers.c
index 7f55c91..2316312 100644
--- a/src/backend/taler-merchant-httpd_private-get-transfers.c
+++ b/src/backend/taler-merchant-httpd_private-get-transfers.c
@@ -14,8 +14,8 @@
   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */
 /**
- * @file backend/taler-merchant-httpd_track-transfer.c
- * @brief implement API for tracking transfers and wire transfers
+ * @file backend/taler-merchant-httpd_private-get-transfers.c
+ * @brief implement API for obtaining a list of wire transfers
  * @author Marcello Stanisci
  * @author Christian Grothoff
  */
@@ -31,1058 +31,208 @@
 
 
 /**
- * How long to wait before giving up processing with the exchange?
- */
-#define TRACK_TIMEOUT (GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_SECONDS, \
-                                                      30))
-
-/**
- * How often do we retry the simple INSERT database transaction?
- */
-#define MAX_RETRIES 3
-
-/**
- * Context used for handing /track/transfer requests.
- */
-struct TrackTransferContext
-{
-
-  /**
-   * This MUST be first!
-   */
-  struct TM_HandlerContext hc;
-
-  /**
-   * Handle to the exchange.
-   */
-  struct TALER_EXCHANGE_Handle *eh;
-
-  /**
-   * Handle for the /wire/transfers request.
-   */
-  struct TALER_EXCHANGE_TransfersGetHandle *wdh;
-
-  /**
-   * For which merchant instance is this tracking request?
-   */
-  struct MerchantInstance *mi;
-
-  /**
-   * HTTP connection we are handling.
-   */
-  struct MHD_Connection *connection;
-
-  /**
-   * Response to return upon resume.
-   */
-  struct MHD_Response *response;
-
-  /**
-   * Handle for operation to lookup /keys (and auditors) from
-   * the exchange used for this transaction; NULL if no operation is
-   * pending.
-   */
-  struct TMH_EXCHANGES_FindOperation *fo;
-
-  /**
-   * Task run on timeout.
-   */
-  struct GNUNET_SCHEDULER_Task *timeout_task;
-
-  /**
-   * URL of the exchange.
-   */
-  char *url;
-
-  /**
-   * Wire method used for the transfer.
-   */
-  char *wire_method;
-
-  /**
-   * Pointer to the detail that we are currently
-   * checking in #check_transfer().
-   */
-  const struct TALER_TrackTransferDetails *current_detail;
-
-  /**
-   * Argument for the /wire/transfers request.
-   */
-  struct TALER_WireTransferIdentifierRawP wtid;
-
-  /**
-   * Full original response we are currently processing.
-   */
-  const json_t *original_response;
-
-  /**
-   * Modified response to return to the frontend.
-   */
-  json_t *deposits_response;
-
-  /**
-   * Which transaction detail are we currently looking at?
-   */
-  unsigned int current_offset;
-
-  /**
-   * Response code to return.
-   */
-  unsigned int response_code;
-
-  /**
-   * #GNUNET_NO if we did not find a matching coin.
-   * #GNUNET_SYSERR if we found a matching coin, but the amounts do not match.
-   * #GNUNET_OK if we did find a matching coin.
-   */
-  int check_transfer_result;
-};
-
-
-/**
- * Represents an entry in the table used to sum up
- * individual deposits for each h_contract_terms.
- */
-struct Entry
-{
-
-  /**
-   * Sum accumulator for deposited value.
-   */
-  struct TALER_Amount deposit_value;
-
-  /**
-   * Sum accumulator for deposit fee.
-   */
-  struct TALER_Amount deposit_fee;
-
-};
-
-
-/**
- * Free the @a rctx.
+ * Function called with information about a wire transfer.
+ * Generate a response (array entry) based on the given arguments.
  *
- * @param rctx data to free
+ * @param cls closure with a `json_t *` array to build up the response
+ * @param credit_amount how much was wired to the merchant (minus fees)
+ * @param wtid wire transfer identifier
+ * @param payto_uri target account that received the wire transfer
+ * @param exchange_url base URL of the exchange that made the wire transfer
+ * @param transfer_serial_id serial number identifying the transfer in the 
backend
+ * @param execution_time when did the exchange make the transfer, 
#GNUNET_TIME_UNIT_FOREVER_ABS
+ *           if it did not yet happen
+ * @param verified YES if we checked the exchange's answer and liked it,
+ *                 NO if we checked the exchange's answer and it is 
problematic,
+ *                 ALL if we did not yet check
  */
 static void
-free_transfer_track_context (struct TrackTransferContext *rctx)
+transfer_cb (void *cls,
+             const struct TALER_Amount *credit_amount,
+             const struct TALER_WireTransferIdentifierRawP *wtid,
+             const char *payto_uri,
+             const char *exchange_url,
+             uint64_t transfer_serial_id,
+             struct GNUNET_TIME_Absolute execution_time,
+             enum TALER_MERCHANTDB_YesNoAll verified)
 {
-  if (NULL != rctx->fo)
-  {
-    TMH_EXCHANGES_find_exchange_cancel (rctx->fo);
-    rctx->fo = NULL;
-  }
-  if (NULL != rctx->timeout_task)
-  {
-    GNUNET_SCHEDULER_cancel (rctx->timeout_task);
-    rctx->timeout_task = NULL;
-  }
-  if (NULL != rctx->wdh)
-  {
-    TALER_EXCHANGE_transfers_get_cancel (rctx->wdh);
-    rctx->wdh = NULL;
-  }
-  if (NULL != rctx->url)
-  {
-    GNUNET_free (rctx->url);
-    rctx->url = NULL;
-  }
-  if (NULL != rctx->wire_method)
-  {
-    GNUNET_free (rctx->wire_method);
-    rctx->wire_method = NULL;
-  }
-  GNUNET_free (rctx);
-}
+  json_t *ja = cls;
 
 
-/**
- * Callback that frees all the elements in the hashmap
- *
- * @param cls closure, NULL
- * @param key current key
- * @param value a `struct Entry`
- * @return #GNUNET_YES if the iteration should continue,
- *         #GNUNET_NO otherwise.
- */
-static int
-hashmap_free (void *cls,
-              const struct GNUNET_HashCode *key,
-              void *value)
-{
-  struct TALER_Entry *entry = value;
-
-  (void) cls;
-  (void) key;
-  GNUNET_free (entry);
-  return GNUNET_YES;
 }
 
 
 /**
- * Builds JSON response containing the summed-up amounts
- * from individual deposits.
+ * Manages a GET /private/transfers call.
  *
- * @param cls closure
- * @param key map's current key
- * @param map's current value
- * @return #GNUNET_YES if iteration is to be continued,
- *         #GNUNET_NO otherwise.
+ * @param rh context of the handler
+ * @param connection the MHD connection to handle
+ * @param[in,out] hc context with further information about the request
+ * @return MHD result code
  */
-static int
-build_deposits_response (void *cls,
-                         const struct GNUNET_HashCode *key,
-                         void *value)
+MHD_RESULT
+TMH_private_get_transfers (const struct TMH_RequestHandler *rh,
+                           struct MHD_Connection *connection,
+                           struct TMH_HandlerContext *hc)
 {
-  struct TrackTransferContext *rctx = cls;
-  struct Entry *entry = value;
-  json_t *element;
-  json_t *contract_terms;
-  json_t *order_id;
-
-  db->preflight (db->cls);
-  if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
-      db->find_contract_terms_from_hash (db->cls,
-                                         &contract_terms,
-                                         key,
-                                         &rctx->mi->pubkey))
-  {
-    GNUNET_break_op (0);
-    return GNUNET_NO;
+  const char *payto_uri;
+  struct GNUNET_TIME_Absolute before = GNUNET_TIME_UNIT_FOREVER_ABS;
+  struct GNUNET_TIME_Absolute after = GNUNET_TIME_UNIT_ZERO_ABS;
+  int64_t limit = -20; /* FIXME: default? Nothing documented!!? */
+  uint64_t offset;
+  enum TALER_MERCHANTDB_YesNoAll verified;
+
+  payto_uri = MHD_lookup_connection_value (connection,
+                                           MHD_GET_ARGUMENT_KIND,
+                                           "payto_uri");
+  {
+    const char *before_s;
+
+    before_s = MHD_lookup_connection_value (connection,
+                                            MHD_GET_ARGUMENT_KIND,
+                                            "before");
+    if ( (NULL != before_s) &&
+         (GNUNET_OK !=
+          GNUNET_STRINGS_fancy_time_to_absolute (before_s,
+                                                 &before)) )
+      return TALER_MHD_reply_with_error (connection,
+                                         MHD_HTTP_BAD_REQUEST,
+                                         TALER_EC_PARAMETER_MALFORMED,
+                                         "before");
   }
-
-  order_id = json_object_get (contract_terms,
-                              "order_id");
-  if (NULL == order_id)
   {
-    GNUNET_break_op (0);
-    json_decref (contract_terms);
-    return GNUNET_NO;
+    const char *after_s;
+
+    after_s = MHD_lookup_connection_value (connection,
+                                           MHD_GET_ARGUMENT_KIND,
+                                           "after");
+    if ( (NULL != after_s) &&
+         (GNUNET_OK !=
+          GNUNET_STRINGS_fancy_time_to_absolute (after_s,
+                                                 &after)) )
+      return TALER_MHD_reply_with_error (connection,
+                                         MHD_HTTP_BAD_REQUEST,
+                                         TALER_EC_PARAMETER_MALFORMED,
+                                         "after");
   }
-  element = json_pack ("{s:O, s:o, s:o}",
-                       "order_id", order_id,
-                       "deposit_value", TALER_JSON_from_amount (
-                         &entry->deposit_value),
-                       "deposit_fee", TALER_JSON_from_amount (
-                         &entry->deposit_fee));
-  json_decref (contract_terms);
-  if (NULL == element)
   {
-    GNUNET_break_op (0);
-    return GNUNET_NO;
-  }
-  GNUNET_break (0 ==
-                json_array_append_new (rctx->deposits_response,
-                                       element));
-  return GNUNET_YES;
-}
-
-
-/**
- * Transform /track/transfer result as gotten from the exchange
- * and transforms it in a format liked by the backoffice Web interface.
- *
- * @param result response from exchange's /track/transfer
- * @result pointer to new JSON, or NULL upon errors.
- */
-static json_t *
-transform_response (const json_t *result,
-                    struct TrackTransferContext *rctx)
-{
-  json_t *deposits;
-  json_t *value;
-  json_t *result_mod = NULL;
-  size_t index;
-  const char *key;
-  struct GNUNET_HashCode h_key;
-  struct GNUNET_CONTAINER_MultiHashMap *map;
-  struct TALER_Amount iter_value;
-  struct TALER_Amount iter_fee;
-  struct Entry *current_entry;
-  struct GNUNET_JSON_Specification spec[] = {
-    TALER_JSON_spec_amount ("deposit_value", &iter_value),
-    TALER_JSON_spec_amount ("deposit_fee", &iter_fee),
-    GNUNET_JSON_spec_string ("h_contract_terms", &key),
-    GNUNET_JSON_spec_end ()
-  };
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Transforming /track/transfer response.\n");
-  map = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO);
-  deposits = json_object_get (result,
-                              "deposits");
+    const char *limit_s;
 
-  json_array_foreach (deposits, index, value)
-  {
-    if (GNUNET_OK !=
-        GNUNET_JSON_parse (value,
-                           spec,
-                           NULL,
-                           NULL))
+    limit_s = MHD_lookup_connection_value (connection,
+                                           MHD_GET_ARGUMENT_KIND,
+                                           "limit");
+    if (NULL != limit_s)
     {
-      GNUNET_break_op (0);
-      return NULL;
+      char dummy[2];
+      long long l;
+
+      if (1 !=
+          sscanf (limit_s,
+                  "%lld%1s",
+                  &l,
+                  dummy))
+        return TALER_MHD_reply_with_error (connection,
+                                           MHD_HTTP_BAD_REQUEST,
+                                           TALER_EC_PARAMETER_MALFORMED,
+                                           "limit");
+      limit = (int64_t) l;
     }
-    GNUNET_CRYPTO_hash_from_string (key,
-                                    &h_key);
+  }
+  {
+    const char *offset_s;
 
-    if (NULL != (current_entry =
-                   GNUNET_CONTAINER_multihashmap_get (map,
-                                                      &h_key)))
+    offset_s = MHD_lookup_connection_value (connection,
+                                            MHD_GET_ARGUMENT_KIND,
+                                            "offset");
+    if (NULL != offset_s)
     {
-      /* The map already knows this h_contract_terms*/
-      if ( (0 >
-            TALER_amount_add (&current_entry->deposit_value,
-                              &current_entry->deposit_value,
-                              &iter_value)) ||
-           (0 >
-            TALER_amount_add (&current_entry->deposit_fee,
-                              &current_entry->deposit_fee,
-                              &iter_fee)) )
-      {
-        GNUNET_JSON_parse_free (spec);
-        goto cleanup;
-      }
+      char dummy[2];
+      unsigned long long o;
+
+      if (1 !=
+          sscanf (limit_s,
+                  "%llu%1s",
+                  &o,
+                  dummy))
+        return TALER_MHD_reply_with_error (connection,
+                                           MHD_HTTP_BAD_REQUEST,
+                                           TALER_EC_PARAMETER_MALFORMED,
+                                           "offset");
+      offset = (uint64_t) o;
     }
     else
     {
-      /* First time in the map for this h_contract_terms*/
-      current_entry = GNUNET_new (struct Entry);
-      current_entry->deposit_value = iter_value;
-      current_entry->deposit_fee = iter_fee;
-
-      if (GNUNET_SYSERR ==
-          GNUNET_CONTAINER_multihashmap_put (map,
-                                             &h_key,
-                                             current_entry,
-                                             
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
-      {
-        GNUNET_JSON_parse_free (spec);
-        goto cleanup;
-      }
+      if (limit > 0)
+        offset = INT64_MAX;
+      else
+        offset = 0;
     }
-    GNUNET_JSON_parse_free (spec);
   }
-  rctx->deposits_response = json_array ();
-
-  if (GNUNET_SYSERR ==
-      GNUNET_CONTAINER_multihashmap_iterate (map,
-                                             &build_deposits_response,
-                                             rctx))
-    goto cleanup;
-
-  result_mod = json_copy ((struct json_t *) result);
-  json_object_del (result_mod,
-                   "deposits");
-  json_object_set_new (result_mod,
-                       "deposits_sums",
-                       rctx->deposits_response);
-  rctx->deposits_response = NULL;
-cleanup:
-  GNUNET_CONTAINER_multihashmap_iterate (map,
-                                         &hashmap_free,
-                                         NULL);
-  GNUNET_CONTAINER_multihashmap_destroy (map);
-  return result_mod;
-}
-
-
-/**
- * Resume the given /track/transfer operation and send the given response.
- * Stores the response in the @a rctx and signals MHD to resume
- * the connection.  Also ensures MHD runs immediately.
- *
- * @param rctx transfer tracking context
- * @param response_code response code to use
- * @param response response data to send back
- */
-static void
-resume_track_transfer_with_response (struct TrackTransferContext *rctx,
-                                     unsigned int response_code,
-                                     struct MHD_Response *response)
-{
-  rctx->response_code = response_code;
-  rctx->response = response;
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Resuming /track/transfer handling as exchange interaction is 
done (%u)\n",
-              response_code);
-  if (NULL != rctx->timeout_task)
   {
-    GNUNET_SCHEDULER_cancel (rctx->timeout_task);
-    rctx->timeout_task = NULL;
-  }
-  MHD_resume_connection (rctx->connection);
-  TMH_trigger_daemon (); /* we resumed, kick MHD */
-}
-
-
-/**
- * Custom cleanup routine for a `struct TrackTransferContext`.
- *
- * @param hc the `struct TrackTransferContext` to clean up.
- */
-static void
-track_transfer_cleanup (struct TM_HandlerContext *hc)
-{
-  struct TrackTransferContext *rctx = (struct TrackTransferContext *) hc;
+    const char *verified_s;
 
-  free_transfer_track_context (rctx);
-}
-
-
-/**
- * This function checks that the information about the coin which
- * was paid back by _this_ wire transfer matches what _we_ (the merchant)
- * knew about this coin.
- *
- * @param cls closure with our `struct TrackTransferContext *`
- * @param transaction_id of the contract
- * @param coin_pub public key of the coin
- * @param exchange_url URL of the exchange that issued @a coin_pub
- * @param amount_with_fee amount the exchange will transfer for this coin
- * @param deposit_fee fee the exchange will charge for this coin
- * @param refund_fee fee the exchange will charge for refunding this coin
- * @param exchange_proof proof from exchange that coin was accepted
- */
-static void
-check_transfer (void *cls,
-                const struct GNUNET_HashCode *h_contract_terms,
-                const struct TALER_CoinSpendPublicKeyP *coin_pub,
-                const char *exchange_url,
-                const struct TALER_Amount *amount_with_fee,
-                const struct TALER_Amount *deposit_fee,
-                const struct TALER_Amount *refund_fee,
-                const struct TALER_Amount *wire_fee,
-                const json_t *exchange_proof)
-{
-  struct TrackTransferContext *rctx = cls;
-  const struct TALER_TrackTransferDetails *ttd = rctx->current_detail;
-
-  if (GNUNET_SYSERR == rctx->check_transfer_result)
-    return; /* already had a serious issue; odd that we're called more than 
once as well... */
-  if ( (0 != TALER_amount_cmp (amount_with_fee,
-                               &ttd->coin_value)) ||
-       (0 != TALER_amount_cmp (deposit_fee,
-                               &ttd->coin_fee)) )
-  {
-    /* Disagreement between the exchange and us about how much this
-       coin is worth! */
-    GNUNET_break_op (0);
-    rctx->check_transfer_result = GNUNET_SYSERR;
-    /* Build the `TrackTransferConflictDetails` */
-    rctx->response
-      = TALER_MHD_make_json_pack (
-          "{s:I, s:s, s:o, s:I, s:o, s:o, s:s, s:o, s:o}",
-          "code", (json_int_t) TALER_EC_TRACK_TRANSFER_CONFLICTING_REPORTS,
-          "hint", "disagreement about deposit valuation",
-          "exchange_deposit_proof", exchange_proof,
-          "conflict_offset", (json_int_t) rctx->current_offset,
-          "exchange_transfer_proof", rctx->original_response,
-          "coin_pub", GNUNET_JSON_from_data_auto (coin_pub),
-          "h_contract_terms", GNUNET_JSON_from_data_auto (
-            &ttd->h_contract_terms),
-          "amount_with_fee", TALER_JSON_from_amount (amount_with_fee),
-          "deposit_fee", TALER_JSON_from_amount (deposit_fee));
-    return;
-  }
-  rctx->check_transfer_result = GNUNET_OK;
-}
-
-
-/**
- * Check that the given @a wire_fee is what the
- * @a exchange_pub should charge at the @a execution_time.
- * If the fee is correct (according to our database),
- * return #GNUNET_OK.  If we do not have the fee structure
- * in our DB, we just accept it and return #GNUNET_NO;
- * if we have proof that the fee is bogus, we respond with
- * the proof to the client and return #GNUNET_SYSERR.
- *
- * @param rctx context of the transfer to respond to
- * @param json response from the exchange
- * @param execution_time time of the wire transfer
- * @param wire_fee fee claimed by the exchange
- * @return #GNUNET_SYSERR if we returned hard proof of
- *   missbehavior from the exchange to the client
- */
-static int
-check_wire_fee (struct TrackTransferContext *rctx,
-                const json_t *json,
-                struct GNUNET_TIME_Absolute execution_time,
-                const struct TALER_Amount *wire_fee)
-{
-  const struct TALER_MasterPublicKeyP *master_pub;
-  struct GNUNET_HashCode h_wire_method;
-  struct TALER_Amount expected_fee;
-  struct TALER_Amount closing_fee;
-  struct TALER_MasterSignatureP master_sig;
-  struct GNUNET_TIME_Absolute start_date;
-  struct GNUNET_TIME_Absolute end_date;
-  enum GNUNET_DB_QueryStatus qs;
-  const struct TALER_EXCHANGE_Keys *keys;
-
-  keys = TALER_EXCHANGE_get_keys (rctx->eh);
-  if (NULL == keys)
-  {
-    GNUNET_break (0);
-    return GNUNET_NO;
-  }
-  master_pub = &keys->master_pub;
-  GNUNET_CRYPTO_hash (rctx->wire_method,
-                      strlen (rctx->wire_method) + 1,
-                      &h_wire_method);
-  db->preflight (db->cls);
-  qs = db->lookup_wire_fee (db->cls,
-                            master_pub,
-                            &h_wire_method,
-                            execution_time,
-                            &expected_fee,
-                            &closing_fee,
-                            &start_date,
-                            &end_date,
-                            &master_sig);
-  if (0 >= qs)
-  {
-    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                "Failed to find wire fee for `%s' and method `%s' at %s in DB, 
accepting blindly that the fee is %s\n",
-                TALER_B2S (master_pub),
-                rctx->wire_method,
-                GNUNET_STRINGS_absolute_time_to_string (execution_time),
-                TALER_amount2s (wire_fee));
-    return GNUNET_NO;
-  }
-  if (0 <= TALER_amount_cmp (&expected_fee,
-                             wire_fee))
-    return GNUNET_OK; /* expected_fee >= wire_fee */
-
-  /* Wire fee check failed, export proof to client */
-  resume_track_transfer_with_response (
-    rctx,
-    MHD_HTTP_FAILED_DEPENDENCY,
-    TALER_MHD_make_json_pack (
-      "{s:I, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:O}",
-      "code", (json_int_t) TALER_EC_TRACK_TRANSFER_JSON_BAD_WIRE_FEE,
-      "wire_fee", TALER_JSON_from_amount (wire_fee),
-      "execution_time", GNUNET_JSON_from_time_abs (execution_time),
-      "expected_wire_fee", TALER_JSON_from_amount (&expected_fee),
-      "expected_closing_fee", TALER_JSON_from_amount (&closing_fee),
-      "start_date", GNUNET_JSON_from_time_abs (start_date),
-      "end_date", GNUNET_JSON_from_time_abs (end_date),
-      "master_sig", GNUNET_JSON_from_data_auto (&master_sig),
-      "master_pub", GNUNET_JSON_from_data_auto (master_pub),
-      "json", json));
-  return GNUNET_SYSERR;
-}
-
-
-/**
- * Function called with detailed wire transfer data, including all
- * of the coin transactions that were combined into the wire transfer.
- *
- * @param cls closure
- * @param hr HTTP response details
- * @param exchange_pub public key of the exchange used to sign @a json
- * @param h_wire hash of the wire transfer address the transfer went to, or 
NULL on error
- * @param execution_time time when the exchange claims to have performed the 
wire transfer
- * @param total_amount total amount of the wire transfer, or NULL if the 
exchange could
- *             not provide any @a wtid (set only if @a http_status is 
#MHD_HTTP_OK)
- * @param wire_fee wire fee that was charged by the exchange
- * @param details_length length of the @a details array
- * @param details array with details about the combined transactions
- */
-static void
-wire_transfer_cb (void *cls,
-                  const struct TALER_EXCHANGE_HttpResponse *hr,
-                  const struct TALER_ExchangePublicKeyP *exchange_pub,
-                  const struct GNUNET_HashCode *h_wire,
-                  struct GNUNET_TIME_Absolute execution_time,
-                  const struct TALER_Amount *total_amount,
-                  const struct TALER_Amount *wire_fee,
-                  unsigned int details_length,
-                  const struct TALER_TrackTransferDetails *details)
-{
-  struct TrackTransferContext *rctx = cls;
-  json_t *jresponse;
-  enum GNUNET_DB_QueryStatus qs;
-
-  rctx->wdh = NULL;
-  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
-              "Got response code %u from exchange for /track/transfer\n",
-              hr->http_status);
-  if (MHD_HTTP_OK != hr->http_status)
-  {
-    resume_track_transfer_with_response (
-      rctx,
-      MHD_HTTP_FAILED_DEPENDENCY,
-      TALER_MHD_make_json_pack (
-        "{s:I, s:I, s:I, s:O}",
-        "code", (json_int_t) TALER_EC_TRACK_TRANSFER_EXCHANGE_ERROR,
-        "exchange_code", (json_int_t) hr->ec,
-        "exchange_http_status", (json_int_t) hr->http_status,
-        "exchange_reply", hr->reply));
-    return;
-  }
-  for (unsigned int i = 0; i<MAX_RETRIES; i++)
-  {
-    db->preflight (db->cls);
-    qs = db->store_transfer_to_proof (db->cls,
-                                      rctx->url,
-                                      &rctx->wtid,
-                                      execution_time,
-                                      exchange_pub,
-                                      hr->reply);
-    if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
-      break;
-  }
-  if (0 > qs)
-  {
-    /* Special report if retries insufficient */
-    GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
-    /* Always report on hard error as well to enable diagnostics */
-    GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
-    resume_track_transfer_with_response
-      (rctx,
-      MHD_HTTP_INTERNAL_SERVER_ERROR,
-      TALER_MHD_make_json_pack ("{s:I, s:s}",
-                                "code",
-                                (json_int_t)
-                                
TALER_EC_TRACK_TRANSFER_DB_STORE_TRANSFER_ERROR,
-                                "details",
-                                "failed to store response from exchange to 
local database"));
-    return;
-  }
-  rctx->original_response = hr->reply;
-
-  if (GNUNET_SYSERR ==
-      check_wire_fee (rctx,
-                      hr->reply,
-                      execution_time,
-                      wire_fee))
-    return;
-
-  /* Now we want to double-check that any (Taler coin) deposit
-   * which is accounted into _this_ wire transfer, does exist
-   * into _our_ database.  This is the rationale: if the
-   * exchange paid us for it, we must have received it _beforehands_!
-   *
-   * details_length is how many (Taler coin) deposits have been
-   * aggregated into _this_ wire transfer.
-   *///
-  for (unsigned int i = 0; i<details_length; i++)
-  {
-    rctx->current_offset = i;
-    rctx->current_detail = &details[i];
-    /* Set the coin as "never seen" before. */
-    rctx->check_transfer_result = GNUNET_NO;
-    db->preflight (db->cls);
-    qs = db->find_payments_by_hash_and_coin (db->cls,
-                                             &details[i].h_contract_terms,
-                                             &rctx->mi->pubkey,
-                                             &details[i].coin_pub,
-                                             &check_transfer,
-                                             rctx);
-    if (0 > qs)
-    {
-      /* single, read-only SQL statements should never cause
-         serialization problems */
-      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
-      /* Always report on hard error as well to enable diagnostics */
-      GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
-      resume_track_transfer_with_response
-        (rctx,
-        MHD_HTTP_INTERNAL_SERVER_ERROR,
-        TALER_MHD_make_json_pack ("{s:I, s:s}",
-                                  "code",
-                                  (json_int_t)
-                                  
TALER_EC_TRACK_TRANSFER_DB_FETCH_DEPOSIT_ERROR,
-                                  "details",
-                                  "failed to obtain deposit data from local 
database"));
-      return;
-    }
-    if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
-    {
-      /* The exchange says we made this deposit, but WE do not
-         recall making it (corrupted / unreliable database?)!
-         Well, let's say thanks and accept the money! */
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  "Failed to find payment data in DB\n");
-      rctx->check_transfer_result = GNUNET_OK;
-    }
-    if (GNUNET_NO == rctx->check_transfer_result)
+    verified_s = MHD_lookup_connection_value (connection,
+                                              MHD_GET_ARGUMENT_KIND,
+                                              "verified");
+    if (NULL == verified_s)
     {
-      /* Internal error: how can we have called #check_transfer()
-         but still have no result? */
-      GNUNET_break (0);
-      resume_track_transfer_with_response
-        (rctx,
-        MHD_HTTP_INTERNAL_SERVER_ERROR,
-        TALER_MHD_make_json_pack ("{s:I, s:s, s:I, s:s}",
-                                  "code",
-                                  (json_int_t)
-                                  
TALER_EC_TRACK_TRANSFER_DB_INTERNAL_LOGIC_ERROR,
-                                  "details", "internal logic error",
-                                  "line", (json_int_t) __LINE__,
-                                  "file", __FILE__));
-      return;
+      verified = TALER_MERCHANTDB_YNA_ALL;
     }
-    if (GNUNET_SYSERR == rctx->check_transfer_result)
-    {
-      /* #check_transfer() failed, report conflict! */
-      GNUNET_break_op (0);
-      GNUNET_assert (NULL != rctx->response);
-      resume_track_transfer_with_response
-        (rctx,
-        MHD_HTTP_FAILED_DEPENDENCY,
-        rctx->response);
-      rctx->response = NULL;
-      return;
-    }
-    /* Response is consistent with the /deposit we made,
-       remember it for future reference */
-    for (unsigned int r = 0; r<MAX_RETRIES; r++)
-    {
-      db->preflight (db->cls);
-      qs = db->store_coin_to_transfer (db->cls,
-                                       &details[i].h_contract_terms,
-                                       &details[i].coin_pub,
-                                       &rctx->wtid);
-      if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
-        break;
-    }
-    if (0 > qs)
-    {
-      /* Special report if retries insufficient */
-      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
-      /* Always report on hard error as well to enable diagnostics */
-      GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
-      resume_track_transfer_with_response
-        (rctx,
-        MHD_HTTP_INTERNAL_SERVER_ERROR,
-        TALER_MHD_make_json_pack ("{s:I, s:s}",
-                                  "code",
-                                  (json_int_t)
-                                  TALER_EC_TRACK_TRANSFER_DB_STORE_COIN_ERROR,
-                                  "details",
-                                  "failed to store response from exchange to 
local database"));
-      return;
-    }
-  }
-  rctx->original_response = NULL;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "About to call tracks transformator.\n");
-
-  if (NULL == (jresponse =
-                 transform_response (hr->reply,
-                                     rctx)))
-  {
-    resume_track_transfer_with_response
-      (rctx,
-      MHD_HTTP_INTERNAL_SERVER_ERROR,
-      TALER_MHD_make_error (TALER_EC_TRACK_TRANSFER_JSON_RESPONSE_ERROR,
-                            "Fail to elaborate the response."));
-    return;
-  }
-
-  resume_track_transfer_with_response (rctx,
-                                       MHD_HTTP_OK,
-                                       TALER_MHD_make_json (jresponse));
-  json_decref (jresponse);
-}
-
-
-/**
- * Function called with the result of our exchange lookup.
- *
- * @param cls the `struct TrackTransferContext`
- * @param hr HTTP response details
- * @param eh NULL if exchange was not found to be acceptable
- * @param wire_fee NULL (we did not specify a wire method)
- * @param exchange_trusted #GNUNET_YES if this exchange is trusted by config
- */
-static void
-process_track_transfer_with_exchange (void *cls,
-                                      const struct
-                                      TALER_EXCHANGE_HttpResponse *hr,
-                                      struct TALER_EXCHANGE_Handle *eh,
-                                      const struct TALER_Amount *wire_fee,
-                                      int exchange_trusted)
-{
-  struct TrackTransferContext *rctx = cls;
-
-  rctx->fo = NULL;
-  if (MHD_HTTP_OK != hr->http_status)
-  {
-    /* The request failed somehow */
-    GNUNET_break_op (0);
-    resume_track_transfer_with_response (
-      rctx,
-      MHD_HTTP_FAILED_DEPENDENCY,
-      TALER_MHD_make_json_pack (
-        (NULL != hr->reply)
-        ? "{s:s, s:I, s:I, s:I, s:O}"
-        : "{s:s, s:I, s:I, s:I}",
-        "hint", "failed to obtain meta-data from exchange",
-        "code", (json_int_t) TALER_EC_TRACK_TRANSFER_EXCHANGE_KEYS_FAILURE,
-        "exchange_http_status", (json_int_t) hr->http_status,
-        "exchange_code", (json_int_t) hr->ec,
-        "exchange_reply", hr->reply));
-    return;
-  }
-  rctx->eh = eh;
-  rctx->wdh = TALER_EXCHANGE_transfers_get (eh,
-                                            &rctx->wtid,
-                                            &wire_transfer_cb,
-                                            rctx);
-  if (NULL == rctx->wdh)
-  {
-    GNUNET_break (0);
-    resume_track_transfer_with_response
-      (rctx,
-      MHD_HTTP_INTERNAL_SERVER_ERROR,
-      TALER_MHD_make_json_pack ("{s:I, s:s}",
-                                "code",
-                                (json_int_t)
-                                TALER_EC_TRACK_TRANSFER_REQUEST_ERROR,
-                                "error",
-                                "failed to run /transfers/ GET on exchange"));
-  }
-}
-
-
-/**
- * Handle a timeout for the processing of the track transfer request.
- *
- * @param cls closure
- */
-static void
-handle_track_transfer_timeout (void *cls)
-{
-  struct TrackTransferContext *rctx = cls;
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Resuming /track/transfer with error after timeout\n");
-  rctx->timeout_task = NULL;
-
-  if (NULL != rctx->fo)
-  {
-    TMH_EXCHANGES_find_exchange_cancel (rctx->fo);
-    rctx->fo = NULL;
-  }
-  resume_track_transfer_with_response (rctx,
-                                       MHD_HTTP_SERVICE_UNAVAILABLE,
-                                       TALER_MHD_make_error (
-                                         
TALER_EC_TRACK_TRANSFER_EXCHANGE_TIMEOUT,
-                                         "exchange not reachable"));
-}
-
-
-/**
- * Function called with information about a wire transfer identifier.
- * Generate a response based on the given @a proof.
- *
- * @param cls closure
- * @param proof proof from exchange about what the wire transfer was for.
- *              should match the `TrackTransactionResponse` format
- *              of the exchange
- */
-static void
-proof_cb (void *cls,
-          const json_t *proof)
-{
-  struct TrackTransferContext *rctx = cls;
-  json_t *transformed_response;
-
-  if (NULL == (transformed_response =
-                 transform_response (proof,
-                                     rctx)))
-  {
-    rctx->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
-    rctx->response
-      = TALER_MHD_make_error (TALER_EC_TRACK_TRANSFER_JSON_RESPONSE_ERROR,
-                              "Fail to elaborate response.");
-    return;
-  }
-
-  rctx->response_code = MHD_HTTP_OK;
-  rctx->response = TALER_MHD_make_json (transformed_response);
-  json_decref (transformed_response);
-}
-
-
-/**
- * Manages a /track/transfer call, thus it calls the /track/wtid
- * offered by the exchange in order to return the set of transfers
- * (of coins) associated with a given wire transfer.
- *
- * @param rh context of the handler
- * @param connection the MHD connection to handle
- * @param[in,out] connection_cls the connection's closure (can be updated)
- * @param upload_data upload data
- * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
- * @param mi merchant backend instance, never NULL
- * @return MHD result code
- */
-MHD_RESULT
-MH_handler_track_transfer (struct TMH_RequestHandler *rh,
-                           struct MHD_Connection *connection,
-                           void **connection_cls,
-                           const char *upload_data,
-                           size_t *upload_data_size,
-                           struct MerchantInstance *mi)
-{
-  struct TrackTransferContext *rctx;
-  const char *str;
-  const char *url;
-  const char *wire_method;
-  MHD_RESULT ret;
-  enum GNUNET_DB_QueryStatus qs;
-
-  if (NULL == *connection_cls)
-  {
-    rctx = GNUNET_new (struct TrackTransferContext);
-    rctx->hc.cc = &track_transfer_cleanup;
-    rctx->connection = connection;
-    *connection_cls = rctx;
-  }
-  else
-  {
-    /* not first call, recover state */
-    rctx = *connection_cls;
-  }
-
-  if (0 != rctx->response_code)
-  {
-    /* We are *done* processing the request, just queue the response (!) */
-    if (UINT_MAX == rctx->response_code)
+    else if (0 == strcasecmp (verified_s,
+                              "yes"))
     {
-      GNUNET_break (0);
-      return MHD_NO; /* hard error */
+      verified = TALER_MERCHANTDB_YNA_YES;
     }
-    ret = MHD_queue_response (connection,
-                              rctx->response_code,
-                              rctx->response);
-    if (NULL != rctx->response)
+    else if (0 == strcasecmp (verified_s,
+                              "no"))
     {
-      MHD_destroy_response (rctx->response);
-      rctx->response = NULL;
+      verified = TALER_MERCHANTDB_YNA_NO;
     }
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Queueing response (%u) for /track/transfer (%s).\n",
-                (unsigned int) rctx->response_code,
-                ret ? "OK" : "FAILED");
-    return ret;
-  }
-  if ( (NULL != rctx->fo) ||
-       (NULL != rctx->eh) )
-  {
-    /* likely old MHD version */
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Not sure why we are here, should be suspended\n");
-    return MHD_YES; /* still work in progress */
-  }
-
-  url = MHD_lookup_connection_value (connection,
-                                     MHD_GET_ARGUMENT_KIND,
-                                     "exchange");
-  if (NULL == url)
-    return TALER_MHD_reply_with_error (connection,
-                                       MHD_HTTP_BAD_REQUEST,
-                                       TALER_EC_PARAMETER_MISSING,
-                                       "exchange");
-  rctx->url = GNUNET_strdup (url);
-
-  /* FIXME: change again: we probably don't want the wire_method
-     but rather the _account_ (section) here! */
-  wire_method = MHD_lookup_connection_value (connection,
-                                             MHD_GET_ARGUMENT_KIND,
-                                             "wire_method");
-  if (NULL == wire_method)
-  {
-    if (1)
+    else if (0 == strcasecmp (verified_s,
+                              "all"))
     {
-      /* temporary work-around until demo is adjusted... */
-      GNUNET_break (0);
-      wire_method = "x-taler-bank";
-      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-                  "Client needs fixing, see API change for #4943!\n");
+      verified = TALER_MERCHANTDB_YNA_ALL;
     }
     else
       return TALER_MHD_reply_with_error (connection,
                                          MHD_HTTP_BAD_REQUEST,
-                                         TALER_EC_PARAMETER_MISSING,
-                                         "wire_method");
-  }
-  rctx->wire_method = GNUNET_strdup (wire_method);
-  rctx->mi = mi;
-  str = MHD_lookup_connection_value (connection,
-                                     MHD_GET_ARGUMENT_KIND,
-                                     "wtid");
-  if (NULL == str)
-    return TALER_MHD_reply_with_error (connection,
-                                       MHD_HTTP_BAD_REQUEST,
-                                       TALER_EC_PARAMETER_MISSING,
-                                       "wtid");
-  if (GNUNET_OK !=
-      GNUNET_STRINGS_string_to_data (str,
-                                     strlen (str),
-                                     &rctx->wtid,
-                                     sizeof (rctx->wtid)))
-  {
-    return TALER_MHD_reply_with_error (connection,
-                                       MHD_HTTP_BAD_REQUEST,
-                                       TALER_EC_PARAMETER_MALFORMED,
-                                       "wtid");
+                                         TALER_EC_PARAMETER_MALFORMED,
+                                         "verified");
   }
 
-  /* Check if reply is already in database! */
   db->preflight (db->cls);
-  qs = db->find_proof_by_wtid (db->cls,
-                               rctx->url,
-                               &rctx->wtid,
-                               &proof_cb,
-                               rctx);
-  if (0 > qs)
-  {
-    /* Simple select queries should not cause serialization issues */
-    GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
-    /* Always report on hard error as well to enable diagnostics */
-    GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
-    return TALER_MHD_reply_with_error (connection,
-                                       MHD_HTTP_INTERNAL_SERVER_ERROR,
-                                       
TALER_EC_TRACK_TRANSFER_DB_FETCH_DEPOSIT_ERROR,
-                                       "Fail to query database about proofs");
-  }
-  if (0 != rctx->response_code)
   {
-    ret = MHD_queue_response (connection,
-                              rctx->response_code,
-                              rctx->response);
-    if (NULL != rctx->response)
+    json_t *ja;
+    enum GNUNET_DB_QueryStatus qs;
+
+    ja = json_array ();
+    GNUNET_assert (NULL != ja);
+    qs = TMH_db->lookup_transfers (TMH_db->cls,
+                                   hc->instance->settings.id,
+                                   payto_uri,
+                                   before,
+                                   after,
+                                   limit,
+                                   offset,
+                                   verified,
+                                   &transfer_cb,
+                                   ja);
+    if (0 > qs)
     {
-      MHD_destroy_response (rctx->response);
-      rctx->response = NULL;
+      /* Simple select queries should not cause serialization issues */
+      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
+      /* Always report on hard error as well to enable diagnostics */
+      GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
+      return TALER_MHD_reply_with_error (connection,
+                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
+                                         
TALER_EC_GET_TRANSFERS_DB_FETCH_DEPOSIT_ERROR,
+                                         "Fail to query database about 
transfers");
     }
-    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                "Queueing response (%u) for /track/transfer (%s).\n",
-                (unsigned int) rctx->response_code,
-                ret ? "OK" : "FAILED");
-    return ret;
+    return MHD_MHD_reply_json_pack (connection,
+                                    MHD_HTTP_OK,
+                                    "{s:o}",
+                                    "transfers", ja);
   }
-
-  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Suspending /track/transfer handling while working with the 
exchange\n");
-  MHD_suspend_connection (connection);
-  rctx->fo = TMH_EXCHANGES_find_exchange (url,
-                                          NULL,
-                                          GNUNET_NO,
-                                          
&process_track_transfer_with_exchange,
-                                          rctx);
-  rctx->timeout_task
-    = GNUNET_SCHEDULER_add_delayed (TRACK_TIMEOUT,
-                                    &handle_track_transfer_timeout,
-                                    rctx);
-  return MHD_YES;
 }
 
 

-- 
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]