LCOV - code coverage report
Current view: top level - lib - merchant_api_get_statistics.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 163 265 61.5 %
Date: 2025-08-28 06:06:54 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2025 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU Lesser General Public License as published by the Free Software
       7             :   Foundation; either version 2.1, or (at your option) any later version.
       8             : 
       9             :   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
      10             :   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      11             :   A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU Lesser General Public License along with
      14             :   TALER; see the file COPYING.LGPL.  If not, see
      15             :   <http://www.gnu.org/licenses/>
      16             : */
      17             : /**
      18             :  * @file merchant_api_get_statistics.c
      19             :  * @brief Implementation of the GET /statistics-[counter,amount]/$SLUG request of the merchant's HTTP API
      20             :  * @author Martin Schanzenbach
      21             :  */
      22             : #include "platform.h"
      23             : #include <curl/curl.h>
      24             : #include <gnunet/gnunet_common.h>
      25             : #include <gnunet/gnunet_json_lib.h>
      26             : #include <jansson.h>
      27             : #include <microhttpd.h> /* just for HTTP status codes */
      28             : #include <gnunet/gnunet_util_lib.h>
      29             : #include <gnunet/gnunet_curl_lib.h>
      30             : #include "taler_merchant_service.h"
      31             : #include "merchant_api_curl_defaults.h"
      32             : #include <taler/taler_json_lib.h>
      33             : #include <taler/taler_signatures.h>
      34             : 
      35             : /**
      36             :  * Maximum number of statistics we return
      37             :  */
      38             : #define MAX_STATISTICS 1024
      39             : 
      40             : /**
      41             :  * Handle for a GET /statistics-amount/$SLUG operation.
      42             :  */
      43             : struct TALER_MERCHANT_StatisticsAmountGetHandle
      44             : {
      45             :   /**
      46             :    * The url for this request.
      47             :    */
      48             :   char *url;
      49             : 
      50             :   /**
      51             :    * Handle for the request.
      52             :    */
      53             :   struct GNUNET_CURL_Job *job;
      54             : 
      55             :   /**
      56             :    * Function to call with the result.
      57             :    */
      58             :   TALER_MERCHANT_StatisticsAmountGetCallback cb;
      59             : 
      60             :   /**
      61             :    * Closure for @a cb.
      62             :    */
      63             :   void *cb_cls;
      64             : 
      65             :   /**
      66             :    * Reference to the execution context.
      67             :    */
      68             :   struct GNUNET_CURL_Context *ctx;
      69             : 
      70             : };
      71             : 
      72             : /**
      73             :  * Handle for a GET /statistics-counter/$SLUG operation.
      74             :  */
      75             : struct TALER_MERCHANT_StatisticsCounterGetHandle
      76             : {
      77             :   /**
      78             :    * The url for this request.
      79             :    */
      80             :   char *url;
      81             : 
      82             :   /**
      83             :    * Handle for the request.
      84             :    */
      85             :   struct GNUNET_CURL_Job *job;
      86             : 
      87             :   /**
      88             :    * Function to call with the result.
      89             :    */
      90             :   TALER_MERCHANT_StatisticsCounterGetCallback cb;
      91             : 
      92             :   /**
      93             :    * Closure for @a cb.
      94             :    */
      95             :   void *cb_cls;
      96             : 
      97             :   /**
      98             :    * Reference to the execution context.
      99             :    */
     100             :   struct GNUNET_CURL_Context *ctx;
     101             : 
     102             : };
     103             : 
     104             : 
     105             : /**
     106             :  * Parse interval information from buckets and intervals.
     107             :  *
     108             :  * @param json overall JSON reply
     109             :  * @param jbuckets JSON array (or NULL!) with bucket data
     110             :  * @param buckets_description human-readable description for the buckets
     111             :  * @param jintervals JSON array (or NULL!) with bucket data
     112             :  * @param intervals_description human-readable description for the intervals
     113             :  * @param sgh operation handle
     114             :  * @return #GNUNET_OK on success
     115             :  */
     116             : static enum GNUNET_GenericReturnValue
     117           2 : parse_intervals_and_buckets_amt (
     118             :   const json_t *json,
     119             :   const json_t *jbuckets,
     120             :   const char *buckets_description,
     121             :   const json_t *jintervals,
     122             :   const char *intervals_description,
     123             :   struct TALER_MERCHANT_StatisticsAmountGetHandle *sgh
     124             :   )
     125             : {
     126           2 :   unsigned int resp_buckets_len = json_array_size (jbuckets);
     127           2 :   unsigned int resp_intervals_len = json_array_size (jintervals);
     128             : 
     129           2 :   if ( (json_array_size (jbuckets) != (size_t)  resp_buckets_len) ||
     130           2 :        (json_array_size (jintervals) != (size_t)  resp_intervals_len) ||
     131           2 :        (resp_intervals_len = resp_buckets_len > MAX_STATISTICS) )
     132             :   {
     133           0 :     GNUNET_break (0);
     134           0 :     return GNUNET_SYSERR;
     135             :   }
     136           2 :   {
     137           2 :     struct TALER_MERCHANT_StatisticAmountByBucket resp_buckets[
     138           2 :       GNUNET_NZL (resp_buckets_len)];
     139           2 :     struct TALER_MERCHANT_StatisticAmountByInterval resp_intervals[
     140           2 :       GNUNET_NZL (resp_intervals_len)];
     141             :     size_t index;
     142             :     json_t *value;
     143             :     enum GNUNET_GenericReturnValue ret;
     144             : 
     145           2 :     ret = GNUNET_OK;
     146           2 :     json_array_foreach (jintervals, index, value) {
     147           0 :       struct TALER_MERCHANT_StatisticAmountByInterval *jinterval
     148             :         = &resp_intervals[index];
     149             :       const json_t *amounts_arr;
     150             :       size_t amounts_len;
     151             : 
     152             :       struct GNUNET_JSON_Specification spec[] = {
     153           0 :         GNUNET_JSON_spec_timestamp ("start_time",
     154             :                                     &jinterval->start_time),
     155           0 :         GNUNET_JSON_spec_array_const ("cumulative_amount",
     156             :                                       &amounts_arr),
     157           0 :         GNUNET_JSON_spec_end ()
     158             :       };
     159             : 
     160           0 :       if (GNUNET_OK !=
     161           0 :           GNUNET_JSON_parse (value,
     162             :                              spec,
     163             :                              NULL, NULL))
     164             :       {
     165           0 :         GNUNET_break_op (0);
     166           0 :         ret = GNUNET_SYSERR;
     167           0 :         continue;
     168             :       }
     169           0 :       if (GNUNET_SYSERR == ret)
     170           0 :         break;
     171           0 :       amounts_len = json_array_size (amounts_arr);
     172           0 :       {
     173           0 :         struct TALER_Amount amt_arr[amounts_len];
     174             :         size_t aindex;
     175             :         json_t *avalue;
     176             : 
     177           0 :         jinterval->cumulative_amount_len = amounts_len;
     178           0 :         jinterval->cumulative_amounts = amt_arr;
     179           0 :         json_array_foreach (amounts_arr, aindex, avalue) {
     180           0 :           if (! json_is_string (avalue))
     181             :           {
     182           0 :             GNUNET_break_op (0);
     183           0 :             return GNUNET_SYSERR;
     184             :           }
     185           0 :           if (GNUNET_OK !=
     186           0 :               TALER_string_to_amount (json_string_value (avalue),
     187             :                                       &amt_arr[aindex]))
     188             :           {
     189           0 :             GNUNET_break_op (0);
     190           0 :             return GNUNET_SYSERR;
     191             :           }
     192             :         }
     193             :       }
     194             :     }
     195           2 :     ret = GNUNET_OK;
     196          14 :     json_array_foreach (jbuckets, index, value) {
     197          12 :       struct TALER_MERCHANT_StatisticAmountByBucket *jbucket
     198             :         = &resp_buckets[index];
     199             :       const json_t *amounts_arr;
     200             :       size_t amounts_len;
     201             :       struct GNUNET_JSON_Specification spec[] = {
     202          12 :         GNUNET_JSON_spec_timestamp ("start_time",
     203             :                                     &jbucket->start_time),
     204          12 :         GNUNET_JSON_spec_timestamp ("end_time",
     205             :                                     &jbucket->end_time),
     206          12 :         GNUNET_JSON_spec_string ("range",
     207             :                                  &jbucket->range),
     208          12 :         GNUNET_JSON_spec_array_const ("cumulative_amount",
     209             :                                       &amounts_arr),
     210          12 :         GNUNET_JSON_spec_end ()
     211             :       };
     212             : 
     213          12 :       if (GNUNET_OK !=
     214          12 :           GNUNET_JSON_parse (value,
     215             :                              spec,
     216             :                              NULL, NULL))
     217             :       {
     218           0 :         GNUNET_break_op (0);
     219           0 :         ret = GNUNET_SYSERR;
     220           0 :         continue;
     221             :       }
     222          12 :       if (GNUNET_SYSERR == ret)
     223           0 :         break;
     224          12 :       amounts_len = json_array_size (amounts_arr);
     225             :       if (0 > amounts_len)
     226             :       {
     227             :         GNUNET_break_op (0);
     228             :         ret = GNUNET_SYSERR;
     229             :         break;
     230             :       }
     231          12 :       {
     232          12 :         struct TALER_Amount amt_arr[amounts_len];
     233             :         size_t aindex;
     234             :         json_t *avalue;
     235          12 :         jbucket->cumulative_amount_len = amounts_len;
     236          12 :         jbucket->cumulative_amounts = amt_arr;
     237          24 :         json_array_foreach (amounts_arr, aindex, avalue) {
     238          12 :           if (! json_is_string (avalue))
     239             :           {
     240           0 :             GNUNET_break_op (0);
     241           0 :             return GNUNET_SYSERR;
     242             :           }
     243          12 :           if (GNUNET_OK !=
     244          12 :               TALER_string_to_amount (json_string_value (avalue),
     245             :                                       &amt_arr[aindex]))
     246             :           {
     247           0 :             GNUNET_break_op (0);
     248           0 :             return GNUNET_SYSERR;
     249             :           }
     250             :         }
     251             :       }
     252             :     }
     253           2 :     if (GNUNET_OK == ret)
     254             :     {
     255           2 :       struct TALER_MERCHANT_StatisticsAmountGetResponse gsr = {
     256             :         .hr.http_status = MHD_HTTP_OK,
     257             :         .hr.reply = json,
     258             :         .details.ok.buckets_length = resp_buckets_len,
     259             :         .details.ok.buckets = resp_buckets,
     260             :         .details.ok.buckets_description = buckets_description,
     261             :         .details.ok.intervals_length = resp_intervals_len,
     262             :         .details.ok.intervals = resp_intervals,
     263             :         .details.ok.intervals_description = intervals_description,
     264             :       };
     265           2 :       sgh->cb (sgh->cb_cls,
     266             :                &gsr);
     267           2 :       sgh->cb = NULL; /* just to be sure */
     268             :     }
     269           2 :     return ret;
     270             :   }
     271             : }
     272             : 
     273             : 
     274             : /**
     275             :  * Function called when we're done processing the
     276             :  * HTTP GET /statistics-amount/$SLUG request.
     277             :  *
     278             :  * @param cls the `struct TALER_MERCHANT_StatisticsAmountGetHandle`
     279             :  * @param response_code HTTP response code, 0 on error
     280             :  * @param response response body, NULL if not in JSON
     281             :  */
     282             : static void
     283           2 : handle_get_statistics_amount_finished (void *cls,
     284             :                                        long response_code,
     285             :                                        const void *response)
     286             : {
     287           2 :   struct TALER_MERCHANT_StatisticsAmountGetHandle *handle = cls;
     288           2 :   const json_t *json = response;
     289           2 :   struct TALER_MERCHANT_StatisticsAmountGetResponse res = {
     290           2 :     .hr.http_status = (unsigned int) response_code,
     291             :     .hr.reply = json
     292             :   };
     293             : 
     294           2 :   handle->job = NULL;
     295           2 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     296             :               "Got /statistics-amount/$SLUG response with status code %u\n",
     297             :               (unsigned int) response_code);
     298           2 :   switch (response_code)
     299             :   {
     300           2 :   case MHD_HTTP_OK:
     301             :     {
     302             :       const json_t *buckets;
     303             :       const json_t *intervals;
     304           2 :       const char *buckets_description = NULL;
     305           2 :       const char *intervals_description = NULL;
     306             :       struct GNUNET_JSON_Specification spec[] = {
     307           2 :         GNUNET_JSON_spec_array_const ("buckets",
     308             :                                       &buckets),
     309           2 :         GNUNET_JSON_spec_mark_optional (
     310             :           GNUNET_JSON_spec_string ("buckets_description",
     311             :                                    &buckets_description),
     312             :           NULL),
     313           2 :         GNUNET_JSON_spec_array_const ("intervals",
     314             :                                       &intervals),
     315           2 :         GNUNET_JSON_spec_mark_optional (
     316             :           GNUNET_JSON_spec_string ("intervals_description",
     317             :                                    &intervals_description),
     318             :           NULL),
     319           2 :         GNUNET_JSON_spec_end ()
     320             :       };
     321             : 
     322           2 :       if (GNUNET_OK !=
     323           2 :           GNUNET_JSON_parse (json,
     324             :                              spec,
     325             :                              NULL, NULL))
     326             :       {
     327           0 :         res.hr.http_status = 0;
     328           0 :         res.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     329           0 :         break;
     330             :       }
     331           2 :       if (GNUNET_OK ==
     332           2 :           parse_intervals_and_buckets_amt (json,
     333             :                                            buckets,
     334             :                                            buckets_description,
     335             :                                            intervals,
     336             :                                            intervals_description,
     337             :                                            handle))
     338             :       {
     339           2 :         TALER_MERCHANT_statistic_amount_get_cancel (handle);
     340           2 :         return;
     341             :       }
     342           0 :       res.hr.http_status = 0;
     343           0 :       res.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     344           0 :       break;
     345             :     }
     346           0 :   case MHD_HTTP_UNAUTHORIZED:
     347           0 :     res.hr.ec = TALER_JSON_get_error_code (json);
     348           0 :     res.hr.hint = TALER_JSON_get_error_hint (json);
     349             :     /* Nothing really to verify, merchant says we need to authenticate. */
     350           0 :     break;
     351           0 :   case MHD_HTTP_NOT_FOUND:
     352           0 :     res.hr.ec = TALER_JSON_get_error_code (json);
     353           0 :     res.hr.hint = TALER_JSON_get_error_hint (json);
     354           0 :     break;
     355           0 :   default:
     356             :     /* unexpected response code */
     357           0 :     res.hr.ec = TALER_JSON_get_error_code (json);
     358           0 :     res.hr.hint = TALER_JSON_get_error_hint (json);
     359           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     360             :                 "Unexpected response code %u/%d\n",
     361             :                 (unsigned int) response_code,
     362             :                 (int) res.hr.ec);
     363           0 :     break;
     364             :   }
     365             : }
     366             : 
     367             : 
     368             : /**
     369             :  * Parse interval information from @a ia.
     370             :  *
     371             :  * @param json overall JSON reply
     372             :  * @param jbuckets JSON array (or NULL!) with bucket data
     373             :  * @param buckets_description human-readable description for the buckets
     374             :  * @param jintervals JSON array (or NULL!) with bucket data
     375             :  * @param intervals_description human-readable description for the intervals
     376             :  * @param scgh operation handle
     377             :  * @return #GNUNET_OK on success
     378             :  */
     379             : static enum GNUNET_GenericReturnValue
     380           4 : parse_intervals_and_buckets (
     381             :   const json_t *json,
     382             :   const json_t *jbuckets,
     383             :   const char *buckets_description,
     384             :   const json_t *jintervals,
     385             :   const char *intervals_description,
     386             :   struct TALER_MERCHANT_StatisticsCounterGetHandle *scgh)
     387             : {
     388           4 :   unsigned int resp_buckets_len = json_array_size (jbuckets);
     389           4 :   unsigned int resp_intervals_len = json_array_size (jintervals);
     390             : 
     391           4 :   if ( (json_array_size (jbuckets) != (size_t)  resp_buckets_len) ||
     392           4 :        (json_array_size (jintervals) != (size_t)  resp_intervals_len) ||
     393           4 :        (resp_intervals_len = resp_buckets_len > MAX_STATISTICS) )
     394             :   {
     395           0 :     GNUNET_break (0);
     396           0 :     return GNUNET_SYSERR;
     397             :   }
     398           4 :   {
     399           4 :     struct TALER_MERCHANT_StatisticCounterByBucket resp_buckets[
     400           4 :       GNUNET_NZL (resp_buckets_len)];
     401           4 :     struct TALER_MERCHANT_StatisticCounterByInterval resp_intervals[
     402           4 :       GNUNET_NZL (resp_intervals_len)];
     403             :     size_t index;
     404             :     json_t *value;
     405             :     enum GNUNET_GenericReturnValue ret;
     406             : 
     407           4 :     ret = GNUNET_OK;
     408           8 :     json_array_foreach (jintervals, index, value) {
     409           4 :       struct TALER_MERCHANT_StatisticCounterByInterval *jinterval
     410             :         = &resp_intervals[index];
     411             :       struct GNUNET_JSON_Specification spec[] = {
     412           4 :         GNUNET_JSON_spec_timestamp ("start_time",
     413             :                                     &jinterval->start_time),
     414           4 :         GNUNET_JSON_spec_uint64 ("cumulative_counter",
     415             :                                  &jinterval->cumulative_counter),
     416           4 :         GNUNET_JSON_spec_end ()
     417             :       };
     418             : 
     419           4 :       if (GNUNET_OK !=
     420           4 :           GNUNET_JSON_parse (value,
     421             :                              spec,
     422             :                              NULL, NULL))
     423             :       {
     424           0 :         GNUNET_break_op (0);
     425           0 :         ret = GNUNET_SYSERR;
     426           0 :         continue;
     427             :       }
     428           4 :       if (GNUNET_SYSERR == ret)
     429           0 :         break;
     430             :     }
     431           4 :     ret = GNUNET_OK;
     432          28 :     json_array_foreach (jbuckets, index, value) {
     433          24 :       struct TALER_MERCHANT_StatisticCounterByBucket *jbucket = &resp_buckets[
     434             :         index];
     435             :       struct GNUNET_JSON_Specification spec[] = {
     436          24 :         GNUNET_JSON_spec_timestamp ("start_time",
     437             :                                     &jbucket->start_time),
     438          24 :         GNUNET_JSON_spec_timestamp ("end_time",
     439             :                                     &jbucket->end_time),
     440          24 :         GNUNET_JSON_spec_string ("range",
     441             :                                  &jbucket->range),
     442          24 :         GNUNET_JSON_spec_uint64 ("cumulative_counter",
     443             :                                  &jbucket->cumulative_counter),
     444          24 :         GNUNET_JSON_spec_end ()
     445             :       };
     446             : 
     447          24 :       if (GNUNET_OK !=
     448          24 :           GNUNET_JSON_parse (value,
     449             :                              spec,
     450             :                              NULL, NULL))
     451             :       {
     452           0 :         GNUNET_break_op (0);
     453           0 :         ret = GNUNET_SYSERR;
     454           0 :         continue;
     455             :       }
     456          24 :       if (GNUNET_SYSERR == ret)
     457           0 :         break;
     458             :     }
     459           4 :     if (GNUNET_OK == ret)
     460             :     {
     461           4 :       struct TALER_MERCHANT_StatisticsCounterGetResponse gsr = {
     462             :         .hr.http_status = MHD_HTTP_OK,
     463             :         .hr.reply = json,
     464             :         .details.ok.buckets_length = resp_buckets_len,
     465             :         .details.ok.buckets = resp_buckets,
     466             :         .details.ok.buckets_description = buckets_description,
     467             :         .details.ok.intervals_length = resp_intervals_len,
     468             :         .details.ok.intervals = resp_intervals,
     469             :         .details.ok.intervals_description = intervals_description,
     470             :       };
     471           4 :       scgh->cb (scgh->cb_cls,
     472             :                 &gsr);
     473           4 :       scgh->cb = NULL; /* just to be sure */
     474             :     }
     475           4 :     return ret;
     476             :   }
     477             : }
     478             : 
     479             : 
     480             : /**
     481             :  * Function called when we're done processing the
     482             :  * HTTP GET /statistics-counter/$SLUG request.
     483             :  *
     484             :  * @param cls the `struct TALER_MERCHANT_StatisticsCounterGetHandle`
     485             :  * @param response_code HTTP response code, 0 on error
     486             :  * @param response response body, NULL if not in JSON
     487             :  */
     488             : static void
     489           4 : handle_get_statistics_counter_finished (void *cls,
     490             :                                         long response_code,
     491             :                                         const void *response)
     492             : {
     493           4 :   struct TALER_MERCHANT_StatisticsCounterGetHandle *handle = cls;
     494           4 :   const json_t *json = response;
     495           4 :   struct TALER_MERCHANT_StatisticsCounterGetResponse res = {
     496           4 :     .hr.http_status = (unsigned int) response_code,
     497             :     .hr.reply = json
     498             :   };
     499             : 
     500           4 :   handle->job = NULL;
     501           4 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     502             :               "Got /statistics-counter/$SLUG response with status code %u\n",
     503             :               (unsigned int) response_code);
     504           4 :   switch (response_code)
     505             :   {
     506           4 :   case MHD_HTTP_OK:
     507             :     {
     508             :       const json_t *buckets;
     509             :       const json_t *intervals;
     510             :       const char *buckets_description;
     511             :       const char *intervals_description;
     512             :       struct GNUNET_JSON_Specification spec[] = {
     513           4 :         GNUNET_JSON_spec_array_const ("buckets",
     514             :                                       &buckets),
     515           4 :         GNUNET_JSON_spec_mark_optional (
     516             :           GNUNET_JSON_spec_string ("buckets_description",
     517             :                                    &buckets_description),
     518             :           NULL),
     519           4 :         GNUNET_JSON_spec_array_const ("intervals",
     520             :                                       &intervals),
     521           4 :         GNUNET_JSON_spec_mark_optional (
     522             :           GNUNET_JSON_spec_string ("intervals_description",
     523             :                                    &intervals_description),
     524             :           NULL),
     525           4 :         GNUNET_JSON_spec_end ()
     526             :       };
     527             : 
     528           4 :       if (GNUNET_OK !=
     529           4 :           GNUNET_JSON_parse (json,
     530             :                              spec,
     531             :                              NULL, NULL))
     532             :       {
     533           0 :         res.hr.http_status = 0;
     534           0 :         res.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     535           0 :         break;
     536             :       }
     537           4 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     538             :                   "%s\n", json_dumps (json, JSON_INDENT (1)));
     539           4 :       if (GNUNET_OK ==
     540           4 :           parse_intervals_and_buckets (json,
     541             :                                        buckets,
     542             :                                        buckets_description,
     543             :                                        intervals,
     544             :                                        intervals_description,
     545             :                                        handle))
     546             :       {
     547           4 :         TALER_MERCHANT_statistic_counter_get_cancel (handle);
     548           4 :         return;
     549             :       }
     550           0 :       res.hr.http_status = 0;
     551           0 :       res.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     552           0 :       break;
     553             :     }
     554           0 :   case MHD_HTTP_UNAUTHORIZED:
     555           0 :     res.hr.ec = TALER_JSON_get_error_code (json);
     556           0 :     res.hr.hint = TALER_JSON_get_error_hint (json);
     557             :     /* Nothing really to verify, merchant says we need to authenticate. */
     558           0 :     break;
     559           0 :   case MHD_HTTP_NOT_FOUND:
     560           0 :     res.hr.ec = TALER_JSON_get_error_code (json);
     561           0 :     res.hr.hint = TALER_JSON_get_error_hint (json);
     562           0 :     break;
     563           0 :   default:
     564             :     /* unexpected response code */
     565           0 :     res.hr.ec = TALER_JSON_get_error_code (json);
     566           0 :     res.hr.hint = TALER_JSON_get_error_hint (json);
     567           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     568             :                 "Unexpected response code %u/%d\n",
     569             :                 (unsigned int) response_code,
     570             :                 (int) res.hr.ec);
     571           0 :     break;
     572             :   }
     573             : }
     574             : 
     575             : 
     576             : struct TALER_MERCHANT_StatisticsCounterGetHandle *
     577           4 : TALER_MERCHANT_statistic_counter_get (
     578             :   struct GNUNET_CURL_Context *ctx,
     579             :   const char *backend_url,
     580             :   const char *slug,
     581             :   enum TALER_MERCHANT_StatisticsType stype,
     582             :   TALER_MERCHANT_StatisticsCounterGetCallback cb,
     583             :   void *cb_cls)
     584             : {
     585             :   struct TALER_MERCHANT_StatisticsCounterGetHandle *handle;
     586             :   CURL *eh;
     587             : 
     588           4 :   handle = GNUNET_new (struct TALER_MERCHANT_StatisticsCounterGetHandle);
     589           4 :   handle->ctx = ctx;
     590           4 :   handle->cb = cb;
     591           4 :   handle->cb_cls = cb_cls;
     592             :   {
     593           4 :     const char *filter = NULL;
     594             :     char *path;
     595             : 
     596           4 :     switch (stype)
     597             :     {
     598           0 :     case TALER_MERCHANT_STATISTICS_BY_BUCKET:
     599           0 :       filter = "bucket";
     600           0 :       break;
     601           0 :     case TALER_MERCHANT_STATISTICS_BY_INTERVAL:
     602           0 :       filter = "interval";
     603           0 :       break;
     604           4 :     case TALER_MERCHANT_STATISTICS_ALL:
     605           4 :       filter = NULL;
     606           4 :       break;
     607             :     }
     608           4 :     GNUNET_asprintf (&path,
     609             :                      "private/statistics-counter/%s",
     610             :                      slug);
     611           4 :     handle->url = TALER_url_join (backend_url,
     612             :                                   path,
     613             :                                   "by",
     614             :                                   filter,
     615             :                                   NULL);
     616           4 :     GNUNET_free (path);
     617             :   }
     618           4 :   if (NULL == handle->url)
     619             :   {
     620           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     621             :                 "Could not construct request URL.\n");
     622           0 :     GNUNET_free (handle);
     623           0 :     return NULL;
     624             :   }
     625           4 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     626             :               "Requesting URL '%s'\n",
     627             :               handle->url);
     628           4 :   eh = TALER_MERCHANT_curl_easy_get_ (handle->url);
     629           4 :   handle->job = GNUNET_CURL_job_add (ctx,
     630             :                                      eh,
     631             :                                      &handle_get_statistics_counter_finished,
     632             :                                      handle);
     633           4 :   return handle;
     634             : }
     635             : 
     636             : 
     637             : void
     638           4 : TALER_MERCHANT_statistic_counter_get_cancel (
     639             :   struct TALER_MERCHANT_StatisticsCounterGetHandle *handle)
     640             : {
     641           4 :   if (NULL != handle->job)
     642           0 :     GNUNET_CURL_job_cancel (handle->job);
     643           4 :   GNUNET_free (handle->url);
     644           4 :   GNUNET_free (handle);
     645           4 : }
     646             : 
     647             : 
     648             : struct TALER_MERCHANT_StatisticsAmountGetHandle *
     649           2 : TALER_MERCHANT_statistic_amount_get (
     650             :   struct GNUNET_CURL_Context *ctx,
     651             :   const char *backend_url,
     652             :   const char *slug,
     653             :   enum TALER_MERCHANT_StatisticsType stype,
     654             :   TALER_MERCHANT_StatisticsAmountGetCallback cb,
     655             :   void *cb_cls)
     656             : {
     657             :   struct TALER_MERCHANT_StatisticsAmountGetHandle *handle;
     658             :   CURL *eh;
     659             : 
     660           2 :   handle = GNUNET_new (struct TALER_MERCHANT_StatisticsAmountGetHandle);
     661           2 :   handle->ctx = ctx;
     662           2 :   handle->cb = cb;
     663           2 :   handle->cb_cls = cb_cls;
     664             :   {
     665           2 :     const char *filter = NULL;
     666             :     char *path;
     667             : 
     668           2 :     switch (stype)
     669             :     {
     670           0 :     case TALER_MERCHANT_STATISTICS_BY_BUCKET:
     671           0 :       filter = "bucket";
     672           0 :       break;
     673           0 :     case TALER_MERCHANT_STATISTICS_BY_INTERVAL:
     674           0 :       filter = "interval";
     675           0 :       break;
     676           2 :     case TALER_MERCHANT_STATISTICS_ALL:
     677           2 :       filter = NULL;
     678           2 :       break;
     679             :     }
     680           2 :     GNUNET_asprintf (&path,
     681             :                      "private/statistics-amount/%s",
     682             :                      slug);
     683           2 :     handle->url = TALER_url_join (backend_url,
     684             :                                   path,
     685             :                                   "by",
     686             :                                   filter,
     687             :                                   NULL);
     688           2 :     GNUNET_free (path);
     689             :   }
     690           2 :   if (NULL == handle->url)
     691             :   {
     692           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     693             :                 "Could not construct request URL.\n");
     694           0 :     GNUNET_free (handle);
     695           0 :     return NULL;
     696             :   }
     697           2 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     698             :               "Requesting URL '%s'\n",
     699             :               handle->url);
     700           2 :   eh = TALER_MERCHANT_curl_easy_get_ (handle->url);
     701           2 :   handle->job = GNUNET_CURL_job_add (ctx,
     702             :                                      eh,
     703             :                                      &handle_get_statistics_amount_finished,
     704             :                                      handle);
     705           2 :   return handle;
     706             : }
     707             : 
     708             : 
     709             : void
     710           2 : TALER_MERCHANT_statistic_amount_get_cancel (
     711             :   struct TALER_MERCHANT_StatisticsAmountGetHandle *handle)
     712             : {
     713           2 :   if (NULL != handle->job)
     714           0 :     GNUNET_CURL_job_cancel (handle->job);
     715           2 :   GNUNET_free (handle->url);
     716           2 :   GNUNET_free (handle);
     717           2 : }

Generated by: LCOV version 1.16