merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

merchant_api_get-management-instances.c (8380B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2014-2026 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-management-instances-new.c
     19  * @brief Implementation of the GET /management/instances request
     20  * @author Christian Grothoff
     21  */
     22 #include "taler/platform.h"
     23 #include <curl/curl.h>
     24 #include <jansson.h>
     25 #include <microhttpd.h> /* just for HTTP status codes */
     26 #include <gnunet/gnunet_util_lib.h>
     27 #include <gnunet/gnunet_curl_lib.h>
     28 #include <taler/taler-merchant/get-management-instances.h>
     29 #include "merchant_api_curl_defaults.h"
     30 #include <taler/taler_json_lib.h>
     31 
     32 /**
     33  * Maximum number of instances permitted.
     34  */
     35 #define MAX_INSTANCES 1024
     36 
     37 
     38 /**
     39  * Handle for a GET /management/instances operation.
     40  */
     41 struct TALER_MERCHANT_GetManagementInstancesHandle
     42 {
     43   /**
     44    * Base URL of the merchant backend.
     45    */
     46   char *base_url;
     47 
     48   /**
     49    * The full URL for this request.
     50    */
     51   char *url;
     52 
     53   /**
     54    * Handle for the request.
     55    */
     56   struct GNUNET_CURL_Job *job;
     57 
     58   /**
     59    * Function to call with the result.
     60    */
     61   TALER_MERCHANT_GetManagementInstancesCallback cb;
     62 
     63   /**
     64    * Closure for @a cb.
     65    */
     66   TALER_MERCHANT_GET_MANAGEMENT_INSTANCES_RESULT_CLOSURE *cb_cls;
     67 
     68   /**
     69    * Reference to the execution context.
     70    */
     71   struct GNUNET_CURL_Context *ctx;
     72 };
     73 
     74 
     75 /**
     76  * Parse instance information from @a ia.
     77  *
     78  * @param ia JSON array (or NULL!) with instance data
     79  * @param[in] igr partially filled response
     80  * @param gimh operation handle
     81  * @return #GNUNET_OK on success
     82  */
     83 static enum GNUNET_GenericReturnValue
     84 parse_instances (const json_t *ia,
     85                  struct TALER_MERCHANT_GetManagementInstancesResponse *igr,
     86                  struct TALER_MERCHANT_GetManagementInstancesHandle *gimh)
     87 {
     88   unsigned int iis_len = (unsigned int) json_array_size (ia);
     89 
     90   if ( (json_array_size (ia) != (size_t) iis_len) ||
     91        (iis_len > MAX_INSTANCES) )
     92   {
     93     GNUNET_break (0);
     94     return GNUNET_SYSERR;
     95   }
     96   {
     97     struct TALER_MERCHANT_GetManagementInstancesInstanceInfo iis[
     98       GNUNET_NZL (iis_len)];
     99     size_t index;
    100     json_t *value;
    101 
    102     memset (iis,
    103             0,
    104             sizeof (iis));
    105     json_array_foreach (ia, index, value) {
    106       struct TALER_MERCHANT_GetManagementInstancesInstanceInfo *ii =
    107         &iis[index];
    108       struct GNUNET_JSON_Specification spec[] = {
    109         GNUNET_JSON_spec_string ("name",
    110                                  &ii->name),
    111         GNUNET_JSON_spec_string ("id",
    112                                  &ii->id),
    113         GNUNET_JSON_spec_fixed_auto ("merchant_pub",
    114                                      &ii->merchant_pub),
    115         GNUNET_JSON_spec_array_const ("payment_targets",
    116                                       &ii->payment_targets),
    117         GNUNET_JSON_spec_mark_optional (
    118           GNUNET_JSON_spec_string ("website",
    119                                    &ii->website),
    120           NULL),
    121         GNUNET_JSON_spec_mark_optional (
    122           GNUNET_JSON_spec_string ("logo",
    123                                    &ii->logo),
    124           NULL),
    125         GNUNET_JSON_spec_bool ("deleted",
    126                                &ii->deleted),
    127         GNUNET_JSON_spec_end ()
    128       };
    129 
    130       if (GNUNET_OK !=
    131           GNUNET_JSON_parse (value,
    132                              spec,
    133                              NULL, NULL))
    134       {
    135         GNUNET_break_op (0);
    136         return GNUNET_SYSERR;
    137       }
    138       for (size_t i = 0; i<json_array_size (ii->payment_targets); i++)
    139       {
    140         if  (! json_is_string (json_array_get (ii->payment_targets,
    141                                                i)))
    142         {
    143           GNUNET_break_op (0);
    144           return GNUNET_SYSERR;
    145         }
    146       }
    147     }
    148     igr->details.ok.iis_length = iis_len;
    149     igr->details.ok.iis = iis;
    150     gimh->cb (gimh->cb_cls,
    151               igr);
    152     gimh->cb = NULL;
    153   }
    154   return GNUNET_OK;
    155 }
    156 
    157 
    158 /**
    159  * Function called when we're done processing the
    160  * HTTP GET /management/instances request.
    161  *
    162  * @param cls the `struct TALER_MERCHANT_GetManagementInstancesHandle`
    163  * @param response_code HTTP response code, 0 on error
    164  * @param response response body, NULL if not in JSON
    165  */
    166 static void
    167 handle_get_instances_finished (void *cls,
    168                                long response_code,
    169                                const void *response)
    170 {
    171   struct TALER_MERCHANT_GetManagementInstancesHandle *gimh = cls;
    172   const json_t *json = response;
    173   struct TALER_MERCHANT_GetManagementInstancesResponse igr = {
    174     .hr.http_status = (unsigned int) response_code,
    175     .hr.reply = json
    176   };
    177 
    178   gimh->job = NULL;
    179   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    180               "Got /management/instances response with status code %u\n",
    181               (unsigned int) response_code);
    182   switch (response_code)
    183   {
    184   case MHD_HTTP_OK:
    185     {
    186       const json_t *instances;
    187       struct GNUNET_JSON_Specification spec[] = {
    188         GNUNET_JSON_spec_array_const ("instances",
    189                                       &instances),
    190         GNUNET_JSON_spec_end ()
    191       };
    192 
    193       if (GNUNET_OK !=
    194           GNUNET_JSON_parse (json,
    195                              spec,
    196                              NULL, NULL))
    197       {
    198         igr.hr.http_status = 0;
    199         igr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    200         break;
    201       }
    202       if (GNUNET_OK ==
    203           parse_instances (instances,
    204                            &igr,
    205                            gimh))
    206       {
    207         TALER_MERCHANT_get_management_instances_cancel (gimh);
    208         return;
    209       }
    210       igr.hr.http_status = 0;
    211       igr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    212       break;
    213     }
    214   case MHD_HTTP_UNAUTHORIZED:
    215     igr.hr.ec = TALER_JSON_get_error_code (json);
    216     igr.hr.hint = TALER_JSON_get_error_hint (json);
    217     break;
    218   default:
    219     igr.hr.ec = TALER_JSON_get_error_code (json);
    220     igr.hr.hint = TALER_JSON_get_error_hint (json);
    221     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    222                 "Unexpected response code %u/%d\n",
    223                 (unsigned int) response_code,
    224                 (int) igr.hr.ec);
    225     break;
    226   }
    227   gimh->cb (gimh->cb_cls,
    228             &igr);
    229   TALER_MERCHANT_get_management_instances_cancel (gimh);
    230 }
    231 
    232 
    233 struct TALER_MERCHANT_GetManagementInstancesHandle *
    234 TALER_MERCHANT_get_management_instances_create (
    235   struct GNUNET_CURL_Context *ctx,
    236   const char *url)
    237 {
    238   struct TALER_MERCHANT_GetManagementInstancesHandle *gimh;
    239 
    240   gimh = GNUNET_new (struct TALER_MERCHANT_GetManagementInstancesHandle);
    241   gimh->ctx = ctx;
    242   gimh->base_url = GNUNET_strdup (url);
    243   return gimh;
    244 }
    245 
    246 
    247 enum TALER_ErrorCode
    248 TALER_MERCHANT_get_management_instances_start (
    249   struct TALER_MERCHANT_GetManagementInstancesHandle *gimh,
    250   TALER_MERCHANT_GetManagementInstancesCallback cb,
    251   TALER_MERCHANT_GET_MANAGEMENT_INSTANCES_RESULT_CLOSURE *cb_cls)
    252 {
    253   CURL *eh;
    254 
    255   gimh->cb = cb;
    256   gimh->cb_cls = cb_cls;
    257   gimh->url = TALER_url_join (gimh->base_url,
    258                               "management/instances",
    259                               NULL);
    260   if (NULL == gimh->url)
    261     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
    262   eh = TALER_MERCHANT_curl_easy_get_ (gimh->url);
    263   if (NULL == eh)
    264     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
    265   gimh->job = GNUNET_CURL_job_add (gimh->ctx,
    266                                    eh,
    267                                    &handle_get_instances_finished,
    268                                    gimh);
    269   if (NULL == gimh->job)
    270     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    271   return TALER_EC_NONE;
    272 }
    273 
    274 
    275 void
    276 TALER_MERCHANT_get_management_instances_cancel (
    277   struct TALER_MERCHANT_GetManagementInstancesHandle *gimh)
    278 {
    279   if (NULL != gimh->job)
    280   {
    281     GNUNET_CURL_job_cancel (gimh->job);
    282     gimh->job = NULL;
    283   }
    284   GNUNET_free (gimh->url);
    285   GNUNET_free (gimh->base_url);
    286   GNUNET_free (gimh);
    287 }
    288 
    289 
    290 /* end of merchant_api_get-management-instances-new.c */