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 */