fakebank_twg_get_transfers.c (7058B)
1 /* 2 This file is part of TALER 3 (C) 2024 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or 6 modify it under the terms of the GNU General Public License 7 as published by the Free Software Foundation; either version 3, 8 or (at your option) any later version. 9 10 TALER is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public 16 License along with TALER; see the file COPYING. If not, 17 see <http://www.gnu.org/licenses/> 18 */ 19 /** 20 * @file bank-lib/fakebank_twg_get_transfers.c 21 * @brief routines to return account histories for the Taler Wire Gateway API 22 * @author Christian Grothoff <christian@grothoff.org> 23 */ 24 #include <pthread.h> 25 #include "taler/taler_fakebank_lib.h" 26 #include "taler/taler_bank_service.h" 27 #include "taler/taler_mhd_lib.h" 28 #include <gnunet/gnunet_mhd_compat.h> 29 #include "fakebank.h" 30 #include "fakebank_common_lookup.h" 31 #include "fakebank_common_lp.h" 32 #include "fakebank_common_parser.h" 33 #include "fakebank_twg_get_transfers.h" 34 35 36 MHD_RESULT 37 TALER_FAKEBANK_twg_get_transfers_ ( 38 struct TALER_FAKEBANK_Handle *h, 39 struct MHD_Connection *connection, 40 const char *account, 41 void **con_cls) 42 { 43 struct Transaction *pos; 44 const char *acc_payto_uri; 45 json_t *history; 46 struct Account *acc; 47 int64_t limit = -20; 48 uint64_t offset; 49 bool have_start; 50 const char *status; 51 52 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 53 "Handling /transfers connection %p\n", 54 connection); 55 56 TALER_MHD_parse_request_snumber (connection, 57 "limit", 58 &limit); 59 if (limit > 0) 60 offset = 0; 61 else 62 offset = UINT64_MAX; 63 TALER_MHD_parse_request_number (connection, 64 "offset", 65 &offset); 66 have_start = ((0 != offset) && (UINT64_MAX != offset)); 67 status = MHD_lookup_connection_value (connection, 68 MHD_GET_ARGUMENT_KIND, 69 "status"); 70 if ( (NULL != status) && 71 (0 != strcasecmp (status, 72 "success")) ) 73 { 74 /* we only have successful transactions */ 75 return TALER_MHD_reply_static (connection, 76 MHD_HTTP_NO_CONTENT, 77 NULL, 78 NULL, 79 0); 80 } 81 82 GNUNET_assert (0 == 83 pthread_mutex_lock (&h->big_lock)); 84 if (UINT64_MAX == offset) 85 offset = h->serial_counter; 86 acc = TALER_FAKEBANK_lookup_account_ (h, 87 account, 88 NULL); 89 if (NULL == acc) 90 { 91 GNUNET_assert (0 == 92 pthread_mutex_unlock (&h->big_lock)); 93 return TALER_MHD_reply_with_error (connection, 94 MHD_HTTP_NOT_FOUND, 95 TALER_EC_BANK_UNKNOWN_ACCOUNT, 96 account); 97 } 98 history = json_array (); 99 if (NULL == history) 100 { 101 GNUNET_break (0); 102 GNUNET_assert (0 == 103 pthread_mutex_unlock (&h->big_lock)); 104 return MHD_NO; 105 } 106 107 if (! have_start) 108 { 109 pos = (0 > limit) 110 ? acc->out_tail 111 : acc->out_head; 112 } 113 else 114 { 115 struct Transaction *t = h->transactions[offset % h->ram_limit]; 116 bool overflow; 117 uint64_t dir; 118 bool skip = true; 119 120 dir = (0 > limit) ? (h->ram_limit - 1) : 1; 121 overflow = (t->row_id != offset); 122 /* If account does not match, linear scan for 123 first matching account. */ 124 while ( (! overflow) && 125 (NULL != t) && 126 (t->debit_account != acc) ) 127 { 128 skip = false; 129 t = h->transactions[(t->row_id + dir) % h->ram_limit]; 130 if ( (NULL != t) && 131 (t->row_id == offset) ) 132 overflow = true; /* full circle, give up! */ 133 } 134 if ( (NULL == t) || 135 (t->debit_account != acc) ) 136 { 137 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 138 "Invalid start specified, transaction %llu not with account %s!\n", 139 (unsigned long long) offset, 140 account); 141 GNUNET_assert (0 == 142 pthread_mutex_unlock (&h->big_lock)); 143 return MHD_NO; 144 } 145 if (skip) 146 { 147 /* range is exclusive, skip the matching entry */ 148 if (0 > limit) 149 pos = t->prev_out; 150 else 151 pos = t->next_out; 152 } 153 else 154 { 155 pos = t; 156 } 157 } 158 if (NULL != pos) 159 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 160 "Returning %lld debit transactions starting (inclusive) from %llu\n", 161 (long long) limit, 162 (unsigned long long) pos->row_id); 163 while ( (0 != limit) && 164 (NULL != pos) ) 165 { 166 json_t *trans; 167 char *credit_payto; 168 169 if (T_DEBIT != pos->type) 170 { 171 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 172 "Unexpected CREDIT transaction #%llu for account `%s'\n", 173 (unsigned long long) pos->row_id, 174 account); 175 if (0 > limit) 176 pos = pos->prev_in; 177 if (0 < limit) 178 pos = pos->next_in; 179 continue; 180 } 181 GNUNET_asprintf (&credit_payto, 182 "payto://x-taler-bank/localhost/%s?receiver-name=%s", 183 pos->credit_account->account_name, 184 pos->credit_account->receiver_name); 185 186 trans = GNUNET_JSON_PACK ( 187 GNUNET_JSON_pack_uint64 ("row_id", 188 pos->row_id), 189 GNUNET_JSON_pack_timestamp ("timestamp", 190 pos->date), 191 TALER_JSON_pack_amount ("amount", 192 &pos->amount), 193 GNUNET_JSON_pack_string ("credit_account", 194 credit_payto), 195 GNUNET_JSON_pack_string ("status", 196 "success")); 197 GNUNET_assert (NULL != trans); 198 GNUNET_free (credit_payto); 199 GNUNET_assert (0 == 200 json_array_append_new (history, 201 trans)); 202 if (limit > 0) 203 limit--; 204 else 205 limit++; 206 if (0 > limit) 207 pos = pos->prev_out; 208 if (0 < limit) 209 pos = pos->next_out; 210 } 211 acc_payto_uri = acc->payto_uri; 212 GNUNET_assert (0 == 213 pthread_mutex_unlock (&h->big_lock)); 214 if (0 == json_array_size (history)) 215 { 216 json_decref (history); 217 return TALER_MHD_reply_static (connection, 218 MHD_HTTP_NO_CONTENT, 219 NULL, 220 NULL, 221 0); 222 } 223 return TALER_MHD_REPLY_JSON_PACK ( 224 connection, 225 MHD_HTTP_OK, 226 GNUNET_JSON_pack_string ( 227 "debit_account", 228 acc_payto_uri), 229 GNUNET_JSON_pack_array_steal ( 230 "transfers", 231 history)); 232 }