From ed0da1fdb3e85a0d19148b3ec9eb481e8c06c025 Mon Sep 17 00:00:00 2001 From: Marcello Stanisci Date: Mon, 8 Apr 2019 23:53:52 +0200 Subject: /history-range. Implementing the "lib" and "testing-lib" functions to use it. --- src/bank-lib/bank_api_history.c | 333 +++++++++++++++++++++++++++++----------- 1 file changed, 242 insertions(+), 91 deletions(-) (limited to 'src/bank-lib/bank_api_history.c') diff --git a/src/bank-lib/bank_api_history.c b/src/bank-lib/bank_api_history.c index ab757a2d2..4b9ea3c3c 100644 --- a/src/bank-lib/bank_api_history.c +++ b/src/bank-lib/bank_api_history.c @@ -2,22 +2,26 @@ This file is part of TALER Copyright (C) 2017 GNUnet e.V. & Inria - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see - + TALER is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 3, + or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, + see */ /** * @file bank-lib/bank_api_history.c - * @brief Implementation of the /history requests of the bank's HTTP API + * @brief Implementation of the /history[-range] + * requests of the bank's HTTP API. * @author Christian Grothoff + * @author Marcello Stanisci */ #include "platform.h" #include "bank_api_common.h" @@ -60,7 +64,23 @@ struct TALER_BANK_HistoryHandle * Closure for @a cb. */ void *hcb_cls; +}; + + +/** + * Represent a URL argument+value pair. + */ +struct HistoryArgumentURL +{ + /** + * Name of the URL argument. + */ + char argument[20]; + /** + * Value of the URL argument. + */ + char value[20]; }; @@ -248,24 +268,202 @@ handle_history_finished (void *cls, } + +/** + * Backend of both the /history[-range] requests. + * + * @param ctx curl context for the event loop + * @param bank_base_url base URL of the bank. + * @param urlargs path + URL arguments. + * @param auth authentication data to use + * @param hres_cb the callback to call with the transaction + * history + * @param hres_cb_cls closure for the above callback + * @return NULL if the inputs are invalid (i.e. zero value for + * @e num_results). In this case, the callback is not + * called. + */ +static struct TALER_BANK_HistoryHandle * +put_history_job (struct GNUNET_CURL_Context *ctx, + const char *bank_base_url, + const char *urlargs, + const struct TALER_BANK_AuthenticationData *auth, + TALER_BANK_HistoryResultCallback hres_cb, + void *hres_cb_cls) +{ + struct TALER_BANK_HistoryHandle *hh; + CURL *eh; + + hh = GNUNET_new (struct TALER_BANK_HistoryHandle); + hh->hcb = hres_cb; + hh->hcb_cls = hres_cb_cls; + hh->bank_base_url = GNUNET_strdup (bank_base_url); + hh->request_url = TALER_BANK_path_to_url_ (bank_base_url, + urlargs); + + hh->authh = TALER_BANK_make_auth_header_ (auth); + eh = curl_easy_init (); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_HTTPHEADER, + hh->authh)); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_URL, + hh->request_url)); + hh->job = GNUNET_CURL_job_add (ctx, + eh, + GNUNET_NO, + &handle_history_finished, + hh); + return hh; +} + + +/** + * Convert fixed value 'direction' into string. + * + * @param direction the value to convert. + * @return string representation of @a direction. When length + * is zero, an error occurred. + */ +static struct HistoryArgumentURL +conv_direction (enum TALER_BANK_Direction direction) +{ + struct HistoryArgumentURL ret; + + if (TALER_BANK_DIRECTION_NONE == direction) + { + /* Should just never happen. */ + GNUNET_assert (0); + return ret; + } + + if (TALER_BANK_DIRECTION_BOTH == + (TALER_BANK_DIRECTION_BOTH & direction)) + strcpy (&ret.value[0], + "both"); + else if (TALER_BANK_DIRECTION_CREDIT == + (TALER_BANK_DIRECTION_CREDIT & direction)) + strcpy (&ret.value[0], + "credit"); + else if (TALER_BANK_DIRECTION_DEBIT == + (TALER_BANK_DIRECTION_BOTH & direction)) /*why use 'both' flag?*/ + strcpy (&ret.value[0], + "debit"); + return ret; +} + + +/** + * Convert fixed value 'direction' into string representation + * of the "cancel" argument. + * + * @param direction the value to convert. + * @return string representation of @a direction. When length + * is zero, an error occurred. + */ +static struct HistoryArgumentURL +conv_cancel (enum TALER_BANK_Direction direction) +{ + struct HistoryArgumentURL ret; + + if (TALER_BANK_DIRECTION_CANCEL == + (TALER_BANK_DIRECTION_CANCEL & direction)) + strcpy (&ret.value[0], + "show"); + else + strcpy (&ret.value[0], + "omit"); + return ret; +} + +/** + * Request the wire transfer history of a bank account, + * using time stamps to narrow the results. + * + * @param ctx curl context for the event loop + * @param bank_base_url URL of the bank (used to execute this + * request) + * @param auth authentication data to use + * @param account_number which account number should we query + * @param direction what kinds of wire transfers should be + * returned + * @param ascending if GNUNET_YES, history elements will + * be returned in chronological order. + * @param start_date threshold for oldest result. + * @param end_date threshold for youngest result. + * @param hres_cb the callback to call with the transaction + * history + * @param hres_cb_cls closure for the above callback + * @return NULL if the inputs are invalid (i.e. zero value for + * @e num_results). In this case, the callback is not + * called. + */ +struct TALER_BANK_HistoryHandle * +TALER_BANK_history_range (struct GNUNET_CURL_Context *ctx, + const char *bank_base_url, + const struct TALER_BANK_AuthenticationData *auth, + uint64_t account_number, + enum TALER_BANK_Direction direction, + unsigned int ascending, + struct GNUNET_TIME_Absolute start_date, + struct GNUNET_TIME_Absolute end_date, + TALER_BANK_HistoryResultCallback hres_cb, + void *hres_cb_cls) +{ + struct TALER_BANK_HistoryHandle *hh; + char *url; + + GNUNET_TIME_round_abs (&start_date); + GNUNET_TIME_round_abs (&end_date); + + GNUNET_asprintf (&url, + "/history?auth=basic&account_number=%llu&start=%llu&end=%llu&direction=%s&cancelled=%s&ordering=%s", + (unsigned long long) account_number, + start_date.abs_value_us / 1000LL / 1000LL, + end_date.abs_value_us / 1000LL / 1000LL, + conv_direction (direction).value, + conv_cancel (direction).value, + (GNUNET_YES == ascending) ? "ascending" : "descending"); + + hh = put_history_job (ctx, + bank_base_url, + url, + auth, + hres_cb, + hres_cb_cls); + + GNUNET_free (url); + return hh; +} + + + /** * Request the wire transfer history of a bank account. * * @param ctx curl context for the event loop - * @param bank_base_url URL of the bank (used to execute this request) + * @param bank_base_url URL of the bank (used to execute this + * request) * @param auth authentication data to use * @param account_number which account number should we query - * @param direction what kinds of wire transfers should be returned - * @param ascending if GNUNET_YES, history elements will be returned in chronological order. - * @param start_row from which row on do we want to get results, use UINT64_MAX for the latest; exclusive - * @param num_results how many results do we want; negative numbers to go into the past, - * positive numbers to go into the future starting at @a start_row; - * must not be zero. - * @param hres_cb the callback to call with the transaction history + * @param direction what kinds of wire transfers should be + * returned + * @param ascending if GNUNET_YES, history elements will + * be returned in chronological order. + * @param start_row from which row on do we want to get results, + * use UINT64_MAX for the latest; exclusive + * @param num_results how many results do we want; + * negative numbers to go into the past, positive numbers + * to go into the future starting at @a start_row; + * must not be zero. + * @param hres_cb the callback to call with the transaction + * history * @param hres_cb_cls closure for the above callback - * @return NULL - * if the inputs are invalid (i.e. zero value for @e num_results). - * In this case, the callback is not called. + * @return NULL if the inputs are invalid (i.e. zero value for + * @e num_results). In this case, the callback is not + * called. */ struct TALER_BANK_HistoryHandle * TALER_BANK_history (struct GNUNET_CURL_Context *ctx, @@ -280,91 +478,44 @@ TALER_BANK_history (struct GNUNET_CURL_Context *ctx, void *hres_cb_cls) { struct TALER_BANK_HistoryHandle *hh; - CURL *eh; char *url; - const char *dir; - const char *can; if (0 == num_results) { GNUNET_break (0); return NULL; } - if (TALER_BANK_DIRECTION_NONE == direction) - { - GNUNET_break (0); - return NULL; - } - - dir = NULL; - if (TALER_BANK_DIRECTION_BOTH == (TALER_BANK_DIRECTION_BOTH & direction)) - dir = "both"; - else if (TALER_BANK_DIRECTION_CREDIT == (TALER_BANK_DIRECTION_CREDIT & direction)) - dir = "credit"; - else if (TALER_BANK_DIRECTION_DEBIT == (TALER_BANK_DIRECTION_BOTH & direction)) - dir = "debit"; - if (NULL == dir) - { - GNUNET_break (0); - return NULL; - } - if (TALER_BANK_DIRECTION_CANCEL == (TALER_BANK_DIRECTION_CANCEL & direction)) - can = "show"; - else - can = "omit"; + GNUNET_asprintf (&url, + "/history?auth=basic&account_number=%llu&delta=%lld&direction=%s&cancelled=%s&ordering=%s&start=%llu", + (unsigned long long) account_number, + (long long) num_results, + conv_direction (direction).value, + conv_cancel (direction).value, + (GNUNET_YES == ascending) ? "ascending" : "descending", + start_row); + + /* Locate and "cut" the 'start' argument, + * if the user didn't provide one. */ if (UINT64_MAX == start_row) - { - GNUNET_asprintf (&url, - "/history?auth=basic&account_number=%llu&delta=%lld&direction=%s&cancelled=%s&ordering=%s", - (unsigned long long) account_number, - (long long) num_results, - dir, - can, - (GNUNET_YES == ascending) ? "ascending" : "descending"); + *strstr (url, "&start=") = '\0'; - } - else - { - GNUNET_asprintf (&url, - "/history?auth=basic&account_number=%llu&delta=%lld&start=%llu&direction=%s&cancelled=%s&ordering=%s", - (unsigned long long) account_number, - (long long) num_results, - (unsigned long long) start_row, - dir, - can, - (GNUNET_YES == ascending) ? "ascending" : "descending"); - } + hh = put_history_job (ctx, + bank_base_url, + url, + auth, + hres_cb, + hres_cb_cls); - hh = GNUNET_new (struct TALER_BANK_HistoryHandle); - hh->hcb = hres_cb; - hh->hcb_cls = hres_cb_cls; - hh->bank_base_url = GNUNET_strdup (bank_base_url); - hh->request_url = TALER_BANK_path_to_url_ (bank_base_url, - url); GNUNET_free (url); - hh->authh = TALER_BANK_make_auth_header_ (auth); - eh = curl_easy_init (); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_HTTPHEADER, - hh->authh)); - GNUNET_assert (CURLE_OK == - curl_easy_setopt (eh, - CURLOPT_URL, - hh->request_url)); - hh->job = GNUNET_CURL_job_add (ctx, - eh, - GNUNET_NO, - &handle_history_finished, - hh); return hh; } /** - * Cancel a history request. This function cannot be used on a request - * handle if a response is already served for it. + * Cancel a history request. This function cannot be + * used on a request handle if a response is already + * served for it. * * @param hh the history request handle */ -- cgit v1.2.3