exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

exchange_api_post-management-drain.c (7453B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2020-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 General Public License as published by the Free Software
      7   Foundation; either version 3, 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 General Public License for more details.
     12 
     13   You should have received a copy of the GNU General Public License along with
     14   TALER; see the file COPYING.  If not, see
     15   <http://www.gnu.org/licenses/>
     16 */
     17 /**
     18  * @file lib/exchange_api_post-management-drain.c
     19  * @brief functions to drain profits from an exchange account
     20  * @author Christian Grothoff
     21  */
     22 #include "taler/taler_json_lib.h"
     23 #include <gnunet/gnunet_curl_lib.h>
     24 #include <microhttpd.h>
     25 #include "taler/exchange/post-management-drain.h"
     26 #include "exchange_api_curl_defaults.h"
     27 #include "taler/taler_curl_lib.h"
     28 
     29 
     30 struct TALER_EXCHANGE_PostManagementDrainHandle
     31 {
     32 
     33   /**
     34    * The base URL for this request.
     35    */
     36   char *base_url;
     37 
     38   /**
     39    * The full URL for this request, set during _start.
     40    */
     41   char *url;
     42 
     43   /**
     44    * Minor context that holds body and headers.
     45    */
     46   struct TALER_CURL_PostContext post_ctx;
     47 
     48   /**
     49    * Handle for the request.
     50    */
     51   struct GNUNET_CURL_Job *job;
     52 
     53   /**
     54    * Function to call with the result.
     55    */
     56   TALER_EXCHANGE_PostManagementDrainCallback cb;
     57 
     58   /**
     59    * Closure for @a cb.
     60    */
     61   TALER_EXCHANGE_POST_MANAGEMENT_DRAIN_RESULT_CLOSURE *cb_cls;
     62 
     63   /**
     64    * Reference to the execution context.
     65    */
     66   struct GNUNET_CURL_Context *ctx;
     67 
     68   /**
     69    * Wire transfer identifier to use.
     70    */
     71   struct TALER_WireTransferIdentifierRawP wtid;
     72 
     73   /**
     74    * Total to transfer.
     75    */
     76   struct TALER_Amount amount;
     77 
     78   /**
     79    * When was the request created.
     80    */
     81   struct GNUNET_TIME_Timestamp date;
     82 
     83   /**
     84    * Configuration section identifying account to debit.
     85    */
     86   char *account_section;
     87 
     88   /**
     89    * Payto URI of the account to credit.
     90    */
     91   char *payto_uri_str;
     92 
     93   /**
     94    * Signature affirming the operation.
     95    */
     96   struct TALER_MasterSignatureP master_sig;
     97 
     98 };
     99 
    100 
    101 /**
    102  * Function called when we're done processing the
    103  * HTTP POST /management/drain request.
    104  *
    105  * @param cls the `struct TALER_EXCHANGE_PostManagementDrainHandle`
    106  * @param response_code HTTP response code, 0 on error
    107  * @param response response body, NULL if not in JSON
    108  */
    109 static void
    110 handle_drain_finished (void *cls,
    111                        long response_code,
    112                        const void *response)
    113 {
    114   struct TALER_EXCHANGE_PostManagementDrainHandle *pmdh = cls;
    115   const json_t *json = response;
    116   struct TALER_EXCHANGE_PostManagementDrainResponse res = {
    117     .hr.http_status = (unsigned int) response_code,
    118     .hr.reply = json
    119   };
    120 
    121   pmdh->job = NULL;
    122   switch (response_code)
    123   {
    124   case MHD_HTTP_NO_CONTENT:
    125     break;
    126   case MHD_HTTP_FORBIDDEN:
    127     res.hr.ec = TALER_JSON_get_error_code (json);
    128     res.hr.hint = TALER_JSON_get_error_hint (json);
    129     break;
    130   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    131     res.hr.ec = TALER_JSON_get_error_code (json);
    132     res.hr.hint = TALER_JSON_get_error_hint (json);
    133     break;
    134   default:
    135     /* unexpected response code */
    136     GNUNET_break_op (0);
    137     res.hr.ec = TALER_JSON_get_error_code (json);
    138     res.hr.hint = TALER_JSON_get_error_hint (json);
    139     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    140                 "Unexpected response code %u/%d for exchange management drain profits\n",
    141                 (unsigned int) response_code,
    142                 (int) res.hr.ec);
    143     break;
    144   }
    145   if (NULL != pmdh->cb)
    146   {
    147     pmdh->cb (pmdh->cb_cls,
    148               &res);
    149     pmdh->cb = NULL;
    150   }
    151   TALER_EXCHANGE_post_management_drain_cancel (pmdh);
    152 }
    153 
    154 
    155 struct TALER_EXCHANGE_PostManagementDrainHandle *
    156 TALER_EXCHANGE_post_management_drain_create (
    157   struct GNUNET_CURL_Context *ctx,
    158   const char *url,
    159   const struct TALER_WireTransferIdentifierRawP *wtid,
    160   const struct TALER_Amount *amount,
    161   struct GNUNET_TIME_Timestamp date,
    162   const char *account_section,
    163   const struct TALER_FullPayto payto_uri,
    164   const struct TALER_MasterSignatureP *master_sig)
    165 {
    166   struct TALER_EXCHANGE_PostManagementDrainHandle *pmdh;
    167 
    168   pmdh = GNUNET_new (struct TALER_EXCHANGE_PostManagementDrainHandle);
    169   pmdh->ctx = ctx;
    170   pmdh->base_url = GNUNET_strdup (url);
    171   pmdh->wtid = *wtid;
    172   pmdh->amount = *amount;
    173   pmdh->date = date;
    174   pmdh->account_section = GNUNET_strdup (account_section);
    175   pmdh->payto_uri_str = GNUNET_strdup (payto_uri.full_payto);
    176   pmdh->master_sig = *master_sig;
    177   return pmdh;
    178 }
    179 
    180 
    181 enum TALER_ErrorCode
    182 TALER_EXCHANGE_post_management_drain_start (
    183   struct TALER_EXCHANGE_PostManagementDrainHandle *pmdh,
    184   TALER_EXCHANGE_PostManagementDrainCallback cb,
    185   TALER_EXCHANGE_POST_MANAGEMENT_DRAIN_RESULT_CLOSURE *cb_cls)
    186 {
    187   CURL *eh;
    188   json_t *body;
    189   struct TALER_FullPayto payto_uri = {
    190     .full_payto = pmdh->payto_uri_str
    191   };
    192 
    193   pmdh->cb = cb;
    194   pmdh->cb_cls = cb_cls;
    195   pmdh->url = TALER_url_join (pmdh->base_url,
    196                               "management/drain",
    197                               NULL);
    198   if (NULL == pmdh->url)
    199   {
    200     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    201                 "Could not construct request URL.\n");
    202     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
    203   }
    204   body = GNUNET_JSON_PACK (
    205     GNUNET_JSON_pack_string ("debit_account_section",
    206                              pmdh->account_section),
    207     TALER_JSON_pack_full_payto ("credit_payto_uri",
    208                                 payto_uri),
    209     GNUNET_JSON_pack_data_auto ("wtid",
    210                                 &pmdh->wtid),
    211     GNUNET_JSON_pack_data_auto ("master_sig",
    212                                 &pmdh->master_sig),
    213     GNUNET_JSON_pack_timestamp ("date",
    214                                 pmdh->date),
    215     TALER_JSON_pack_amount ("amount",
    216                             &pmdh->amount));
    217   eh = TALER_EXCHANGE_curl_easy_get_ (pmdh->url);
    218   if ( (NULL == eh) ||
    219        (GNUNET_OK !=
    220         TALER_curl_easy_post (&pmdh->post_ctx,
    221                               eh,
    222                               body)) )
    223   {
    224     GNUNET_break (0);
    225     if (NULL != eh)
    226       curl_easy_cleanup (eh);
    227     json_decref (body);
    228     GNUNET_free (pmdh->url);
    229     pmdh->url = NULL;
    230     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    231   }
    232   json_decref (body);
    233   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    234               "Requesting URL '%s'\n",
    235               pmdh->url);
    236   pmdh->job = GNUNET_CURL_job_add2 (pmdh->ctx,
    237                                     eh,
    238                                     pmdh->post_ctx.headers,
    239                                     &handle_drain_finished,
    240                                     pmdh);
    241   if (NULL == pmdh->job)
    242   {
    243     TALER_curl_easy_post_finished (&pmdh->post_ctx);
    244     GNUNET_free (pmdh->url);
    245     pmdh->url = NULL;
    246     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    247   }
    248   return TALER_EC_NONE;
    249 }
    250 
    251 
    252 void
    253 TALER_EXCHANGE_post_management_drain_cancel (
    254   struct TALER_EXCHANGE_PostManagementDrainHandle *pmdh)
    255 {
    256   if (NULL != pmdh->job)
    257   {
    258     GNUNET_CURL_job_cancel (pmdh->job);
    259     pmdh->job = NULL;
    260   }
    261   TALER_curl_easy_post_finished (&pmdh->post_ctx);
    262   GNUNET_free (pmdh->account_section);
    263   GNUNET_free (pmdh->payto_uri_str);
    264   GNUNET_free (pmdh->url);
    265   GNUNET_free (pmdh->base_url);
    266   GNUNET_free (pmdh);
    267 }
    268 
    269 
    270 /* end of exchange_api_post-management-drain.c */