LCOV - code coverage report
Current view: top level - lib - merchant_api_get_statistics.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 156 265 58.9 %
Date: 2025-06-23 16:22:09 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 jintervals JSON array (or NULL!) with bucket data
     111             :  * @param scgh operation handle
     112             :  * @return #GNUNET_OK on success
     113             :  */
     114             : static enum GNUNET_GenericReturnValue
     115           2 : parse_intervals_and_buckets_amt (
     116             :   const json_t *json,
     117             :   const json_t *jbuckets,
     118             :   const char *buckets_description,
     119             :   const json_t *jintervals,
     120             :   const char *intervals_description,
     121             :   struct TALER_MERCHANT_StatisticsAmountGetHandle *sgh
     122             :   )
     123             : {
     124           2 :   unsigned int resp_buckets_len = json_array_size (jbuckets);
     125           2 :   unsigned int resp_intervals_len = json_array_size (jintervals);
     126             : 
     127           2 :   if ( (json_array_size (jbuckets) != (size_t)  resp_buckets_len) ||
     128           2 :        (json_array_size (jintervals) != (size_t)  resp_intervals_len) ||
     129           2 :        (resp_intervals_len = resp_buckets_len > MAX_STATISTICS) )
     130             :   {
     131           0 :     GNUNET_break (0);
     132           0 :     return GNUNET_SYSERR;
     133             :   }
     134           2 :   {
     135           2 :     struct TALER_MERCHANT_StatisticAmountByBucket resp_buckets[
     136           2 :       GNUNET_NZL (resp_buckets_len)];
     137           2 :     struct TALER_MERCHANT_StatisticAmountByInterval resp_intervals[
     138           2 :       GNUNET_NZL (resp_intervals_len)];
     139             :     size_t index;
     140             :     json_t *value;
     141             :     enum GNUNET_GenericReturnValue ret;
     142             : 
     143           2 :     ret = GNUNET_OK;
     144           2 :     json_array_foreach (jintervals, index, value) {
     145           0 :       struct TALER_MERCHANT_StatisticAmountByInterval *jinterval
     146             :         = &resp_intervals[index];
     147             :       const json_t *amounts_arr;
     148             :       size_t amounts_len;
     149             : 
     150             :       struct GNUNET_JSON_Specification spec[] = {
     151           0 :         GNUNET_JSON_spec_timestamp ("start_time",
     152             :                                     &jinterval->start_time),
     153           0 :         GNUNET_JSON_spec_array_const ("cumulative_amount",
     154             :                                       &amounts_arr),
     155           0 :         GNUNET_JSON_spec_end ()
     156             :       };
     157             : 
     158           0 :       if (GNUNET_OK !=
     159           0 :           GNUNET_JSON_parse (value,
     160             :                              spec,
     161             :                              NULL, NULL))
     162             :       {
     163           0 :         GNUNET_break_op (0);
     164           0 :         ret = GNUNET_SYSERR;
     165           0 :         continue;
     166             :       }
     167           0 :       if (GNUNET_SYSERR == ret)
     168           0 :         break;
     169           0 :       amounts_len = json_array_size (amounts_arr);
     170             :       if (0 > amounts_len)
     171             :       {
     172             :         GNUNET_break_op (0);
     173             :         ret = GNUNET_SYSERR;
     174             :         break;
     175             :       }
     176           0 :       {
     177           0 :         struct TALER_Amount amt_arr[amounts_len];
     178             :         size_t aindex;
     179             :         json_t *avalue;
     180           0 :         jinterval->cumulative_amount_len = amounts_len;
     181           0 :         jinterval->cumulative_amounts = amt_arr;
     182           0 :         json_array_foreach (amounts_arr, aindex, avalue) {
     183           0 :           if (! json_is_string (avalue))
     184             :           {
     185           0 :             GNUNET_break_op (0);
     186           0 :             return GNUNET_SYSERR;
     187             :           }
     188           0 :           if (GNUNET_OK !=
     189           0 :               TALER_string_to_amount (json_string_value (avalue),
     190             :                                       &amt_arr[aindex]))
     191             :           {
     192           0 :             GNUNET_break_op (0);
     193           0 :             return GNUNET_SYSERR;
     194             :           }
     195             :         }
     196             :       }
     197             :     }
     198           2 :     ret = GNUNET_OK;
     199          14 :     json_array_foreach (jbuckets, index, value) {
     200          12 :       struct TALER_MERCHANT_StatisticAmountByBucket *jbucket
     201             :         = &resp_buckets[index];
     202             :       const json_t *amounts_arr;
     203             :       size_t amounts_len;
     204             :       struct GNUNET_JSON_Specification spec[] = {
     205          12 :         GNUNET_JSON_spec_timestamp ("start_time",
     206             :                                     &jbucket->start_time),
     207          12 :         GNUNET_JSON_spec_timestamp ("end_time",
     208             :                                     &jbucket->end_time),
     209          12 :         GNUNET_JSON_spec_string ("range",
     210             :                                  &jbucket->range),
     211          12 :         GNUNET_JSON_spec_array_const ("cumulative_amount",
     212             :                                       &amounts_arr),
     213          12 :         GNUNET_JSON_spec_end ()
     214             :       };
     215             : 
     216          12 :       if (GNUNET_OK !=
     217          12 :           GNUNET_JSON_parse (value,
     218             :                              spec,
     219             :                              NULL, NULL))
     220             :       {
     221           0 :         GNUNET_break_op (0);
     222           0 :         ret = GNUNET_SYSERR;
     223           0 :         continue;
     224             :       }
     225          12 :       if (GNUNET_SYSERR == ret)
     226           0 :         break;
     227          12 :       amounts_len = json_array_size (amounts_arr);
     228             :       if (0 > amounts_len)
     229             :       {
     230             :         GNUNET_break_op (0);
     231             :         ret = GNUNET_SYSERR;
     232             :         break;
     233             :       }
     234          12 :       {
     235          12 :         struct TALER_Amount amt_arr[amounts_len];
     236             :         size_t aindex;
     237             :         json_t *avalue;
     238          12 :         jbucket->cumulative_amount_len = amounts_len;
     239          12 :         jbucket->cumulative_amounts = amt_arr;
     240          24 :         json_array_foreach (amounts_arr, aindex, avalue) {
     241          12 :           if (! json_is_string (avalue))
     242             :           {
     243           0 :             GNUNET_break_op (0);
     244           0 :             return GNUNET_SYSERR;
     245             :           }
     246          12 :           if (GNUNET_OK !=
     247          12 :               TALER_string_to_amount (json_string_value (avalue),
     248             :                                       &amt_arr[aindex]))
     249             :           {
     250           0 :             GNUNET_break_op (0);
     251           0 :             return GNUNET_SYSERR;
     252             :           }
     253             :         }
     254             :       }
     255             :     }
     256           2 :     if (GNUNET_OK == ret)
     257             :     {
     258           2 :       struct TALER_MERCHANT_StatisticsAmountGetResponse gsr = {
     259             :         .hr.http_status = MHD_HTTP_OK,
     260             :         .hr.reply = json,
     261             :         .details.ok.buckets_length = resp_buckets_len,
     262             :         .details.ok.buckets = resp_buckets,
     263             :         .details.ok.buckets_description = buckets_description,
     264             :         .details.ok.intervals_length = resp_intervals_len,
     265             :         .details.ok.intervals = resp_intervals,
     266             :         .details.ok.intervals_description = intervals_description,
     267             :       };
     268           2 :       sgh->cb (sgh->cb_cls,
     269             :                &gsr);
     270           2 :       sgh->cb = NULL; /* just to be sure */
     271             :     }
     272           2 :     return ret;
     273             :   }
     274             : }
     275             : 
     276             : 
     277             : /**
     278             :  * Function called when we're done processing the
     279             :  * HTTP GET /statistics-amount/$SLUG request.
     280             :  *
     281             :  * @param cls the `struct TALER_MERCHANT_StatisticsAmountGetHandle`
     282             :  * @param response_code HTTP response code, 0 on error
     283             :  * @param response response body, NULL if not in JSON
     284             :  */
     285             : static void
     286           2 : handle_get_statistics_amount_finished (void *cls,
     287             :                                        long response_code,
     288             :                                        const void *response)
     289             : {
     290           2 :   struct TALER_MERCHANT_StatisticsAmountGetHandle *handle = cls;
     291           2 :   const json_t *json = response;
     292           2 :   struct TALER_MERCHANT_StatisticsAmountGetResponse res = {
     293           2 :     .hr.http_status = (unsigned int) response_code,
     294             :     .hr.reply = json
     295             :   };
     296             : 
     297           2 :   handle->job = NULL;
     298           2 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     299             :               "Got /statistics-amount/$SLUG response with status code %u\n",
     300             :               (unsigned int) response_code);
     301           2 :   switch (response_code)
     302             :   {
     303           2 :   case MHD_HTTP_OK:
     304             :     {
     305             :       const json_t *buckets;
     306             :       const json_t *intervals;
     307           2 :       const char *buckets_description = NULL;
     308           2 :       const char *intervals_description = NULL;
     309             :       struct GNUNET_JSON_Specification spec[] = {
     310           2 :         GNUNET_JSON_spec_array_const ("buckets",
     311             :                                       &buckets),
     312           2 :         GNUNET_JSON_spec_mark_optional (
     313             :           GNUNET_JSON_spec_string ("buckets_description",
     314             :                                    &buckets_description),
     315             :           NULL),
     316           2 :         GNUNET_JSON_spec_array_const ("intervals",
     317             :                                       &intervals),
     318           2 :         GNUNET_JSON_spec_mark_optional (
     319             :           GNUNET_JSON_spec_string ("intervals_description",
     320             :                                    &intervals_description),
     321             :           NULL),
     322           2 :         GNUNET_JSON_spec_end ()
     323             :       };
     324             : 
     325           2 :       if (GNUNET_OK !=
     326           2 :           GNUNET_JSON_parse (json,
     327             :                              spec,
     328             :                              NULL, NULL))
     329             :       {
     330           0 :         res.hr.http_status = 0;
     331           0 :         res.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     332           0 :         break;
     333             :       }
     334           2 :       if (GNUNET_OK ==
     335           2 :           parse_intervals_and_buckets_amt (json,
     336             :                                            buckets,
     337             :                                            buckets_description,
     338             :                                            intervals,
     339             :                                            intervals_description,
     340             :                                            handle))
     341             :       {
     342           2 :         TALER_MERCHANT_statistic_amount_get_cancel (handle);
     343           2 :         return;
     344             :       }
     345           0 :       res.hr.http_status = 0;
     346           0 :       res.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     347           0 :       break;
     348             :     }
     349           0 :   case MHD_HTTP_UNAUTHORIZED:
     350           0 :     res.hr.ec = TALER_JSON_get_error_code (json);
     351           0 :     res.hr.hint = TALER_JSON_get_error_hint (json);
     352             :     /* Nothing really to verify, merchant says we need to authenticate. */
     353           0 :     break;
     354           0 :   case MHD_HTTP_NOT_FOUND:
     355           0 :     res.hr.ec = TALER_JSON_get_error_code (json);
     356           0 :     res.hr.hint = TALER_JSON_get_error_hint (json);
     357           0 :     break;
     358           0 :   default:
     359             :     /* unexpected response code */
     360           0 :     res.hr.ec = TALER_JSON_get_error_code (json);
     361           0 :     res.hr.hint = TALER_JSON_get_error_hint (json);
     362           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     363             :                 "Unexpected response code %u/%d\n",
     364             :                 (unsigned int) response_code,
     365             :                 (int) res.hr.ec);
     366           0 :     break;
     367             :   }
     368             : }
     369             : 
     370             : 
     371             : /**
     372             :  * Parse interval information from @a ia.
     373             :  *
     374             :  * @param json overall JSON reply
     375             :  * @param jbuckets JSON array (or NULL!) with bucket data
     376             :  * @param jintervals JSON array (or NULL!) with bucket data
     377             :  * @param scgh operation handle
     378             :  * @return #GNUNET_OK on success
     379             :  */
     380             : static enum GNUNET_GenericReturnValue
     381           4 : parse_intervals_and_buckets (
     382             :   const json_t *json,
     383             :   const json_t *jbuckets,
     384             :   const char *buckets_description,
     385             :   const json_t *jintervals,
     386             :   const char *intervals_description,
     387             :   struct TALER_MERCHANT_StatisticsCounterGetHandle *scgh)
     388             : {
     389           4 :   unsigned int resp_buckets_len = json_array_size (jbuckets);
     390           4 :   unsigned int resp_intervals_len = json_array_size (jintervals);
     391             : 
     392           4 :   if ( (json_array_size (jbuckets) != (size_t)  resp_buckets_len) ||
     393           4 :        (json_array_size (jintervals) != (size_t)  resp_intervals_len) ||
     394           4 :        (resp_intervals_len = resp_buckets_len > MAX_STATISTICS) )
     395             :   {
     396           0 :     GNUNET_break (0);
     397           0 :     return GNUNET_SYSERR;
     398             :   }
     399           4 :   {
     400           4 :     struct TALER_MERCHANT_StatisticCounterByBucket resp_buckets[
     401           4 :       GNUNET_NZL (resp_buckets_len)];
     402           4 :     struct TALER_MERCHANT_StatisticCounterByInterval resp_intervals[
     403           4 :       GNUNET_NZL (resp_intervals_len)];
     404             :     size_t index;
     405             :     json_t *value;
     406             :     enum GNUNET_GenericReturnValue ret;
     407             : 
     408           4 :     ret = GNUNET_OK;
     409           4 :     json_array_foreach (jintervals, index, value) {
     410           0 :       struct TALER_MERCHANT_StatisticCounterByInterval *jinterval
     411             :         = &resp_intervals[index];
     412             :       struct GNUNET_JSON_Specification spec[] = {
     413           0 :         GNUNET_JSON_spec_timestamp ("start_time",
     414             :                                     &jinterval->start_time),
     415           0 :         GNUNET_JSON_spec_uint64 ("cumulative_counter",
     416             :                                  &jinterval->cumulative_counter),
     417           0 :         GNUNET_JSON_spec_end ()
     418             :       };
     419             : 
     420           0 :       if (GNUNET_OK !=
     421           0 :           GNUNET_JSON_parse (value,
     422             :                              spec,
     423             :                              NULL, NULL))
     424             :       {
     425           0 :         GNUNET_break_op (0);
     426           0 :         ret = GNUNET_SYSERR;
     427           0 :         continue;
     428             :       }
     429           0 :       if (GNUNET_SYSERR == ret)
     430           0 :         break;
     431             :     }
     432           4 :     ret = GNUNET_OK;
     433          28 :     json_array_foreach (jbuckets, index, value) {
     434          24 :       struct TALER_MERCHANT_StatisticCounterByBucket *jbucket = &resp_buckets[
     435             :         index];
     436             :       struct GNUNET_JSON_Specification spec[] = {
     437          24 :         GNUNET_JSON_spec_timestamp ("start_time",
     438             :                                     &jbucket->start_time),
     439          24 :         GNUNET_JSON_spec_timestamp ("end_time",
     440             :                                     &jbucket->end_time),
     441          24 :         GNUNET_JSON_spec_string ("range",
     442             :                                  &jbucket->range),
     443          24 :         GNUNET_JSON_spec_uint64 ("cumulative_counter",
     444             :                                  &jbucket->cumulative_counter),
     445          24 :         GNUNET_JSON_spec_end ()
     446             :       };
     447             : 
     448          24 :       if (GNUNET_OK !=
     449          24 :           GNUNET_JSON_parse (value,
     450             :                              spec,
     451             :                              NULL, NULL))
     452             :       {
     453           0 :         GNUNET_break_op (0);
     454           0 :         ret = GNUNET_SYSERR;
     455           0 :         continue;
     456             :       }
     457          24 :       if (GNUNET_SYSERR == ret)
     458           0 :         break;
     459             :     }
     460           4 :     if (GNUNET_OK == ret)
     461             :     {
     462           4 :       struct TALER_MERCHANT_StatisticsCounterGetResponse gsr = {
     463             :         .hr.http_status = MHD_HTTP_OK,
     464             :         .hr.reply = json,
     465             :         .details.ok.buckets_length = resp_buckets_len,
     466             :         .details.ok.buckets = resp_buckets,
     467             :         .details.ok.buckets_description = buckets_description,
     468             :         .details.ok.intervals_length = resp_intervals_len,
     469             :         .details.ok.intervals = resp_intervals,
     470             :         .details.ok.intervals_description = intervals_description,
     471             :       };
     472           4 :       scgh->cb (scgh->cb_cls,
     473             :                 &gsr);
     474           4 :       scgh->cb = NULL; /* just to be sure */
     475             :     }
     476           4 :     return ret;
     477             :   }
     478             : }
     479             : 
     480             : 
     481             : /**
     482             :  * Function called when we're done processing the
     483             :  * HTTP GET /statistics-counter/$SLUG request.
     484             :  *
     485             :  * @param cls the `struct TALER_MERCHANT_StatisticsCounterGetHandle`
     486             :  * @param response_code HTTP response code, 0 on error
     487             :  * @param response response body, NULL if not in JSON
     488             :  */
     489             : static void
     490           4 : handle_get_statistics_counter_finished (void *cls,
     491             :                                         long response_code,
     492             :                                         const void *response)
     493             : {
     494           4 :   struct TALER_MERCHANT_StatisticsCounterGetHandle *handle = cls;
     495           4 :   const json_t *json = response;
     496           4 :   struct TALER_MERCHANT_StatisticsCounterGetResponse res = {
     497           4 :     .hr.http_status = (unsigned int) response_code,
     498             :     .hr.reply = json
     499             :   };
     500             : 
     501           4 :   handle->job = NULL;
     502           4 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     503             :               "Got /statistics-counter/$SLUG response with status code %u\n",
     504             :               (unsigned int) response_code);
     505           4 :   switch (response_code)
     506             :   {
     507           4 :   case MHD_HTTP_OK:
     508             :     {
     509             :       const json_t *buckets;
     510             :       const json_t *intervals;
     511             :       const char *buckets_description;
     512             :       const char *intervals_description;
     513             :       struct GNUNET_JSON_Specification spec[] = {
     514           4 :         GNUNET_JSON_spec_array_const ("buckets",
     515             :                                       &buckets),
     516           4 :         GNUNET_JSON_spec_mark_optional (
     517             :           GNUNET_JSON_spec_string ("buckets_description",
     518             :                                    &buckets_description),
     519             :           NULL),
     520           4 :         GNUNET_JSON_spec_array_const ("intervals",
     521             :                                       &intervals),
     522           4 :         GNUNET_JSON_spec_mark_optional (
     523             :           GNUNET_JSON_spec_string ("intervals_description",
     524             :                                    &intervals_description),
     525             :           NULL),
     526           4 :         GNUNET_JSON_spec_end ()
     527             :       };
     528             : 
     529           4 :       if (GNUNET_OK !=
     530           4 :           GNUNET_JSON_parse (json,
     531             :                              spec,
     532             :                              NULL, NULL))
     533             :       {
     534           0 :         res.hr.http_status = 0;
     535           0 :         res.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     536           0 :         break;
     537             :       }
     538           4 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     539             :                   "%s\n", json_dumps (json, JSON_INDENT (1)));
     540           4 :       if (GNUNET_OK ==
     541           4 :           parse_intervals_and_buckets (json,
     542             :                                        buckets,
     543             :                                        buckets_description,
     544             :                                        intervals,
     545             :                                        intervals_description,
     546             :                                        handle))
     547             :       {
     548           4 :         TALER_MERCHANT_statistic_counter_get_cancel (handle);
     549           4 :         return;
     550             :       }
     551           0 :       res.hr.http_status = 0;
     552           0 :       res.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     553           0 :       break;
     554             :     }
     555           0 :   case MHD_HTTP_UNAUTHORIZED:
     556           0 :     res.hr.ec = TALER_JSON_get_error_code (json);
     557           0 :     res.hr.hint = TALER_JSON_get_error_hint (json);
     558             :     /* Nothing really to verify, merchant says we need to authenticate. */
     559           0 :     break;
     560           0 :   case MHD_HTTP_NOT_FOUND:
     561           0 :     res.hr.ec = TALER_JSON_get_error_code (json);
     562           0 :     res.hr.hint = TALER_JSON_get_error_hint (json);
     563           0 :     break;
     564           0 :   default:
     565             :     /* unexpected response code */
     566           0 :     res.hr.ec = TALER_JSON_get_error_code (json);
     567           0 :     res.hr.hint = TALER_JSON_get_error_hint (json);
     568           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     569             :                 "Unexpected response code %u/%d\n",
     570             :                 (unsigned int) response_code,
     571             :                 (int) res.hr.ec);
     572           0 :     break;
     573             :   }
     574             : }
     575             : 
     576             : 
     577             : struct TALER_MERCHANT_StatisticsCounterGetHandle *
     578           4 : TALER_MERCHANT_statistic_counter_get (
     579             :   struct GNUNET_CURL_Context *ctx,
     580             :   const char *backend_url,
     581             :   const char *slug,
     582             :   enum TALER_MERCHANT_StatisticsType stype,
     583             :   TALER_MERCHANT_StatisticsCounterGetCallback cb,
     584             :   void *cb_cls)
     585             : {
     586             :   struct TALER_MERCHANT_StatisticsCounterGetHandle *handle;
     587             :   CURL *eh;
     588             : 
     589           4 :   handle = GNUNET_new (struct TALER_MERCHANT_StatisticsCounterGetHandle);
     590           4 :   handle->ctx = ctx;
     591           4 :   handle->cb = cb;
     592           4 :   handle->cb_cls = cb_cls;
     593             :   {
     594           4 :     const char *filter = NULL;
     595             :     char *path;
     596             : 
     597           4 :     switch (stype)
     598             :     {
     599           0 :     case TALER_MERCHANT_STATISTICS_BY_BUCKET:
     600           0 :       filter = "bucket";
     601           0 :       break;
     602           0 :     case TALER_MERCHANT_STATISTICS_BY_INTERVAL:
     603           0 :       filter = "interval";
     604           0 :       break;
     605           4 :     case TALER_MERCHANT_STATISTICS_ALL:
     606           4 :       filter = NULL;
     607           4 :       break;
     608             :     }
     609           4 :     GNUNET_asprintf (&path,
     610             :                      "private/statistics-counter/%s",
     611             :                      slug);
     612           4 :     handle->url = TALER_url_join (backend_url,
     613             :                                   path,
     614             :                                   "by",
     615             :                                   filter,
     616             :                                   NULL);
     617           4 :     GNUNET_free (path);
     618             :   }
     619           4 :   if (NULL == handle->url)
     620             :   {
     621           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     622             :                 "Could not construct request URL.\n");
     623           0 :     GNUNET_free (handle);
     624           0 :     return NULL;
     625             :   }
     626           4 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     627             :               "Requesting URL '%s'\n",
     628             :               handle->url);
     629           4 :   eh = TALER_MERCHANT_curl_easy_get_ (handle->url);
     630           4 :   handle->job = GNUNET_CURL_job_add (ctx,
     631             :                                      eh,
     632             :                                      &handle_get_statistics_counter_finished,
     633             :                                      handle);
     634           4 :   return handle;
     635             : }
     636             : 
     637             : 
     638             : void
     639           4 : TALER_MERCHANT_statistic_counter_get_cancel (
     640             :   struct TALER_MERCHANT_StatisticsCounterGetHandle *handle)
     641             : {
     642           4 :   if (NULL != handle->job)
     643           0 :     GNUNET_CURL_job_cancel (handle->job);
     644           4 :   GNUNET_free (handle->url);
     645           4 :   GNUNET_free (handle);
     646           4 : }
     647             : 
     648             : 
     649             : struct TALER_MERCHANT_StatisticsAmountGetHandle *
     650           2 : TALER_MERCHANT_statistic_amount_get (
     651             :   struct GNUNET_CURL_Context *ctx,
     652             :   const char *backend_url,
     653             :   const char *slug,
     654             :   enum TALER_MERCHANT_StatisticsType stype,
     655             :   TALER_MERCHANT_StatisticsAmountGetCallback cb,
     656             :   void *cb_cls)
     657             : {
     658             :   struct TALER_MERCHANT_StatisticsAmountGetHandle *handle;
     659             :   CURL *eh;
     660             : 
     661           2 :   handle = GNUNET_new (struct TALER_MERCHANT_StatisticsAmountGetHandle);
     662           2 :   handle->ctx = ctx;
     663           2 :   handle->cb = cb;
     664           2 :   handle->cb_cls = cb_cls;
     665             :   {
     666           2 :     const char *filter = NULL;
     667             :     char *path;
     668             : 
     669           2 :     switch (stype)
     670             :     {
     671           0 :     case TALER_MERCHANT_STATISTICS_BY_BUCKET:
     672           0 :       filter = "bucket";
     673           0 :       break;
     674           0 :     case TALER_MERCHANT_STATISTICS_BY_INTERVAL:
     675           0 :       filter = "interval";
     676           0 :       break;
     677           2 :     case TALER_MERCHANT_STATISTICS_ALL:
     678           2 :       filter = NULL;
     679           2 :       break;
     680             :     }
     681           2 :     GNUNET_asprintf (&path,
     682             :                      "private/statistics-amount/%s",
     683             :                      slug);
     684           2 :     handle->url = TALER_url_join (backend_url,
     685             :                                   path,
     686             :                                   "by",
     687             :                                   filter,
     688             :                                   NULL);
     689           2 :     GNUNET_free (path);
     690             :   }
     691           2 :   if (NULL == handle->url)
     692             :   {
     693           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     694             :                 "Could not construct request URL.\n");
     695           0 :     GNUNET_free (handle);
     696           0 :     return NULL;
     697             :   }
     698           2 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     699             :               "Requesting URL '%s'\n",
     700             :               handle->url);
     701           2 :   eh = TALER_MERCHANT_curl_easy_get_ (handle->url);
     702           2 :   handle->job = GNUNET_CURL_job_add (ctx,
     703             :                                      eh,
     704             :                                      &handle_get_statistics_amount_finished,
     705             :                                      handle);
     706           2 :   return handle;
     707             : }
     708             : 
     709             : 
     710             : void
     711           2 : TALER_MERCHANT_statistic_amount_get_cancel (
     712             :   struct TALER_MERCHANT_StatisticsAmountGetHandle *handle)
     713             : {
     714           2 :   if (NULL != handle->job)
     715           0 :     GNUNET_CURL_job_cancel (handle->job);
     716           2 :   GNUNET_free (handle->url);
     717           2 :   GNUNET_free (handle);
     718           2 : }

Generated by: LCOV version 1.16