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 "taler/platform.h"
25 : #include <pthread.h>
26 : #include "taler/taler_fakebank_lib.h"
27 : #include "taler/taler_bank_service.h"
28 : #include "taler/taler_mhd_lib.h"
29 : #include <gnunet/gnunet_mhd_compat.h>
30 : #include "fakebank.h"
31 : #include "fakebank_common_lookup.h"
32 : #include "fakebank_common_lp.h"
33 : #include "fakebank_common_parser.h"
34 : #include "fakebank_twg_get_transfers.h"
35 :
36 :
37 : MHD_RESULT
38 0 : TALER_FAKEBANK_twg_get_transfers_ (
39 : struct TALER_FAKEBANK_Handle *h,
40 : struct MHD_Connection *connection,
41 : const char *account,
42 : void **con_cls)
43 : {
44 : struct Transaction *pos;
45 : const char *acc_payto_uri;
46 : json_t *history;
47 : struct Account *acc;
48 0 : int64_t limit = -20;
49 : uint64_t offset;
50 : bool have_start;
51 : const char *status;
52 :
53 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
54 : "Handling /transfers connection %p\n",
55 : connection);
56 :
57 0 : TALER_MHD_parse_request_snumber (connection,
58 : "limit",
59 : &limit);
60 0 : if (limit > 0)
61 0 : offset = 0;
62 : else
63 0 : offset = UINT64_MAX;
64 0 : TALER_MHD_parse_request_number (connection,
65 : "offset",
66 : &offset);
67 0 : have_start = ((0 != offset) && (UINT64_MAX != offset));
68 0 : status = MHD_lookup_connection_value (connection,
69 : MHD_GET_ARGUMENT_KIND,
70 : "status");
71 0 : if ( (NULL != status) &&
72 0 : (0 != strcasecmp (status,
73 : "success")) )
74 : {
75 : /* we only have successful transactions */
76 0 : return TALER_MHD_reply_static (connection,
77 : MHD_HTTP_NO_CONTENT,
78 : NULL,
79 : NULL,
80 : 0);
81 : }
82 :
83 0 : GNUNET_assert (0 ==
84 : pthread_mutex_lock (&h->big_lock));
85 0 : if (UINT64_MAX == offset)
86 0 : offset = h->serial_counter;
87 0 : acc = TALER_FAKEBANK_lookup_account_ (h,
88 : account,
89 : NULL);
90 0 : if (NULL == acc)
91 : {
92 0 : GNUNET_assert (0 ==
93 : pthread_mutex_unlock (&h->big_lock));
94 0 : return TALER_MHD_reply_with_error (connection,
95 : MHD_HTTP_NOT_FOUND,
96 : TALER_EC_BANK_UNKNOWN_ACCOUNT,
97 : account);
98 : }
99 0 : history = json_array ();
100 0 : if (NULL == history)
101 : {
102 0 : GNUNET_break (0);
103 0 : GNUNET_assert (0 ==
104 : pthread_mutex_unlock (&h->big_lock));
105 0 : return MHD_NO;
106 : }
107 :
108 0 : if (! have_start)
109 : {
110 0 : pos = (0 > limit)
111 : ? acc->out_tail
112 0 : : acc->out_head;
113 : }
114 : else
115 : {
116 0 : struct Transaction *t = h->transactions[offset % h->ram_limit];
117 : bool overflow;
118 : uint64_t dir;
119 0 : bool skip = true;
120 :
121 0 : dir = (0 > limit) ? (h->ram_limit - 1) : 1;
122 0 : overflow = (t->row_id != offset);
123 : /* If account does not match, linear scan for
124 : first matching account. */
125 0 : while ( (! overflow) &&
126 0 : (NULL != t) &&
127 0 : (t->debit_account != acc) )
128 : {
129 0 : skip = false;
130 0 : t = h->transactions[(t->row_id + dir) % h->ram_limit];
131 0 : if ( (NULL != t) &&
132 0 : (t->row_id == offset) )
133 0 : overflow = true; /* full circle, give up! */
134 : }
135 0 : if ( (NULL == t) ||
136 0 : (t->debit_account != acc) )
137 : {
138 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
139 : "Invalid start specified, transaction %llu not with account %s!\n",
140 : (unsigned long long) offset,
141 : account);
142 0 : GNUNET_assert (0 ==
143 : pthread_mutex_unlock (&h->big_lock));
144 0 : return MHD_NO;
145 : }
146 0 : if (skip)
147 : {
148 : /* range is exclusive, skip the matching entry */
149 0 : if (0 > limit)
150 0 : pos = t->prev_out;
151 : else
152 0 : pos = t->next_out;
153 : }
154 : else
155 : {
156 0 : pos = t;
157 : }
158 : }
159 0 : if (NULL != pos)
160 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
161 : "Returning %lld debit transactions starting (inclusive) from %llu\n",
162 : (long long) limit,
163 : (unsigned long long) pos->row_id);
164 0 : while ( (0 != limit) &&
165 : (NULL != pos) )
166 : {
167 : json_t *trans;
168 : char *credit_payto;
169 :
170 0 : if (T_DEBIT != pos->type)
171 : {
172 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
173 : "Unexpected CREDIT transaction #%llu for account `%s'\n",
174 : (unsigned long long) pos->row_id,
175 : account);
176 0 : if (0 > limit)
177 0 : pos = pos->prev_in;
178 0 : if (0 < limit)
179 0 : pos = pos->next_in;
180 0 : continue;
181 : }
182 0 : GNUNET_asprintf (&credit_payto,
183 : "payto://x-taler-bank/localhost/%s?receiver-name=%s",
184 0 : pos->credit_account->account_name,
185 0 : pos->credit_account->receiver_name);
186 :
187 0 : trans = GNUNET_JSON_PACK (
188 : GNUNET_JSON_pack_uint64 ("row_id",
189 : pos->row_id),
190 : GNUNET_JSON_pack_timestamp ("timestamp",
191 : pos->date),
192 : TALER_JSON_pack_amount ("amount",
193 : &pos->amount),
194 : GNUNET_JSON_pack_string ("credit_account",
195 : credit_payto),
196 : GNUNET_JSON_pack_string ("status",
197 : "success"));
198 0 : GNUNET_assert (NULL != trans);
199 0 : GNUNET_free (credit_payto);
200 0 : GNUNET_assert (0 ==
201 : json_array_append_new (history,
202 : trans));
203 0 : if (limit > 0)
204 0 : limit--;
205 : else
206 0 : limit++;
207 0 : if (0 > limit)
208 0 : pos = pos->prev_out;
209 0 : if (0 < limit)
210 0 : pos = pos->next_out;
211 : }
212 0 : acc_payto_uri = acc->payto_uri;
213 0 : GNUNET_assert (0 ==
214 : pthread_mutex_unlock (&h->big_lock));
215 0 : if (0 == json_array_size (history))
216 : {
217 0 : json_decref (history);
218 0 : return TALER_MHD_reply_static (connection,
219 : MHD_HTTP_NO_CONTENT,
220 : NULL,
221 : NULL,
222 : 0);
223 : }
224 0 : return TALER_MHD_REPLY_JSON_PACK (
225 : connection,
226 : MHD_HTTP_OK,
227 : GNUNET_JSON_pack_string (
228 : "debit_account",
229 : acc_payto_uri),
230 : GNUNET_JSON_pack_array_steal (
231 : "transfers",
232 : history));
233 : }
|