Line data Source code
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 0 : 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 0 : int64_t limit = -20;
48 : uint64_t offset;
49 : bool have_start;
50 : const char *status;
51 :
52 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
53 : "Handling /transfers connection %p\n",
54 : connection);
55 :
56 0 : TALER_MHD_parse_request_snumber (connection,
57 : "limit",
58 : &limit);
59 0 : if (limit > 0)
60 0 : offset = 0;
61 : else
62 0 : offset = UINT64_MAX;
63 0 : TALER_MHD_parse_request_number (connection,
64 : "offset",
65 : &offset);
66 0 : have_start = ((0 != offset) && (UINT64_MAX != offset));
67 0 : status = MHD_lookup_connection_value (connection,
68 : MHD_GET_ARGUMENT_KIND,
69 : "status");
70 0 : if ( (NULL != status) &&
71 0 : (0 != strcasecmp (status,
72 : "success")) )
73 : {
74 : /* we only have successful transactions */
75 0 : return TALER_MHD_reply_static (connection,
76 : MHD_HTTP_NO_CONTENT,
77 : NULL,
78 : NULL,
79 : 0);
80 : }
81 :
82 0 : GNUNET_assert (0 ==
83 : pthread_mutex_lock (&h->big_lock));
84 0 : if (UINT64_MAX == offset)
85 0 : offset = h->serial_counter;
86 0 : acc = TALER_FAKEBANK_lookup_account_ (h,
87 : account,
88 : NULL);
89 0 : if (NULL == acc)
90 : {
91 0 : GNUNET_assert (0 ==
92 : pthread_mutex_unlock (&h->big_lock));
93 0 : return TALER_MHD_reply_with_error (connection,
94 : MHD_HTTP_NOT_FOUND,
95 : TALER_EC_BANK_UNKNOWN_ACCOUNT,
96 : account);
97 : }
98 0 : history = json_array ();
99 0 : if (NULL == history)
100 : {
101 0 : GNUNET_break (0);
102 0 : GNUNET_assert (0 ==
103 : pthread_mutex_unlock (&h->big_lock));
104 0 : return MHD_NO;
105 : }
106 :
107 0 : if (! have_start)
108 : {
109 0 : pos = (0 > limit)
110 : ? acc->out_tail
111 0 : : acc->out_head;
112 : }
113 : else
114 : {
115 0 : struct Transaction *t = h->transactions[offset % h->ram_limit];
116 : bool overflow;
117 : uint64_t dir;
118 0 : bool skip = true;
119 :
120 0 : dir = (0 > limit) ? (h->ram_limit - 1) : 1;
121 0 : overflow = (t->row_id != offset);
122 : /* If account does not match, linear scan for
123 : first matching account. */
124 0 : while ( (! overflow) &&
125 0 : (NULL != t) &&
126 0 : (t->debit_account != acc) )
127 : {
128 0 : skip = false;
129 0 : t = h->transactions[(t->row_id + dir) % h->ram_limit];
130 0 : if ( (NULL != t) &&
131 0 : (t->row_id == offset) )
132 0 : overflow = true; /* full circle, give up! */
133 : }
134 0 : if ( (NULL == t) ||
135 0 : (t->debit_account != acc) )
136 : {
137 0 : 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 0 : GNUNET_assert (0 ==
142 : pthread_mutex_unlock (&h->big_lock));
143 0 : return MHD_NO;
144 : }
145 0 : if (skip)
146 : {
147 : /* range is exclusive, skip the matching entry */
148 0 : if (0 > limit)
149 0 : pos = t->prev_out;
150 : else
151 0 : pos = t->next_out;
152 : }
153 : else
154 : {
155 0 : pos = t;
156 : }
157 : }
158 0 : if (NULL != pos)
159 0 : 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 0 : while ( (0 != limit) &&
164 : (NULL != pos) )
165 : {
166 : json_t *trans;
167 : char *credit_payto;
168 :
169 0 : if (T_DEBIT != pos->type)
170 : {
171 0 : 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 0 : if (0 > limit)
176 0 : pos = pos->prev_in;
177 0 : if (0 < limit)
178 0 : pos = pos->next_in;
179 0 : continue;
180 : }
181 0 : GNUNET_asprintf (&credit_payto,
182 : "payto://x-taler-bank/localhost/%s?receiver-name=%s",
183 0 : pos->credit_account->account_name,
184 0 : pos->credit_account->receiver_name);
185 :
186 0 : 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 0 : GNUNET_assert (NULL != trans);
198 0 : GNUNET_free (credit_payto);
199 0 : GNUNET_assert (0 ==
200 : json_array_append_new (history,
201 : trans));
202 0 : if (limit > 0)
203 0 : limit--;
204 : else
205 0 : limit++;
206 0 : if (0 > limit)
207 0 : pos = pos->prev_out;
208 0 : if (0 < limit)
209 0 : pos = pos->next_out;
210 : }
211 0 : acc_payto_uri = acc->payto_uri;
212 0 : GNUNET_assert (0 ==
213 : pthread_mutex_unlock (&h->big_lock));
214 0 : if (0 == json_array_size (history))
215 : {
216 0 : json_decref (history);
217 0 : return TALER_MHD_reply_static (connection,
218 : MHD_HTTP_NO_CONTENT,
219 : NULL,
220 : NULL,
221 : 0);
222 : }
223 0 : 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 : }
|