bank API refactoring for #7276 (incomplete)
This commit is contained in:
parent
8e0f06c86b
commit
741831e87b
@ -77,6 +77,11 @@ static enum GNUNET_GenericReturnValue
|
||||
parse_account_history (struct TALER_BANK_CreditHistoryHandle *hh,
|
||||
const json_t *history)
|
||||
{
|
||||
struct TALER_BANK_CreditHistoryResponse chr = {
|
||||
.http_status = MHD_HTTP_OK,
|
||||
.ec = TALER_EC_NONE,
|
||||
.response = history
|
||||
};
|
||||
json_t *history_array;
|
||||
|
||||
if (NULL == (history_array = json_object_get (history,
|
||||
@ -90,23 +95,26 @@ parse_account_history (struct TALER_BANK_CreditHistoryHandle *hh,
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
{
|
||||
size_t len = json_array_size (history_array);
|
||||
struct TALER_BANK_CreditDetails cd[len];
|
||||
|
||||
for (unsigned int i = 0; i<json_array_size (history_array); i++)
|
||||
{
|
||||
struct TALER_BANK_CreditDetails td;
|
||||
uint64_t row_id;
|
||||
struct TALER_BANK_CreditDetails *td = &cd[i];
|
||||
struct GNUNET_JSON_Specification hist_spec[] = {
|
||||
TALER_JSON_spec_amount_any ("amount",
|
||||
&td.amount),
|
||||
&td->amount),
|
||||
GNUNET_JSON_spec_timestamp ("date",
|
||||
&td.execution_date),
|
||||
&td->execution_date),
|
||||
GNUNET_JSON_spec_uint64 ("row_id",
|
||||
&row_id),
|
||||
&td->serial_id),
|
||||
GNUNET_JSON_spec_fixed_auto ("reserve_pub",
|
||||
&td.reserve_pub),
|
||||
&td->reserve_pub),
|
||||
GNUNET_JSON_spec_string ("debit_account",
|
||||
&td.debit_account_uri),
|
||||
&td->debit_account_uri),
|
||||
GNUNET_JSON_spec_string ("credit_account",
|
||||
&td.credit_account_uri),
|
||||
&td->credit_account_uri),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
json_t *transaction = json_array_get (history_array,
|
||||
@ -115,24 +123,17 @@ parse_account_history (struct TALER_BANK_CreditHistoryHandle *hh,
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_JSON_parse (transaction,
|
||||
hist_spec,
|
||||
NULL, NULL))
|
||||
NULL,
|
||||
NULL))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
hh->hcb (hh->hcb_cls,
|
||||
MHD_HTTP_OK,
|
||||
TALER_EC_NONE,
|
||||
row_id,
|
||||
&td,
|
||||
transaction))
|
||||
{
|
||||
hh->hcb = NULL;
|
||||
GNUNET_JSON_parse_free (hist_spec);
|
||||
return GNUNET_OK;
|
||||
}
|
||||
GNUNET_JSON_parse_free (hist_spec);
|
||||
chr.details.success.details_length = len;
|
||||
chr.details.success.details = cd;
|
||||
hh->hcb (hh->hcb_cls,
|
||||
&chr);
|
||||
}
|
||||
return GNUNET_OK;
|
||||
}
|
||||
@ -152,72 +153,67 @@ handle_credit_history_finished (void *cls,
|
||||
const void *response)
|
||||
{
|
||||
struct TALER_BANK_CreditHistoryHandle *hh = cls;
|
||||
const json_t *j = response;
|
||||
enum TALER_ErrorCode ec;
|
||||
struct TALER_BANK_CreditHistoryResponse chr = {
|
||||
.http_status = MHD_HTTP_OK,
|
||||
.response = response
|
||||
};
|
||||
|
||||
hh->job = NULL;
|
||||
switch (response_code)
|
||||
{
|
||||
case 0:
|
||||
ec = TALER_EC_GENERIC_INVALID_RESPONSE;
|
||||
chr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
|
||||
break;
|
||||
case MHD_HTTP_OK:
|
||||
if (GNUNET_OK !=
|
||||
parse_account_history (hh,
|
||||
j))
|
||||
chr.response))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
json_dumpf (j,
|
||||
json_dumpf (chr.response,
|
||||
stderr,
|
||||
JSON_INDENT (2));
|
||||
response_code = 0;
|
||||
ec = TALER_EC_GENERIC_INVALID_RESPONSE;
|
||||
chr.http_status = 0;
|
||||
chr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
|
||||
break;
|
||||
}
|
||||
response_code = MHD_HTTP_NO_CONTENT; /* signal end of list */
|
||||
ec = TALER_EC_NONE;
|
||||
break;
|
||||
TALER_BANK_credit_history_cancel (hh);
|
||||
return;
|
||||
case MHD_HTTP_NO_CONTENT:
|
||||
ec = TALER_EC_NONE;
|
||||
break;
|
||||
case MHD_HTTP_BAD_REQUEST:
|
||||
/* This should never happen, either us or the bank is buggy
|
||||
(or API version conflict); just pass JSON reply to the application */
|
||||
GNUNET_break_op (0);
|
||||
ec = TALER_JSON_get_error_code (j);
|
||||
chr.ec = TALER_JSON_get_error_code (chr.response);
|
||||
break;
|
||||
case MHD_HTTP_UNAUTHORIZED:
|
||||
/* Nothing really to verify, bank says the HTTP Authentication
|
||||
failed. May happen if HTTP authentication is used and the
|
||||
user supplied a wrong username/password combination. */
|
||||
ec = TALER_JSON_get_error_code (j);
|
||||
chr.ec = TALER_JSON_get_error_code (chr.response);
|
||||
break;
|
||||
case MHD_HTTP_NOT_FOUND:
|
||||
/* Nothing really to verify: the bank is either unaware
|
||||
of the endpoint (not a bank), or of the account.
|
||||
We should pass the JSON (?) reply to the application */
|
||||
ec = TALER_JSON_get_error_code (j);
|
||||
chr.ec = TALER_JSON_get_error_code (chr.response);
|
||||
break;
|
||||
case MHD_HTTP_INTERNAL_SERVER_ERROR:
|
||||
/* Server had an internal issue; we should retry, but this API
|
||||
leaves this to the application */
|
||||
ec = TALER_JSON_get_error_code (j);
|
||||
chr.ec = TALER_JSON_get_error_code (chr.response);
|
||||
break;
|
||||
default:
|
||||
/* unexpected response code */
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Unexpected response code %u\n",
|
||||
(unsigned int) response_code);
|
||||
ec = TALER_JSON_get_error_code (j);
|
||||
chr.ec = TALER_JSON_get_error_code (chr.response);
|
||||
break;
|
||||
}
|
||||
if (NULL != hh->hcb)
|
||||
hh->hcb (hh->hcb_cls,
|
||||
response_code,
|
||||
ec,
|
||||
0LLU,
|
||||
NULL,
|
||||
j);
|
||||
&chr);
|
||||
TALER_BANK_credit_history_cancel (hh);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2017--2021 Taler Systems SA
|
||||
Copyright (C) 2017--2022 Taler Systems SA
|
||||
|
||||
TALER is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
@ -77,6 +77,11 @@ static enum GNUNET_GenericReturnValue
|
||||
parse_account_history (struct TALER_BANK_DebitHistoryHandle *hh,
|
||||
const json_t *history)
|
||||
{
|
||||
struct TALER_BANK_DebitHistoryResponse dhr = {
|
||||
.http_status = MHD_HTTP_OK,
|
||||
.ec = TALER_EC_NONE,
|
||||
.response = history
|
||||
};
|
||||
json_t *history_array;
|
||||
|
||||
if (NULL == (history_array = json_object_get (history,
|
||||
@ -90,25 +95,28 @@ parse_account_history (struct TALER_BANK_DebitHistoryHandle *hh,
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
for (unsigned int i = 0; i<json_array_size (history_array); i++)
|
||||
{
|
||||
struct TALER_BANK_DebitDetails td;
|
||||
uint64_t row_id;
|
||||
size_t len = json_array_size (history_array);
|
||||
struct TALER_BANK_DebitDetails dd[len];
|
||||
|
||||
for (unsigned int i = 0; i<len; i++)
|
||||
{
|
||||
struct TALER_BANK_DebitDetails *td = &dd[i];
|
||||
struct GNUNET_JSON_Specification hist_spec[] = {
|
||||
TALER_JSON_spec_amount_any ("amount",
|
||||
&td.amount),
|
||||
&td->amount),
|
||||
GNUNET_JSON_spec_timestamp ("date",
|
||||
&td.execution_date),
|
||||
&td->execution_date),
|
||||
GNUNET_JSON_spec_uint64 ("row_id",
|
||||
&row_id),
|
||||
&td->serial_id),
|
||||
GNUNET_JSON_spec_fixed_auto ("wtid",
|
||||
&td.wtid),
|
||||
&td->wtid),
|
||||
GNUNET_JSON_spec_string ("credit_account",
|
||||
&td.credit_account_uri),
|
||||
&td->credit_account_uri),
|
||||
GNUNET_JSON_spec_string ("debit_account",
|
||||
&td.debit_account_uri),
|
||||
&td->debit_account_uri),
|
||||
GNUNET_JSON_spec_string ("exchange_base_url",
|
||||
&td.exchange_base_url),
|
||||
&td->exchange_base_url),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
json_t *transaction = json_array_get (history_array,
|
||||
@ -117,24 +125,17 @@ parse_account_history (struct TALER_BANK_DebitHistoryHandle *hh,
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_JSON_parse (transaction,
|
||||
hist_spec,
|
||||
NULL, NULL))
|
||||
NULL,
|
||||
NULL))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
hh->hcb (hh->hcb_cls,
|
||||
MHD_HTTP_OK,
|
||||
TALER_EC_NONE,
|
||||
row_id,
|
||||
&td,
|
||||
transaction))
|
||||
{
|
||||
hh->hcb = NULL;
|
||||
GNUNET_JSON_parse_free (hist_spec);
|
||||
return GNUNET_OK;
|
||||
}
|
||||
GNUNET_JSON_parse_free (hist_spec);
|
||||
dhr.details.success.details_length = len;
|
||||
dhr.details.success.details = dd;
|
||||
hh->hcb (hh->hcb_cls,
|
||||
&dhr);
|
||||
}
|
||||
return GNUNET_OK;
|
||||
}
|
||||
@ -154,69 +155,64 @@ handle_debit_history_finished (void *cls,
|
||||
const void *response)
|
||||
{
|
||||
struct TALER_BANK_DebitHistoryHandle *hh = cls;
|
||||
const json_t *j = response;
|
||||
enum TALER_ErrorCode ec;
|
||||
struct TALER_BANK_DebitHistoryResponse dhr = {
|
||||
.http_status = MHD_HTTP_OK,
|
||||
.response = response
|
||||
};
|
||||
|
||||
hh->job = NULL;
|
||||
switch (response_code)
|
||||
{
|
||||
case 0:
|
||||
ec = TALER_EC_GENERIC_INVALID_RESPONSE;
|
||||
dhr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
|
||||
break;
|
||||
case MHD_HTTP_OK:
|
||||
if (GNUNET_OK !=
|
||||
parse_account_history (hh,
|
||||
j))
|
||||
dhr.response))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
response_code = 0;
|
||||
ec = TALER_EC_GENERIC_INVALID_RESPONSE;
|
||||
dhr.http_status = 0;
|
||||
dhr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
|
||||
break;
|
||||
}
|
||||
response_code = MHD_HTTP_NO_CONTENT; /* signal end of list */
|
||||
ec = TALER_EC_NONE;
|
||||
break;
|
||||
TALER_BANK_debit_history_cancel (hh);
|
||||
return;
|
||||
case MHD_HTTP_NO_CONTENT:
|
||||
ec = TALER_EC_NONE;
|
||||
break;
|
||||
case MHD_HTTP_BAD_REQUEST:
|
||||
/* This should never happen, either us or the bank is buggy
|
||||
(or API version conflict); just pass JSON reply to the application */
|
||||
GNUNET_break_op (0);
|
||||
ec = TALER_JSON_get_error_code (j);
|
||||
dhr.ec = TALER_JSON_get_error_code (dhr.response);
|
||||
break;
|
||||
case MHD_HTTP_UNAUTHORIZED:
|
||||
/* Nothing really to verify, bank says the HTTP Authentication
|
||||
failed. May happen if HTTP authentication is used and the
|
||||
user supplied a wrong username/password combination. */
|
||||
ec = TALER_JSON_get_error_code (j);
|
||||
dhr.ec = TALER_JSON_get_error_code (dhr.response);
|
||||
break;
|
||||
case MHD_HTTP_NOT_FOUND:
|
||||
/* Nothing really to verify: the bank is either unaware
|
||||
of the endpoint (not a bank), or of the account.
|
||||
We should pass the JSON (?) reply to the application */
|
||||
ec = TALER_JSON_get_error_code (j);
|
||||
dhr.ec = TALER_JSON_get_error_code (dhr.response);
|
||||
break;
|
||||
case MHD_HTTP_INTERNAL_SERVER_ERROR:
|
||||
/* Server had an internal issue; we should retry, but this API
|
||||
leaves this to the application */
|
||||
ec = TALER_JSON_get_error_code (j);
|
||||
dhr.ec = TALER_JSON_get_error_code (dhr.response);
|
||||
break;
|
||||
default:
|
||||
/* unexpected response code */
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Unexpected response code %u\n",
|
||||
(unsigned int) response_code);
|
||||
ec = TALER_JSON_get_error_code (j);
|
||||
dhr.ec = TALER_JSON_get_error_code (dhr.response);
|
||||
break;
|
||||
}
|
||||
if (NULL != hh->hcb)
|
||||
hh->hcb (hh->hcb_cls,
|
||||
response_code,
|
||||
ec,
|
||||
0LLU,
|
||||
NULL,
|
||||
j);
|
||||
&dhr);
|
||||
TALER_BANK_debit_history_cancel (hh);
|
||||
}
|
||||
|
||||
|
@ -152,83 +152,72 @@ do_shutdown (void *cls)
|
||||
|
||||
|
||||
/**
|
||||
* Callback used to process ONE entry in the transaction
|
||||
* Callback used to process the transaction
|
||||
* history returned by the bank.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param http_status HTTP status code from server
|
||||
* @param ec taler error code
|
||||
* @param serial_id identification of the position at
|
||||
* which we are returning data
|
||||
* @param details details about the wire transfer
|
||||
* @param json original full response from server
|
||||
* @return #GNUNET_OK to continue, #GNUNET_SYSERR to
|
||||
* abort iteration
|
||||
* @param reply response we got from the bank
|
||||
*/
|
||||
static enum GNUNET_GenericReturnValue
|
||||
static void
|
||||
credit_history_cb (void *cls,
|
||||
unsigned int http_status,
|
||||
enum TALER_ErrorCode ec,
|
||||
uint64_t serial_id,
|
||||
const struct TALER_BANK_CreditDetails *details,
|
||||
const json_t *json)
|
||||
const struct TALER_BANK_CreditHistoryResponse *reply)
|
||||
{
|
||||
(void) cls;
|
||||
|
||||
chh = NULL;
|
||||
if (MHD_HTTP_OK != http_status)
|
||||
{
|
||||
if ( (MHD_HTTP_NO_CONTENT != http_status) ||
|
||||
(TALER_EC_NONE != ec) )
|
||||
{
|
||||
if (0 == http_status)
|
||||
switch (reply->http_status)
|
||||
{
|
||||
case 0:
|
||||
fprintf (stderr,
|
||||
"Failed to obtain HTTP reply from `%s'\n",
|
||||
auth.wire_gateway_url);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Failed to obtain credit history from `%s': HTTP status %u (%s)\n",
|
||||
auth.wire_gateway_url,
|
||||
http_status,
|
||||
TALER_ErrorCode_get_hint (ec));
|
||||
}
|
||||
if (NULL != json)
|
||||
json_dumpf (json,
|
||||
stderr,
|
||||
JSON_INDENT (2));
|
||||
global_ret = 2;
|
||||
GNUNET_SCHEDULER_shutdown ();
|
||||
return GNUNET_NO;
|
||||
}
|
||||
break;
|
||||
case MHD_HTTP_NO_CONTENT:
|
||||
fprintf (stdout,
|
||||
"End of transactions list.\n");
|
||||
"No transactions.\n");
|
||||
global_ret = 0;
|
||||
GNUNET_SCHEDULER_shutdown ();
|
||||
return GNUNET_NO;
|
||||
}
|
||||
break;
|
||||
case MHD_HTTP_OK:
|
||||
for (unsigned int i = 0; i<reply->details.success.details_length; i++)
|
||||
{
|
||||
const struct TALER_BANK_CreditDetails *cd =
|
||||
&reply->details.success.details[i];
|
||||
|
||||
/* If credit/debit accounts were specified, use as a filter */
|
||||
if ( (NULL != credit_account) &&
|
||||
(0 != strcasecmp (credit_account,
|
||||
details->credit_account_uri) ) )
|
||||
return GNUNET_OK;
|
||||
cd->credit_account_uri) ) )
|
||||
continue;
|
||||
if ( (NULL != debit_account) &&
|
||||
(0 != strcasecmp (debit_account,
|
||||
details->debit_account_uri) ) )
|
||||
return GNUNET_OK;
|
||||
|
||||
cd->debit_account_uri) ) )
|
||||
continue;
|
||||
fprintf (stdout,
|
||||
"%llu: %s->%s (%s) over %s at %s\n",
|
||||
(unsigned long long) serial_id,
|
||||
details->debit_account_uri,
|
||||
details->credit_account_uri,
|
||||
TALER_B2S (&details->reserve_pub),
|
||||
TALER_amount2s (&details->amount),
|
||||
GNUNET_TIME_timestamp2s (details->execution_date));
|
||||
return GNUNET_OK;
|
||||
(unsigned long long) cd->serial_id,
|
||||
cd->debit_account_uri,
|
||||
cd->credit_account_uri,
|
||||
TALER_B2S (&cd->reserve_pub),
|
||||
TALER_amount2s (&cd->amount),
|
||||
GNUNET_TIME_timestamp2s (cd->execution_date));
|
||||
}
|
||||
global_ret = 0;
|
||||
break;
|
||||
default:
|
||||
fprintf (stderr,
|
||||
"Failed to obtain credit history from `%s': HTTP status %u (%s)\n",
|
||||
auth.wire_gateway_url,
|
||||
reply->http_status,
|
||||
TALER_ErrorCode_get_hint (reply->ec));
|
||||
if (NULL != reply->response)
|
||||
json_dumpf (reply->response,
|
||||
stderr,
|
||||
JSON_INDENT (2));
|
||||
global_ret = 2;
|
||||
break;
|
||||
}
|
||||
GNUNET_SCHEDULER_shutdown ();
|
||||
}
|
||||
|
||||
|
||||
@ -264,84 +253,71 @@ execute_credit_history (void)
|
||||
|
||||
|
||||
/**
|
||||
* Function with the debit debit transaction history.
|
||||
* Function with the debit transaction history.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
|
||||
* 0 if the bank's reply is bogus (fails to follow the protocol),
|
||||
* #MHD_HTTP_NO_CONTENT if there are no more results; on success the
|
||||
* last callback is always of this status (even if `abs(num_results)` were
|
||||
* already returned).
|
||||
* @param ec detailed error code
|
||||
* @param serial_id monotonically increasing counter corresponding to the transaction
|
||||
* @param details details about the wire transfer
|
||||
* @param json detailed response from the HTTPD, or NULL if reply was not in JSON
|
||||
* @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
|
||||
* @param reply response details
|
||||
*/
|
||||
static enum GNUNET_GenericReturnValue
|
||||
static void
|
||||
debit_history_cb (void *cls,
|
||||
unsigned int http_status,
|
||||
enum TALER_ErrorCode ec,
|
||||
uint64_t serial_id,
|
||||
const struct TALER_BANK_DebitDetails *details,
|
||||
const json_t *json)
|
||||
const struct TALER_BANK_DebitHistoryResponse *reply)
|
||||
{
|
||||
(void) cls;
|
||||
|
||||
dhh = NULL;
|
||||
if (MHD_HTTP_OK != http_status)
|
||||
{
|
||||
if ( (MHD_HTTP_NO_CONTENT != http_status) ||
|
||||
(TALER_EC_NONE != ec) )
|
||||
{
|
||||
if (0 == http_status)
|
||||
switch (reply->http_status)
|
||||
{
|
||||
case 0:
|
||||
fprintf (stderr,
|
||||
"Failed to obtain HTTP reply from `%s'\n",
|
||||
auth.wire_gateway_url);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Failed to obtain debit history from `%s': HTTP status %u (%s)\n",
|
||||
auth.wire_gateway_url,
|
||||
http_status,
|
||||
TALER_ErrorCode_get_hint (ec));
|
||||
}
|
||||
if (NULL != json)
|
||||
json_dumpf (json,
|
||||
stderr,
|
||||
JSON_INDENT (2));
|
||||
global_ret = 2;
|
||||
GNUNET_SCHEDULER_shutdown ();
|
||||
return GNUNET_NO;
|
||||
}
|
||||
break;
|
||||
case MHD_HTTP_NO_CONTENT:
|
||||
fprintf (stdout,
|
||||
"End of transactions list.\n");
|
||||
"No transactions.\n");
|
||||
global_ret = 0;
|
||||
GNUNET_SCHEDULER_shutdown ();
|
||||
return GNUNET_NO;
|
||||
}
|
||||
break;
|
||||
case MHD_HTTP_OK:
|
||||
for (unsigned int i = 0; i<reply->details.success.details_length; i++)
|
||||
{
|
||||
const struct TALER_BANK_DebitDetails *dd =
|
||||
&reply->details.success.details[i];
|
||||
|
||||
/* If credit/debit accounts were specified, use as a filter */
|
||||
if ( (NULL != credit_account) &&
|
||||
(0 != strcasecmp (credit_account,
|
||||
details->credit_account_uri) ) )
|
||||
return GNUNET_OK;
|
||||
dd->credit_account_uri) ) )
|
||||
continue;
|
||||
if ( (NULL != debit_account) &&
|
||||
(0 != strcasecmp (debit_account,
|
||||
details->debit_account_uri) ) )
|
||||
return GNUNET_OK;
|
||||
|
||||
dd->debit_account_uri) ) )
|
||||
continue;
|
||||
fprintf (stdout,
|
||||
"%llu: %s->%s (%s) over %s at %s\n",
|
||||
(unsigned long long) serial_id,
|
||||
details->debit_account_uri,
|
||||
details->credit_account_uri,
|
||||
TALER_B2S (&details->wtid),
|
||||
TALER_amount2s (&details->amount),
|
||||
GNUNET_TIME_timestamp2s (details->execution_date));
|
||||
return GNUNET_OK;
|
||||
(unsigned long long) dd->serial_id,
|
||||
dd->debit_account_uri,
|
||||
dd->credit_account_uri,
|
||||
TALER_B2S (&dd->wtid),
|
||||
TALER_amount2s (&dd->amount),
|
||||
GNUNET_TIME_timestamp2s (dd->execution_date));
|
||||
}
|
||||
global_ret = 0;
|
||||
break;
|
||||
default:
|
||||
fprintf (stderr,
|
||||
"Failed to obtain debit history from `%s': HTTP status %u (%s)\n",
|
||||
auth.wire_gateway_url,
|
||||
reply->http_status,
|
||||
TALER_ErrorCode_get_hint (reply->ec));
|
||||
if (NULL != reply->response)
|
||||
json_dumpf (reply->response,
|
||||
stderr,
|
||||
JSON_INDENT (2));
|
||||
global_ret = 2;
|
||||
break;
|
||||
}
|
||||
GNUNET_SCHEDULER_shutdown ();
|
||||
}
|
||||
|
||||
|
||||
|
@ -290,7 +290,6 @@ batch_deposit_transaction (void *cls,
|
||||
mhd_ret);
|
||||
if (qs < 0)
|
||||
return qs;
|
||||
|
||||
qs = TEH_plugin->do_deposit (
|
||||
TEH_plugin->cls,
|
||||
deposit,
|
||||
|
@ -74,8 +74,7 @@ reply_deposit_success (
|
||||
struct TALER_ExchangeSignatureP sig;
|
||||
enum TALER_ErrorCode ec;
|
||||
|
||||
if (TALER_EC_NONE !=
|
||||
(ec = TALER_exchange_online_deposit_confirmation_sign (
|
||||
ec = TALER_exchange_online_deposit_confirmation_sign (
|
||||
&TEH_keys_exchange_sign_,
|
||||
h_contract_terms,
|
||||
h_wire,
|
||||
@ -87,7 +86,8 @@ reply_deposit_success (
|
||||
coin_pub,
|
||||
merchant,
|
||||
&pub,
|
||||
&sig)))
|
||||
&sig);
|
||||
if (TALER_EC_NONE != ec)
|
||||
{
|
||||
return TALER_MHD_reply_with_ec (connection,
|
||||
ec,
|
||||
@ -187,8 +187,6 @@ deposit_transaction (void *cls,
|
||||
mhd_ret);
|
||||
if (qs < 0)
|
||||
return qs;
|
||||
|
||||
|
||||
/* If the deposit has a policy associated to it, persist it. This will
|
||||
* insert or update the record. */
|
||||
if (dc->has_policy)
|
||||
@ -203,8 +201,6 @@ deposit_transaction (void *cls,
|
||||
if (qs < 0)
|
||||
return qs;
|
||||
}
|
||||
|
||||
|
||||
qs = TEH_plugin->do_deposit (
|
||||
TEH_plugin->cls,
|
||||
dc->deposit,
|
||||
|
@ -606,123 +606,64 @@ do_commit (struct WireAccount *wa)
|
||||
|
||||
|
||||
/**
|
||||
* Callbacks of this type are used to serve the result of asking
|
||||
* the bank for the transaction history.
|
||||
* We got incoming transaction details from the bank. Add them
|
||||
* to the database.
|
||||
*
|
||||
* @param cls closure with the `struct WioreAccount *` we are processing
|
||||
* @param http_status HTTP status code from the server
|
||||
* @param ec taler error code
|
||||
* @param serial_id identification of the position at which we are querying
|
||||
* @param details details about the wire transfer
|
||||
* @param json raw JSON response
|
||||
* @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
|
||||
* @param wa wire account we are handling
|
||||
* @param details array of transaction details
|
||||
* @param details_length length of the @a details array
|
||||
* @return true on success
|
||||
*/
|
||||
static enum GNUNET_GenericReturnValue
|
||||
history_cb (void *cls,
|
||||
unsigned int http_status,
|
||||
enum TALER_ErrorCode ec,
|
||||
uint64_t serial_id,
|
||||
static bool
|
||||
process_reply (struct WireAccount *wa,
|
||||
const struct TALER_BANK_CreditDetails *details,
|
||||
const json_t *json)
|
||||
unsigned int details_length)
|
||||
{
|
||||
struct WireAccount *wa = cls;
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
uint64_t lroff = wa->latest_row_off;
|
||||
|
||||
(void) json;
|
||||
GNUNET_assert (NULL == task);
|
||||
if (NULL == details)
|
||||
/* check serial IDs for range constraints */
|
||||
for (unsigned int i = 0; i<details_length; i++)
|
||||
{
|
||||
wa->hh = NULL;
|
||||
if ( (! ( (MHD_HTTP_NOT_FOUND == http_status) &&
|
||||
(ignore_account_404) ) ) &&
|
||||
( (MHD_HTTP_NO_CONTENT != http_status) &&
|
||||
( (TALER_EC_NONE != ec) ||
|
||||
(MHD_HTTP_OK != http_status) ) ) )
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Error fetching history: %s (%u)\n",
|
||||
TALER_ErrorCode_get_hint (ec),
|
||||
http_status);
|
||||
if (! (exit_on_error || test_mode) )
|
||||
{
|
||||
account_completed (wa);
|
||||
return GNUNET_OK;
|
||||
}
|
||||
GNUNET_SCHEDULER_shutdown ();
|
||||
return GNUNET_OK;
|
||||
}
|
||||
if (wa->started_transaction)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"End of list. Committing progress on %s of (%llu,%llu]!\n",
|
||||
wa->job_name,
|
||||
(unsigned long long) wa->batch_start,
|
||||
(unsigned long long) wa->latest_row_off);
|
||||
do_commit (wa);
|
||||
return GNUNET_OK; /* will be ignored anyway */
|
||||
}
|
||||
/* We did not even start a transaction. */
|
||||
if ( (wa->delay) &&
|
||||
(test_mode) &&
|
||||
(NULL == wa->next) )
|
||||
{
|
||||
/* We exit on idle */
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Shutdown due to test mode!\n");
|
||||
GNUNET_SCHEDULER_shutdown ();
|
||||
return GNUNET_OK;
|
||||
}
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"No transactions in history response, moving on.\n");
|
||||
account_completed (wa);
|
||||
return GNUNET_OK; /* will be ignored anyway */
|
||||
}
|
||||
const struct TALER_BANK_CreditDetails *cd = &details[i];
|
||||
|
||||
/* We did get 'details' from the bank. Do sanity checks before inserting. */
|
||||
if (serial_id < wa->latest_row_off)
|
||||
if (cd->serial_id < lroff)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Serial ID %llu not monotonic (got %llu before). Failing!\n",
|
||||
(unsigned long long) serial_id,
|
||||
(unsigned long long) wa->latest_row_off);
|
||||
(unsigned long long) cd->serial_id,
|
||||
(unsigned long long) lroff);
|
||||
db_plugin->rollback (db_plugin->cls);
|
||||
GNUNET_SCHEDULER_shutdown ();
|
||||
wa->hh = NULL;
|
||||
return GNUNET_SYSERR;
|
||||
return false;
|
||||
}
|
||||
/* If we got 'limit' transactions back from the bank,
|
||||
we should not introduce any delay before the next
|
||||
call. */
|
||||
if (serial_id >= wa->max_row_off)
|
||||
if (cd->serial_id >= wa->max_row_off)
|
||||
{
|
||||
/* We got 'limit' transactions back from the bank, so we should not
|
||||
introduce any delay before the next call. */
|
||||
wa->delay = false;
|
||||
if (serial_id > wa->shard_end)
|
||||
}
|
||||
if (cd->serial_id > wa->shard_end)
|
||||
{
|
||||
/* we are *past* the current shard (likely because the serial_id of the
|
||||
shard_end happens to not exist in the DB). So commit and stop this
|
||||
iteration! */
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Serial ID %llu past shard end at %llu, ending iteration early!\n",
|
||||
(unsigned long long) serial_id,
|
||||
(unsigned long long) cd->serial_id,
|
||||
(unsigned long long) wa->shard_end);
|
||||
wa->latest_row_off = serial_id - 1; /* excluding serial_id! */
|
||||
wa->hh = NULL;
|
||||
if (wa->started_transaction)
|
||||
{
|
||||
GNUNET_assert (NULL == task);
|
||||
do_commit (wa);
|
||||
details_length = i;
|
||||
wa->delay = false;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
GNUNET_assert (NULL == task);
|
||||
if (check_shard_done (wa))
|
||||
account_completed (wa);
|
||||
else
|
||||
task = GNUNET_SCHEDULER_add_now (&continue_with_shard,
|
||||
wa);
|
||||
lroff = cd->serial_id;
|
||||
}
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (! wa->started_transaction)
|
||||
if (0 == details_length)
|
||||
{
|
||||
/* Server should have used 204, not 200! */
|
||||
GNUNET_break_op (0);
|
||||
return true;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
db_plugin->start_read_committed (db_plugin->cls,
|
||||
"wirewatch check for incoming wire transfers"))
|
||||
@ -732,26 +673,27 @@ history_cb (void *cls,
|
||||
global_ret = EXIT_FAILURE;
|
||||
GNUNET_SCHEDULER_shutdown ();
|
||||
wa->hh = NULL;
|
||||
return GNUNET_SYSERR;
|
||||
return false;
|
||||
}
|
||||
wa->started_transaction = true;
|
||||
}
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
||||
"Adding wire transfer over %s with (hashed) subject `%s'\n",
|
||||
TALER_amount2s (&details->amount),
|
||||
TALER_B2S (&details->reserve_pub));
|
||||
|
||||
for (unsigned int i = 0; i<details_length; i++)
|
||||
{
|
||||
const struct TALER_BANK_CreditDetails *cd = &details[i];
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
|
||||
/* FIXME #7276: Consider using Postgres multi-valued insert here,
|
||||
for up to 15x speed-up according to
|
||||
https://dba.stackexchange.com/questions/224989/multi-row-insert-vs-transactional-single-row-inserts#225006
|
||||
(Note: this may require changing both the
|
||||
plugin API as well as modifying how this function is called.) */
|
||||
qs = db_plugin->reserves_in_insert (db_plugin->cls,
|
||||
&details->reserve_pub,
|
||||
&details->amount,
|
||||
details->execution_date,
|
||||
details->debit_account_uri,
|
||||
&cd->reserve_pub,
|
||||
&cd->amount,
|
||||
cd->execution_date,
|
||||
cd->debit_account_uri,
|
||||
wa->ai->section_name,
|
||||
serial_id);
|
||||
cd->serial_id);
|
||||
switch (qs)
|
||||
{
|
||||
case GNUNET_DB_STATUS_HARD_ERROR:
|
||||
@ -760,13 +702,13 @@ history_cb (void *cls,
|
||||
wa->started_transaction = false;
|
||||
GNUNET_SCHEDULER_shutdown ();
|
||||
wa->hh = NULL;
|
||||
return GNUNET_SYSERR;
|
||||
return false;
|
||||
case GNUNET_DB_STATUS_SOFT_ERROR:
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Got DB soft error for reserves_in_insert. Rolling back.\n");
|
||||
handle_soft_error (wa);
|
||||
wa->hh = NULL;
|
||||
return GNUNET_SYSERR;
|
||||
return true;
|
||||
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
|
||||
/* Either wirewatch was freshly started after the system was
|
||||
shutdown and we're going over an incomplete shard again
|
||||
@ -777,16 +719,79 @@ history_cb (void *cls,
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Attempted to import transaction %llu (%s) twice. "
|
||||
"This should happen rarely (if not, ask for support).\n",
|
||||
(unsigned long long) serial_id,
|
||||
(unsigned long long) cd->serial_id,
|
||||
wa->job_name);
|
||||
db_plugin->rollback (db_plugin->cls);
|
||||
wa->latest_row_off = cd->serial_id;
|
||||
wa->started_transaction = false;
|
||||
/* already existed, ok, let's just continue */
|
||||
break;
|
||||
return true;
|
||||
case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
|
||||
wa->latest_row_off = cd->serial_id;
|
||||
/* normal case */
|
||||
break;
|
||||
}
|
||||
wa->latest_row_off = serial_id;
|
||||
return GNUNET_OK;
|
||||
}
|
||||
do_commit (wa);
|
||||
if (check_shard_done (wa))
|
||||
account_completed (wa);
|
||||
else
|
||||
task = GNUNET_SCHEDULER_add_now (&continue_with_shard,
|
||||
wa);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callbacks of this type are used to serve the result of asking
|
||||
* the bank for the transaction history.
|
||||
*
|
||||
* @param cls closure with the `struct WireAccount *` we are processing
|
||||
* @param reply response we got from the bank
|
||||
*/
|
||||
static void
|
||||
history_cb (void *cls,
|
||||
const struct TALER_BANK_CreditHistoryResponse *reply)
|
||||
{
|
||||
struct WireAccount *wa = cls;
|
||||
bool ok;
|
||||
|
||||
GNUNET_assert (NULL == task);
|
||||
wa->hh = NULL;
|
||||
switch (reply->http_status)
|
||||
{
|
||||
case 0:
|
||||
ok = false;
|
||||
case MHD_HTTP_OK:
|
||||
ok = process_reply (wa,
|
||||
reply->details.success.details,
|
||||
reply->details.success.details_length);
|
||||
break;
|
||||
case MHD_HTTP_NO_CONTENT:
|
||||
ok = true;
|
||||
break;
|
||||
case MHD_HTTP_NOT_FOUND:
|
||||
ok = ignore_account_404;
|
||||
break;
|
||||
default:
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (! ok)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Error fetching history: %s (%u)\n",
|
||||
TALER_ErrorCode_get_hint (reply->ec),
|
||||
reply->http_status);
|
||||
if (! (exit_on_error || test_mode) )
|
||||
{
|
||||
account_completed (wa);
|
||||
return;
|
||||
}
|
||||
GNUNET_SCHEDULER_shutdown ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -26,6 +26,8 @@
|
||||
#include "pg_helper.h"
|
||||
#include "pg_setup_wire_target.h"
|
||||
#include "pg_compute_shard.h"
|
||||
|
||||
|
||||
enum GNUNET_DB_QueryStatus
|
||||
TEH_PG_insert_deposit (void *cls,
|
||||
struct GNUNET_TIME_Timestamp exchange_timestamp,
|
||||
|
@ -260,6 +260,11 @@ struct TALER_BANK_CreditHistoryHandle;
|
||||
*/
|
||||
struct TALER_BANK_CreditDetails
|
||||
{
|
||||
/**
|
||||
* Serial ID of the wire transfer.
|
||||
*/
|
||||
uint64_t serial_id;
|
||||
|
||||
/**
|
||||
* Amount that was transferred
|
||||
*/
|
||||
@ -271,49 +276,85 @@ struct TALER_BANK_CreditDetails
|
||||
struct GNUNET_TIME_Timestamp execution_date;
|
||||
|
||||
/**
|
||||
* Reserve public key encoded in the wire
|
||||
* transfer subject.
|
||||
* Reserve public key encoded in the wire transfer subject.
|
||||
*/
|
||||
struct TALER_ReservePublicKeyP reserve_pub;
|
||||
|
||||
/**
|
||||
* payto://-URL of the source account that
|
||||
* send the funds.
|
||||
* payto://-URL of the source account that send the funds.
|
||||
*/
|
||||
const char *debit_account_uri;
|
||||
|
||||
/**
|
||||
* payto://-URL of the target account that
|
||||
* received the funds.
|
||||
* payto://-URL of the target account that received the funds.
|
||||
*/
|
||||
const char *credit_account_uri;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Response details for a history request.
|
||||
*/
|
||||
struct TALER_BANK_CreditHistoryResponse
|
||||
{
|
||||
|
||||
/**
|
||||
* HTTP status. Note that #MHD_HTTP_OK and #MHD_HTTP_NO_CONTENT are both
|
||||
* successful replies, but @e details will only contain @e success information
|
||||
* if this is set to #MHD_HTTP_OK.
|
||||
*/
|
||||
unsigned int http_status;
|
||||
|
||||
/**
|
||||
* Taler error code, #TALER_EC_NONE on success.
|
||||
*/
|
||||
enum TALER_ErrorCode ec;
|
||||
|
||||
/**
|
||||
* Full response, NULL if body was not in JSON format.
|
||||
*/
|
||||
const json_t *response;
|
||||
|
||||
/**
|
||||
* Details returned depending on the @e http_status.
|
||||
*/
|
||||
union
|
||||
{
|
||||
|
||||
/**
|
||||
* Details if status was #MHD_HTTP_OK
|
||||
*/
|
||||
struct
|
||||
{
|
||||
|
||||
/**
|
||||
* Array of transactions recevied.
|
||||
*/
|
||||
const struct TALER_BANK_CreditDetails *details;
|
||||
|
||||
/**
|
||||
* Length of the @e details array.
|
||||
*/
|
||||
unsigned int details_length;
|
||||
|
||||
} success;
|
||||
|
||||
} details;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Callbacks of this type are used to serve the result of asking
|
||||
* the bank for the credit transaction history.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
|
||||
* 0 if the bank's reply is bogus (fails to follow the protocol),
|
||||
* #MHD_HTTP_NO_CONTENT if there are no more results; on success the
|
||||
* last callback is always of this status (even if `abs(num_results)` were
|
||||
* already returned).
|
||||
* @param ec detailed error code
|
||||
* @param serial_id monotonically increasing counter corresponding to the transaction
|
||||
* @param details details about the wire transfer
|
||||
* @param json detailed response from the HTTPD, or NULL if reply was not in JSON
|
||||
* @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
|
||||
* @param reply details about the response
|
||||
*/
|
||||
typedef enum GNUNET_GenericReturnValue
|
||||
typedef void
|
||||
(*TALER_BANK_CreditHistoryCallback)(
|
||||
void *cls,
|
||||
unsigned int http_status,
|
||||
enum TALER_ErrorCode ec,
|
||||
uint64_t serial_id,
|
||||
const struct TALER_BANK_CreditDetails *details,
|
||||
const json_t *json);
|
||||
const struct TALER_BANK_CreditHistoryResponse *reply);
|
||||
|
||||
|
||||
/**
|
||||
@ -369,6 +410,11 @@ struct TALER_BANK_DebitHistoryHandle;
|
||||
*/
|
||||
struct TALER_BANK_DebitDetails
|
||||
{
|
||||
/**
|
||||
* Serial ID of the wire transfer.
|
||||
*/
|
||||
uint64_t serial_id;
|
||||
|
||||
/**
|
||||
* Amount that was transferred
|
||||
*/
|
||||
@ -390,44 +436,81 @@ struct TALER_BANK_DebitDetails
|
||||
const char *exchange_base_url;
|
||||
|
||||
/**
|
||||
* payto://-URI of the source account that
|
||||
* send the funds.
|
||||
* payto://-URI of the source account that send the funds.
|
||||
*/
|
||||
const char *debit_account_uri;
|
||||
|
||||
/**
|
||||
* payto://-URI of the target account that
|
||||
* received the funds.
|
||||
* payto://-URI of the target account that received the funds.
|
||||
*/
|
||||
const char *credit_account_uri;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Response details for a history request.
|
||||
*/
|
||||
struct TALER_BANK_DebitHistoryResponse
|
||||
{
|
||||
|
||||
/**
|
||||
* HTTP status. Note that #MHD_HTTP_OK and #MHD_HTTP_NO_CONTENT are both
|
||||
* successful replies, but @e details will only contain @e success information
|
||||
* if this is set to #MHD_HTTP_OK.
|
||||
*/
|
||||
unsigned int http_status;
|
||||
|
||||
/**
|
||||
* Taler error code, #TALER_EC_NONE on success.
|
||||
*/
|
||||
enum TALER_ErrorCode ec;
|
||||
|
||||
/**
|
||||
* Full response, NULL if body was not in JSON format.
|
||||
*/
|
||||
const json_t *response;
|
||||
|
||||
/**
|
||||
* Details returned depending on the @e http_status.
|
||||
*/
|
||||
union
|
||||
{
|
||||
|
||||
/**
|
||||
* Details if status was #MHD_HTTP_OK
|
||||
*/
|
||||
struct
|
||||
{
|
||||
|
||||
/**
|
||||
* Array of transactions initiated.
|
||||
*/
|
||||
const struct TALER_BANK_DebitDetails *details;
|
||||
|
||||
/**
|
||||
* Length of the @e details array.
|
||||
*/
|
||||
unsigned int details_length;
|
||||
|
||||
} success;
|
||||
|
||||
} details;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Callbacks of this type are used to serve the result of asking
|
||||
* the bank for the debit transaction history.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request
|
||||
* 0 if the bank's reply is bogus (fails to follow the protocol),
|
||||
* #MHD_HTTP_NO_CONTENT if there are no more results; on success the
|
||||
* last callback is always of this status (even if `abs(num_results)` were
|
||||
* already returned).
|
||||
* @param ec detailed error code
|
||||
* @param serial_id monotonically increasing counter corresponding to the transaction
|
||||
* @param details details about the wire transfer
|
||||
* @param json detailed response from the HTTPD, or NULL if reply was not in JSON
|
||||
* @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration
|
||||
* @param reply details about the response
|
||||
*/
|
||||
typedef enum GNUNET_GenericReturnValue
|
||||
typedef void
|
||||
(*TALER_BANK_DebitHistoryCallback)(
|
||||
void *cls,
|
||||
unsigned int http_status,
|
||||
enum TALER_ErrorCode ec,
|
||||
uint64_t serial_id,
|
||||
const struct TALER_BANK_DebitDetails *details,
|
||||
const json_t *json);
|
||||
const struct TALER_BANK_DebitHistoryResponse *reply);
|
||||
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user