merchant

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

merchant_api_get_unit.c (7167B)


      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 <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file merchant_api_get_unit.c
     18  * @brief Implementation of GET /private/units/$ID
     19  * @author Bohdan Potuzhnyi
     20  */
     21 #include "platform.h"
     22 #include <curl/curl.h>
     23 #include <jansson.h>
     24 #include <microhttpd.h>
     25 #include <gnunet/gnunet_util_lib.h>
     26 #include <gnunet/gnunet_curl_lib.h>
     27 #include "taler_merchant_service.h"
     28 #include "merchant_api_curl_defaults.h"
     29 #include <taler/taler_json_lib.h>
     30 
     31 
     32 /**
     33  * Handle for a GET /private/units/$ID operation.
     34  */
     35 struct TALER_MERCHANT_UnitGetHandle
     36 {
     37   /**
     38    * Fully qualified request URL.
     39    */
     40   char *url;
     41 
     42   /**
     43    * In-flight job handle.
     44    */
     45   struct GNUNET_CURL_Job *job;
     46 
     47   /**
     48    * Callback to invoke with the response.
     49    */
     50   TALER_MERCHANT_UnitGetCallback cb;
     51 
     52   /**
     53    * Closure for @a cb.
     54    */
     55   void *cb_cls;
     56 
     57   /**
     58    * Execution context.
     59    */
     60   struct GNUNET_CURL_Context *ctx;
     61 };
     62 
     63 
     64 /**
     65  * Parse the JSON response into @a ugr.
     66  *
     67  * @param json full JSON reply
     68  * @param ugr response descriptor to populate
     69  * @return #GNUNET_OK on success
     70  */
     71 static enum GNUNET_GenericReturnValue
     72 parse_unit (const json_t *json,
     73             struct TALER_MERCHANT_UnitGetResponse *ugr)
     74 {
     75   struct TALER_MERCHANT_UnitEntry *entry = &ugr->details.ok.unit;
     76   const char *unit;
     77   const char *unit_name_long;
     78   const char *unit_name_short;
     79   const json_t *unit_name_long_i18n = NULL;
     80   const json_t *unit_name_short_i18n = NULL;
     81   bool unit_allow_fraction;
     82   bool unit_active;
     83   bool unit_builtin;
     84   uint32_t unit_precision_level;
     85   struct GNUNET_JSON_Specification spec[] = {
     86     GNUNET_JSON_spec_string ("unit",
     87                              &unit),
     88     GNUNET_JSON_spec_string ("unit_name_long",
     89                              &unit_name_long),
     90     GNUNET_JSON_spec_string ("unit_name_short",
     91                              &unit_name_short),
     92     GNUNET_JSON_spec_mark_optional (
     93       GNUNET_JSON_spec_object_const ("unit_name_long_i18n",
     94                                      &unit_name_long_i18n),
     95       NULL),
     96     GNUNET_JSON_spec_mark_optional (
     97       GNUNET_JSON_spec_object_const ("unit_name_short_i18n",
     98                                      &unit_name_short_i18n),
     99       NULL),
    100     GNUNET_JSON_spec_bool ("unit_allow_fraction",
    101                            &unit_allow_fraction),
    102     GNUNET_JSON_spec_uint32 ("unit_precision_level",
    103                              &unit_precision_level),
    104     GNUNET_JSON_spec_bool ("unit_active",
    105                            &unit_active),
    106     GNUNET_JSON_spec_bool ("unit_builtin",
    107                            &unit_builtin),
    108     GNUNET_JSON_spec_end ()
    109   };
    110 
    111   if (GNUNET_OK !=
    112       GNUNET_JSON_parse (json,
    113                          spec,
    114                          NULL,
    115                          NULL))
    116   {
    117     GNUNET_break_op (0);
    118     GNUNET_JSON_parse_free (spec);
    119     return GNUNET_SYSERR;
    120   }
    121   GNUNET_JSON_parse_free (spec);
    122   entry->unit = unit;
    123   entry->unit_name_long = unit_name_long;
    124   entry->unit_name_short = unit_name_short;
    125   entry->unit_name_long_i18n = unit_name_long_i18n;
    126   entry->unit_name_short_i18n = unit_name_short_i18n;
    127   entry->unit_allow_fraction = unit_allow_fraction;
    128   entry->unit_precision_level = unit_precision_level;
    129   entry->unit_active = unit_active;
    130   entry->unit_builtin = unit_builtin;
    131   return GNUNET_OK;
    132 }
    133 
    134 
    135 /**
    136  * Called once the HTTP request completes.
    137  *
    138  * @param cls operation handle
    139  * @param response_code HTTP status (0 on client-side errors)
    140  * @param response parsed JSON reply (NULL if parsing failed)
    141  */
    142 static void
    143 handle_get_unit_finished (void *cls,
    144                           long response_code,
    145                           const void *response)
    146 {
    147   struct TALER_MERCHANT_UnitGetHandle *ugh = cls;
    148   const json_t *json = response;
    149   struct TALER_MERCHANT_UnitGetResponse ugr = {
    150     .hr.http_status = (unsigned int) response_code,
    151     .hr.reply = json
    152   };
    153 
    154   ugh->job = NULL;
    155   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    156               "GET /private/units/$ID finished with status %u\n",
    157               (unsigned int) response_code);
    158   switch (response_code)
    159   {
    160   case MHD_HTTP_OK:
    161     if (GNUNET_OK !=
    162         parse_unit (json,
    163                     &ugr))
    164     {
    165       ugr.hr.http_status = 0;
    166       ugr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    167       break;
    168     }
    169     ugh->cb (ugh->cb_cls,
    170              &ugr);
    171     TALER_MERCHANT_unit_get_cancel (ugh);
    172     return;
    173   case MHD_HTTP_UNAUTHORIZED:
    174   case MHD_HTTP_FORBIDDEN:
    175   case MHD_HTTP_NOT_FOUND:
    176     ugr.hr.ec = TALER_JSON_get_error_code (json);
    177     ugr.hr.hint = TALER_JSON_get_error_hint (json);
    178     break;
    179   case 0:
    180     ugr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    181     break;
    182   default:
    183     ugr.hr.ec = TALER_JSON_get_error_code (json);
    184     ugr.hr.hint = TALER_JSON_get_error_hint (json);
    185     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    186                 "Unexpected response %u/%d for GET /private/units/$ID\n",
    187                 (unsigned int) response_code,
    188                 (int) ugr.hr.ec);
    189     break;
    190   }
    191   ugh->cb (ugh->cb_cls,
    192            &ugr);
    193   TALER_MERCHANT_unit_get_cancel (ugh);
    194 }
    195 
    196 
    197 struct TALER_MERCHANT_UnitGetHandle *
    198 TALER_MERCHANT_unit_get (struct GNUNET_CURL_Context *ctx,
    199                          const char *backend_url,
    200                          const char *unit_id,
    201                          TALER_MERCHANT_UnitGetCallback cb,
    202                          void *cb_cls)
    203 {
    204   struct TALER_MERCHANT_UnitGetHandle *ugh;
    205   CURL *eh;
    206   char *path;
    207 
    208   GNUNET_asprintf (&path,
    209                    "private/units/%s",
    210                    unit_id);
    211   ugh = GNUNET_new (struct TALER_MERCHANT_UnitGetHandle);
    212   ugh->ctx = ctx;
    213   ugh->cb = cb;
    214   ugh->cb_cls = cb_cls;
    215   ugh->url = TALER_url_join (backend_url,
    216                              path,
    217                              NULL);
    218   GNUNET_free (path);
    219   if (NULL == ugh->url)
    220   {
    221     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    222                 "Failed to build /private/units/%s URL\n",
    223                 unit_id);
    224     GNUNET_free (ugh);
    225     return NULL;
    226   }
    227   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    228               "Requesting URL '%s'\n",
    229               ugh->url);
    230   eh = TALER_MERCHANT_curl_easy_get_ (ugh->url);
    231   ugh->job = GNUNET_CURL_job_add (ctx,
    232                                   eh,
    233                                   &handle_get_unit_finished,
    234                                   ugh);
    235   return ugh;
    236 }
    237 
    238 
    239 void
    240 TALER_MERCHANT_unit_get_cancel (struct TALER_MERCHANT_UnitGetHandle *ugh)
    241 {
    242   if (NULL != ugh->job)
    243     GNUNET_CURL_job_cancel (ugh->job);
    244   GNUNET_free (ugh->url);
    245   GNUNET_free (ugh);
    246 }
    247 
    248 
    249 /* end of merchant_api_get_unit.c */