summaryrefslogtreecommitdiff
path: root/src/bank-lib/fakebank.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2023-08-23 13:47:28 +0200
committerChristian Grothoff <christian@grothoff.org>2023-08-23 13:47:28 +0200
commit50f9cab93d6e457c531ae3c59f53401f59c8f13e (patch)
treec222b28d9d4503a2e093eef343787e0221d79be9 /src/bank-lib/fakebank.c
parent32659fe78b382982bf972ded25881d3ca0c44e81 (diff)
downloadexchange-50f9cab93d6e457c531ae3c59f53401f59c8f13e.tar.gz
exchange-50f9cab93d6e457c531ae3c59f53401f59c8f13e.tar.bz2
exchange-50f9cab93d6e457c531ae3c59f53401f59c8f13e.zip
add anastasis facade to fakebank
Diffstat (limited to 'src/bank-lib/fakebank.c')
-rw-r--r--src/bank-lib/fakebank.c339
1 files changed, 339 insertions, 0 deletions
diff --git a/src/bank-lib/fakebank.c b/src/bank-lib/fakebank.c
index c916ad70c..c0eb41bd7 100644
--- a/src/bank-lib/fakebank.c
+++ b/src/bank-lib/fakebank.c
@@ -4059,6 +4059,323 @@ handle_bank_access (struct TALER_FAKEBANK_Handle *h,
/**
+ * Handle incoming HTTP request for /history/incoming
+ * of the Anastasis API. This one can return transactions
+ * created by debits from the exchange!
+ *
+ * @param h the fakebank handle
+ * @param connection the connection
+ * @param account which account the request is about
+ * @param con_cls closure for request (NULL or &special_ptr)
+ * @return MHD result code
+ */
+static MHD_RESULT
+handle_anastasis_credit_history (
+ struct TALER_FAKEBANK_Handle *h,
+ struct MHD_Connection *connection,
+ const char *account,
+ void **con_cls)
+{
+ struct ConnectionContext *cc = *con_cls;
+ struct HistoryContext *hc;
+ const struct Transaction *pos;
+ enum GNUNET_GenericReturnValue ret;
+
+ if (NULL == cc)
+ {
+ cc = GNUNET_new (struct ConnectionContext);
+ cc->ctx_cleaner = &history_cleanup;
+ *con_cls = cc;
+ hc = GNUNET_new (struct HistoryContext);
+ cc->ctx = hc;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Handling /history/incoming connection %p\n",
+ connection);
+ if (GNUNET_OK !=
+ (ret = parse_history_common_args (h,
+ connection,
+ &hc->ha)))
+ {
+ GNUNET_break_op (0);
+ return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES;
+ }
+ GNUNET_assert (0 ==
+ pthread_mutex_lock (&h->big_lock));
+ hc->acc = lookup_account (h,
+ account,
+ NULL);
+ if (NULL == hc->acc)
+ {
+ GNUNET_assert (0 ==
+ pthread_mutex_unlock (&h->big_lock));
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_BANK_UNKNOWN_ACCOUNT,
+ account);
+ }
+ /* FIXME: was simply: acc->payto_uri -- same!? */
+ GNUNET_asprintf (&hc->payto_uri,
+ "payto://x-taler-bank/localhost/%s?receiver-name=%s",
+ account,
+ hc->acc->receiver_name);
+ GNUNET_assert (0 == strcmp (hc->payto_uri,
+ hc->acc->payto_uri));
+ hc->history = json_array ();
+ if (NULL == hc->history)
+ {
+ GNUNET_break (0);
+ GNUNET_assert (0 ==
+ pthread_mutex_unlock (&h->big_lock));
+ return MHD_NO;
+ }
+ hc->timeout = GNUNET_TIME_relative_to_absolute (hc->ha.lp_timeout);
+ }
+ else
+ {
+ hc = cc->ctx;
+ GNUNET_assert (0 ==
+ pthread_mutex_lock (&h->big_lock));
+ }
+
+ if (! hc->ha.have_start)
+ {
+ pos = (0 > hc->ha.delta)
+ ? hc->acc->in_tail
+ : hc->acc->in_head;
+ }
+ else
+ {
+ struct Transaction *t = h->transactions[hc->ha.start_idx % h->ram_limit];
+ bool overflow;
+ uint64_t dir;
+ bool skip = true;
+
+ overflow = ( (NULL != t) && (t->row_id != hc->ha.start_idx) );
+ dir = (0 > hc->ha.delta) ? (h->ram_limit - 1) : 1;
+ /* If account does not match, linear scan for
+ first matching account. */
+ while ( (! overflow) &&
+ (NULL != t) &&
+ (t->credit_account != hc->acc) )
+ {
+ skip = false;
+ t = h->transactions[(t->row_id + dir) % h->ram_limit];
+ if ( (NULL != t) &&
+ (t->row_id == hc->ha.start_idx) )
+ overflow = true; /* full circle, give up! */
+ }
+ if ( (NULL == t) ||
+ overflow)
+ {
+ /* FIXME: these conditions are unclear to me. */
+ if (GNUNET_TIME_relative_is_zero (hc->ha.lp_timeout) &&
+ (0 < hc->ha.delta))
+ {
+ GNUNET_assert (0 ==
+ pthread_mutex_unlock (&h->big_lock));
+ if (overflow)
+ return TALER_MHD_reply_with_ec (
+ connection,
+ TALER_EC_BANK_ANCIENT_TRANSACTION_GONE,
+ NULL);
+ goto finish;
+ }
+ if (h->in_shutdown)
+ {
+ GNUNET_assert (0 ==
+ pthread_mutex_unlock (&h->big_lock));
+ goto finish;
+ }
+ start_lp (h,
+ connection,
+ hc->acc,
+ GNUNET_TIME_absolute_get_remaining (hc->timeout),
+ LP_CREDIT,
+ NULL);
+ GNUNET_assert (0 ==
+ pthread_mutex_unlock (&h->big_lock));
+ return MHD_YES;
+ }
+ if (skip)
+ {
+ /* range from application is exclusive, skip the
+ matching entry */
+ if (0 > hc->ha.delta)
+ pos = t->prev_in;
+ else
+ pos = t->next_in;
+ }
+ else
+ {
+ pos = t;
+ }
+ }
+ if (NULL != pos)
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Returning %lld credit transactions starting (inclusive) from %llu\n",
+ (long long) hc->ha.delta,
+ (unsigned long long) pos->row_id);
+ while ( (0 != hc->ha.delta) &&
+ (NULL != pos) )
+ {
+ json_t *trans;
+ char *subject;
+
+ if (T_DEBIT != pos->type)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Unexpected CREDIT transaction #%llu for account `%s'\n",
+ (unsigned long long) pos->row_id,
+ account);
+ if (0 > hc->ha.delta)
+ pos = pos->prev_in;
+ if (0 < hc->ha.delta)
+ pos = pos->next_in;
+ continue;
+ }
+
+ {
+ char *wtids;
+
+ wtids = GNUNET_STRINGS_data_to_string_alloc (
+ &pos->subject.debit.wtid,
+ sizeof (pos->subject.debit.wtid));
+ GNUNET_asprintf (&subject,
+ "%s %s",
+ wtids,
+ pos->subject.debit.exchange_base_url);
+ GNUNET_free (wtids);
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Found transaction over %s with subject %s\n",
+ TALER_amount2s (&pos->amount),
+ subject);
+ trans = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_uint64 ("row_id",
+ pos->row_id),
+ GNUNET_JSON_pack_timestamp ("date",
+ pos->date),
+ TALER_JSON_pack_amount ("amount",
+ &pos->amount),
+ GNUNET_JSON_pack_string ("credit_account",
+ hc->payto_uri), // FIXME #7275: inefficient to repeat this always here!
+ GNUNET_JSON_pack_string ("debit_account",
+ pos->debit_account->payto_uri),
+ GNUNET_JSON_pack_string ("subject",
+ subject));
+ GNUNET_free (subject);
+ GNUNET_assert (NULL != trans);
+ GNUNET_assert (0 ==
+ json_array_append_new (hc->history,
+ trans));
+ if (hc->ha.delta > 0)
+ hc->ha.delta--;
+ else
+ hc->ha.delta++;
+ if (0 > hc->ha.delta)
+ pos = pos->prev_in;
+ if (0 < hc->ha.delta)
+ pos = pos->next_in;
+ }
+ if ( (0 == json_array_size (hc->history)) &&
+ (! h->in_shutdown) &&
+ (GNUNET_TIME_absolute_is_future (hc->timeout)) &&
+ (0 < hc->ha.delta))
+ {
+ start_lp (h,
+ connection,
+ hc->acc,
+ GNUNET_TIME_absolute_get_remaining (hc->timeout),
+ LP_CREDIT,
+ NULL);
+ GNUNET_assert (0 ==
+ pthread_mutex_unlock (&h->big_lock));
+ return MHD_YES;
+ }
+ GNUNET_assert (0 ==
+ pthread_mutex_unlock (&h->big_lock));
+finish:
+ if (0 == json_array_size (hc->history))
+ {
+ GNUNET_break (h->in_shutdown ||
+ (! GNUNET_TIME_absolute_is_future (hc->timeout)));
+ return TALER_MHD_reply_static (connection,
+ MHD_HTTP_NO_CONTENT,
+ NULL,
+ NULL,
+ 0);
+ }
+ {
+ json_t *h = hc->history;
+
+ hc->history = NULL;
+ return TALER_MHD_REPLY_JSON_PACK (connection,
+ MHD_HTTP_OK,
+ GNUNET_JSON_pack_array_steal (
+ "incoming_transactions",
+ h));
+ }
+}
+
+
+/**
+ * Handle incoming HTTP request to Anastasis API.
+ *
+ * @param h our handle
+ * @param connection the connection
+ * @param url the requested url
+ * @param method the method (POST, GET, ...)
+ * @param account which account should process the request
+ * @param upload_data request data
+ * @param upload_data_size size of @a upload_data in bytes
+ * @param con_cls closure
+ * @return MHD result code
+ */
+static MHD_RESULT
+handle_anastasis_api (
+ struct TALER_FAKEBANK_Handle *h,
+ struct MHD_Connection *connection,
+ const char *account,
+ const char *url,
+ const char *method,
+ const char *upload_data,
+ size_t *upload_data_size,
+ void **con_cls)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Fakebank - Anastasis API: serving URL `%s' for account `%s'\n",
+ url,
+ account);
+ if (0 == strcasecmp (method,
+ MHD_HTTP_METHOD_GET))
+ {
+ if ( (0 == strcmp (url,
+ "/history/incoming")) &&
+ (NULL != account) )
+ return handle_anastasis_credit_history (h,
+ connection,
+ account,
+ con_cls);
+ if (0 == strcmp (url,
+ "/"))
+ return handle_home_page (h,
+ connection);
+ }
+ /* Unexpected URL path, just close the connection. */
+ TALER_LOG_ERROR ("Breaking URL: %s %s\n",
+ method,
+ url);
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (
+ connection,
+ MHD_HTTP_NOT_FOUND,
+ TALER_EC_GENERIC_ENDPOINT_UNKNOWN,
+ url);
+}
+
+
+/**
* Handle incoming HTTP request.
*
* @param cls a `struct TALER_FAKEBANK_Handle`
@@ -4114,6 +4431,28 @@ handle_mhd_request (void *cls,
con_cls);
}
if (0 == strncmp (url,
+ "/anastasis-api/",
+ strlen ("/anastasis-api/")))
+ {
+ url += strlen ("/anastasis-api");
+ if ( (strlen (url) > 1) &&
+ (NULL != (end = strchr (url + 1, '/'))) )
+ {
+ account = GNUNET_strndup (url + 1,
+ end - url - 1);
+ url = end;
+ }
+ return handle_anastasis_api (h,
+ connection,
+ account,
+ url,
+ method,
+ upload_data,
+ upload_data_size,
+ con_cls);
+ }
+
+ if (0 == strncmp (url,
"/taler-wire-gateway/",
strlen ("/taler-wire-gateway/")))
url += strlen ("/taler-wire-gateway");