summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2023-04-23 17:45:53 +0200
committerChristian Grothoff <christian@grothoff.org>2023-04-23 17:45:53 +0200
commit889595f986d922ffbcdcd746fdfad7f1a0e53595 (patch)
tree41571e0f04caa95c06610440d2b8c9c3698b08ed /src
parent4b7d9f5e19e9f28ec1163f3b6e5c00f0805e6221 (diff)
downloadmerchant-889595f986d922ffbcdcd746fdfad7f1a0e53595.tar.gz
merchant-889595f986d922ffbcdcd746fdfad7f1a0e53595.tar.bz2
merchant-889595f986d922ffbcdcd746fdfad7f1a0e53595.zip
make taler-merchant-wirewatch multi-instance capable
Diffstat (limited to 'src')
-rw-r--r--src/backend/taler-merchant-wirewatch.c326
-rw-r--r--src/backenddb/Makefile.am3
-rw-r--r--src/backenddb/merchant-0005.sql19
-rw-r--r--src/backenddb/pg_insert_wirewatch_progress.c53
-rw-r--r--src/backenddb/pg_insert_wirewatch_progress.h44
-rw-r--r--src/backenddb/pg_lookup_instances.c31
-rw-r--r--src/backenddb/pg_select_wirewatch_accounts.c147
-rw-r--r--src/backenddb/pg_select_wirewatch_accounts.h (renamed from src/backenddb/pg_select_wirewatch_progress.h)18
-rw-r--r--src/backenddb/pg_select_wirewatch_progress.c56
-rw-r--r--src/backenddb/pg_update_wirewatch_progress.c16
-rw-r--r--src/backenddb/pg_update_wirewatch_progress.h8
-rw-r--r--src/backenddb/plugin_merchantdb_postgres.c13
-rw-r--r--src/bank/mb_parse.c98
-rw-r--r--src/include/taler_merchant_bank_lib.h16
-rw-r--r--src/include/taler_merchantdb_plugin.h67
15 files changed, 552 insertions, 363 deletions
diff --git a/src/backend/taler-merchant-wirewatch.c b/src/backend/taler-merchant-wirewatch.c
index 7772befa..380bcc11 100644
--- a/src/backend/taler-merchant-wirewatch.c
+++ b/src/backend/taler-merchant-wirewatch.c
@@ -34,30 +34,83 @@
30)
/**
- * The merchant's configuration.
+ * Information about a watch job.
*/
-static const struct GNUNET_CONFIGURATION_Handle *cfg;
+struct Watch
+{
+ /**
+ * Kept in a DLL.
+ */
+ struct Watch *next;
+
+ /**
+ * Kept in a DLL.
+ */
+ struct Watch *prev;
+
+ /**
+ * Next task to run, if any.
+ */
+ struct GNUNET_SCHEDULER_Task *task;
+
+ /**
+ * For which instance are we importing bank transfers?
+ */
+ char *instance_id;
+
+ /**
+ * For which account are we importing bank transfers?
+ */
+ char *payto_uri;
+
+ /**
+ * Bank history request.
+ */
+ struct TALER_MERCHANT_BANK_CreditHistoryHandle *hh;
+
+ /**
+ * Start row for the bank interaction. Exclusive.
+ */
+ uint64_t start_row;
+
+ /**
+ * Artificial delay to use between API calls. Used to
+ * throttle on failures.
+ */
+ struct GNUNET_TIME_Relative delay;
+
+ /**
+ * Login data for the bank.
+ */
+ struct TALER_MERCHANT_BANK_AuthenticationData ad;
+
+ /**
+ * Set to true if we found a transaction in the last iteration.
+ */
+ bool found;
+
+};
+
/**
- * Our database plugin.
+ * Head of active watches.
*/
-static struct TALER_MERCHANTDB_Plugin *db_plugin;
+static struct Watch *w_head;
/**
- * Login data for the bank.
+ * Tail of active watches.
*/
-static struct TALER_MERCHANT_BANK_AuthenticationData ad;
+static struct Watch *w_tail;
/**
- * Next task to run, if any.
+ * The merchant's configuration.
*/
-static struct GNUNET_SCHEDULER_Task *task;
+static const struct GNUNET_CONFIGURATION_Handle *cfg;
/**
- * Configuration section with authentication data.
- * Set to default value, can be overridden via command-line.
+ * Our database plugin.
*/
-static char *section = "taler-merchant-wirewatch";
+static struct TALER_MERCHANTDB_Plugin *db_plugin;
/**
* Handle to the context for interacting with the bank.
@@ -84,64 +137,61 @@ static unsigned int batch_size = 32;
*/
static int test_mode;
-/**
- * Bank history request.
- */
-static struct TALER_MERCHANT_BANK_CreditHistoryHandle *hh;
-
-/**
- * Artificial delay to use between API calls. Used to
- * throttle on failures.
- */
-static struct GNUNET_TIME_Relative delay;
-
-/**
- * For which instance are we importing bank transfers?
- */
-static char *instance_id;
-
-/**
- * Start row for the bank interaction. Exclusive.
- */
-static uint64_t start_row;
-
-/**
- * Set to true if we need to update instead of insert on the merchant_wirewatch table.
- */
-static bool progress_update;
-
-/**
- * Set to true if we found a transaction in the last iteration.
- */
-static bool found;
-
/**
* Save progress in DB.
*/
static void
-save (void)
+save (struct Watch *w)
{
enum GNUNET_DB_QueryStatus qs;
- if (progress_update)
- qs = db_plugin->update_wirewatch_progress (db_plugin->cls,
- section,
- start_row);
- else
- qs = db_plugin->insert_wirewatch_progress (db_plugin->cls,
- section,
- start_row);
+ qs = db_plugin->update_wirewatch_progress (db_plugin->cls,
+ w->instance_id,
+ w->payto_uri,
+ w->start_row);
if (qs < 0)
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to persist wirewatch progress (%d)\n",
+ "Failed to persist wirewatch progress for %s/%s (%d)\n",
+ w->instance_id,
+ w->payto_uri,
qs);
+ GNUNET_SCHEDULER_shutdown ();
+ global_ret = EXIT_FAILURE;
}
}
/**
+ * Free resources of @a w.
+ *
+ * @param w watch job to terminate
+ */
+static void
+end_watch (struct Watch *w)
+{
+ if (NULL != w->task)
+ {
+ GNUNET_SCHEDULER_cancel (w->task);
+ w->task = NULL;
+ }
+ if (NULL != w->hh)
+ {
+ TALER_MERCHANT_BANK_credit_history_cancel (w->hh);
+ w->hh = NULL;
+ }
+ GNUNET_free (w->instance_id);
+ GNUNET_free (w->payto_uri);
+ TALER_MERCHANT_BANK_auth_free (&w->ad);
+ GNUNET_CONTAINER_DLL_remove (w_head,
+ w_tail,
+ w);
+ GNUNET_free (w);
+}
+
+
+/**
* We're being aborted with CTRL-C (or SIGTERM). Shut down.
*
* @param cls closure
@@ -152,17 +202,13 @@ shutdown_task (void *cls)
(void) cls;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Running shutdown\n");
- if (NULL != task)
+ while (NULL != w_head)
{
- GNUNET_SCHEDULER_cancel (task);
- task = NULL;
- }
- if (NULL != hh)
- {
- TALER_MERCHANT_BANK_credit_history_cancel (hh);
- hh = NULL;
+ struct Watch *w = w_head;
+
+ save (w);
+ end_watch (w);
}
- save ();
TALER_MERCHANTDB_plugin_unload (db_plugin);
db_plugin = NULL;
cfg = NULL;
@@ -176,7 +222,6 @@ shutdown_task (void *cls)
GNUNET_CURL_gnunet_rc_destroy (rc);
rc = NULL;
}
- TALER_MERCHANT_BANK_auth_free (&ad);
}
@@ -223,7 +268,7 @@ parse_subject (const char *subject,
/**
* Run next iteration.
*
- * @param cls NULL
+ * @param cls a `struct Watch *`
*/
static void
do_work (void *cls);
@@ -233,7 +278,7 @@ do_work (void *cls);
* Callbacks of this type are used to serve the result of asking
* the bank for the credit transaction history.
*
- * @param cls closure
+ * @param cls a `struct Watch *`
* @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
@@ -252,13 +297,14 @@ credit_cb (
uint64_t serial_id,
const struct TALER_MERCHANT_BANK_CreditDetails *details)
{
- (void) cls;
+ struct Watch *w = cls;
+
switch (http_status)
{
case 0:
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Invalid HTTP response from bank\n");
- delay = GNUNET_TIME_STD_BACKOFF (delay);
+ w->delay = GNUNET_TIME_STD_BACKOFF (w->delay);
break;
case MHD_HTTP_OK:
{
@@ -270,7 +316,7 @@ credit_cb (
"Received wire transfer `%s' over %s\n",
details->wire_subject,
TALER_amount2s (&details->amount));
- found = true;
+ w->found = true;
if (GNUNET_OK !=
parse_subject (details->wire_subject,
&wtid,
@@ -280,11 +326,11 @@ credit_cb (
"Skipping transfer %llu (%s): not from exchange\n",
(unsigned long long) serial_id,
details->wire_subject);
- start_row = serial_id;
+ w->start_row = serial_id;
return GNUNET_OK;
}
qs = db_plugin->insert_transfer (db_plugin->cls,
- instance_id,
+ w->instance_id,
exchange_url,
&wtid,
&details->amount,
@@ -294,7 +340,7 @@ credit_cb (
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Inserting transfer for %s into database failed. Is the credit account %s configured correctly?\n",
- instance_id,
+ w->instance_id,
details->credit_account_uri);
}
GNUNET_free (exchange_url);
@@ -305,31 +351,33 @@ credit_cb (
return GNUNET_SYSERR;
}
}
- start_row = serial_id;
+ w->start_row = serial_id;
return GNUNET_OK;
case MHD_HTTP_NO_CONTENT:
- save ();
- delay = GNUNET_TIME_UNIT_ZERO;
+ save (w);
+ w->delay = GNUNET_TIME_UNIT_ZERO;
break;
default:
- delay = GNUNET_TIME_STD_BACKOFF (delay);
+ w->delay = GNUNET_TIME_STD_BACKOFF (w->delay);
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Unexpected HTTP status code %u(%d) from bank\n",
http_status,
ec);
break;
}
- hh = NULL;
- if (test_mode && (! found))
+ w->hh = NULL;
+ if (test_mode && (! w->found))
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "No transactions found and in test mode. Shutting down!\n");
- GNUNET_SCHEDULER_shutdown ();
+ "No transactions found and in test mode. Ending watch!\n");
+ end_watch (w);
+ if (NULL == w_head)
+ GNUNET_SCHEDULER_shutdown ();
return GNUNET_OK;
}
- task = GNUNET_SCHEDULER_add_delayed (delay,
- &do_work,
- NULL);
+ w->task = GNUNET_SCHEDULER_add_delayed (w->delay,
+ &do_work,
+ w);
return GNUNET_OK;
}
@@ -337,19 +385,20 @@ credit_cb (
static void
do_work (void *cls)
{
- (void) cls;
- task = NULL;
- found = false;
- hh = TALER_MERCHANT_BANK_credit_history (ctx,
- &ad,
- start_row,
- batch_size,
- test_mode
- ? GNUNET_TIME_UNIT_ZERO
- : BANK_TIMEOUT,
- &credit_cb,
- NULL);
- if (NULL == hh)
+ struct Watch *w = cls;
+
+ w->task = NULL;
+ w->found = false;
+ w->hh = TALER_MERCHANT_BANK_credit_history (ctx,
+ &w->ad,
+ w->start_row,
+ batch_size,
+ test_mode
+ ? GNUNET_TIME_UNIT_ZERO
+ : BANK_TIMEOUT,
+ &credit_cb,
+ w);
+ if (NULL == w->hh)
{
GNUNET_break (0);
GNUNET_SCHEDULER_shutdown ();
@@ -359,6 +408,55 @@ do_work (void *cls)
/**
+ * Function called with information about a accounts
+ * the wirewatcher should monitor.
+ *
+ * @param cls closure (NULL)
+ * @param instance instance that owns the account
+ * @param payto_uri account URI
+ * @param credit_facade_url URL for the credit facade
+ * @param credit_facade_credentials account access credentials
+ * @param last_serial last transaction serial (inclusive) we have seen from this account
+ */
+static void
+start_watch (
+ void *cls,
+ const char *instance,
+ const char *payto_uri,
+ const char *credit_facade_url,
+ const json_t *credit_facade_credentials,
+ uint64_t last_serial)
+{
+ struct Watch *w = GNUNET_new (struct Watch);
+
+ (void) cls;
+ if (GNUNET_OK !=
+ TALER_MERCHANT_BANK_auth_parse_json (credit_facade_credentials,
+ credit_facade_url,
+ &w->ad))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse authentication data of `%s/%s'\n",
+ instance,
+ payto_uri);
+ GNUNET_free (w);
+ GNUNET_SCHEDULER_shutdown ();
+ global_ret = 1;
+ return;
+ }
+
+ GNUNET_CONTAINER_DLL_insert (w_head,
+ w_tail,
+ w);
+ w->instance_id = GNUNET_strdup (instance);
+ w->payto_uri = GNUNET_strdup (payto_uri);
+ w->start_row = last_serial;
+ w->task = GNUNET_SCHEDULER_add_now (&do_work,
+ w);
+}
+
+
+/**
* First task.
*
* @param cls closure, NULL
@@ -376,28 +474,6 @@ run (void *cls,
(void) cfgfile;
cfg = c;
- if (GNUNET_OK !=
- TALER_MERCHANT_BANK_auth_parse_cfg (cfg,
- section,
- &ad))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse authentication data in `%s'\n",
- section);
- return;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- section,
- "INSTANCE",
- &instance_id))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- section,
- "INSTANCE");
- TALER_MERCHANT_BANK_auth_free (&ad);
- return;
- }
GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
NULL);
ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
@@ -425,24 +501,21 @@ run (void *cls,
GNUNET_SCHEDULER_shutdown ();
return;
}
+ // FIXME: also add notification job!
{
enum GNUNET_DB_QueryStatus qs;
- qs = db_plugin->select_wirewatch_progress (db_plugin->cls,
- section,
- &start_row);
+ qs = db_plugin->select_wirewatch_accounts (db_plugin->cls,
+ &start_watch,
+ NULL);
if (qs < 0)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to obtain wirewatch progress from database\n");
+ "Failed to obtain wirewatch accounts from database\n");
GNUNET_SCHEDULER_shutdown ();
return;
}
- progress_update = (0 != qs);
}
- GNUNET_assert (NULL == task);
- task = GNUNET_SCHEDULER_add_now (&do_work,
- NULL);
}
@@ -458,11 +531,6 @@ main (int argc,
char *const *argv)
{
struct GNUNET_GETOPT_CommandLineOption options[] = {
- GNUNET_GETOPT_option_string ('s',
- "section",
- "SECTION",
- "configuration section to use for bank authentication data",
- &section),
GNUNET_GETOPT_option_flag ('t',
"test",
"run in test mode and exit when idle",
diff --git a/src/backenddb/Makefile.am b/src/backenddb/Makefile.am
index 01947a81..189b7a32 100644
--- a/src/backenddb/Makefile.am
+++ b/src/backenddb/Makefile.am
@@ -52,9 +52,8 @@ libtalermerchantdb_la_LDFLAGS = \
-no-undefined
libtaler_plugin_merchantdb_postgres_la_SOURCES = \
- pg_insert_wirewatch_progress.h pg_insert_wirewatch_progress.c \
pg_update_wirewatch_progress.h pg_update_wirewatch_progress.c \
- pg_select_wirewatch_progress.h pg_select_wirewatch_progress.c \
+ pg_select_wirewatch_accounts.h pg_select_wirewatch_accounts.c \
pg_lookup_instances.h pg_lookup_instances.c \
pg_lookup_transfers.h pg_lookup_transfers.c \
plugin_merchantdb_postgres.c pg_helper.h
diff --git a/src/backenddb/merchant-0005.sql b/src/backenddb/merchant-0005.sql
index f558cbd2..1f3b9131 100644
--- a/src/backenddb/merchant-0005.sql
+++ b/src/backenddb/merchant-0005.sql
@@ -29,15 +29,16 @@ COMMENT ON COLUMN merchant_instances.user_type
IS 'what type of user is this (individual or business)';
-CREATE TABLE IF NOT EXISTS merchant_wirewatch
- (account_section VARCHAR PRIMARY KEY
- ,last_bank_serial INT8 NOT NULL
- );
-COMMENT ON TABLE merchant_wirewatch
- IS 'table used to keep track of progress made by the taler-merchant-wirewatch tool';
-COMMENT ON COLUMN merchant_wirewatch.account_section
- IS 'Name of the configuration section that specifies the bank account details and merchant instance being tracked here';
-COMMENT ON COLUMN merchant_wirewatch.last_bank_serial
+ALTER TABLE merchant_accounts
+ ADD COLUMN credit_facade_url VARCHAR,
+ ADD COLUMN credit_facade_credentials VARCHAR,
+ ADD COLUMN last_bank_serial INT8 NOT NULL DEFAULT (0);
+
+COMMENT ON COLUMN merchant_accounts.credit_facade_url
+ IS 'Base URL of a facade where the merchant can inquire about incoming bank transactions into this account';
+COMMENT ON COLUMN merchant_accounts.credit_facade_credentials
+ IS 'JSON with credentials needed to access the credit facade';
+COMMENT ON COLUMN merchant_accounts.last_bank_serial
IS 'Serial number of the bank of the last transaction we successfully imported';
-- Complete transaction
diff --git a/src/backenddb/pg_insert_wirewatch_progress.c b/src/backenddb/pg_insert_wirewatch_progress.c
deleted file mode 100644
index f4d1b0f8..00000000
--- a/src/backenddb/pg_insert_wirewatch_progress.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 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 as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-/**
- * @file backenddb/pg_insert_wirewatch_progress.c
- * @brief Implementation of the insert_wirewatch_progress function for Postgres
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <taler/taler_error_codes.h>
-#include <taler/taler_dbevents.h>
-#include <taler/taler_pq_lib.h>
-#include "pg_insert_wirewatch_progress.h"
-#include "pg_helper.h"
-
-
-enum GNUNET_DB_QueryStatus
-TMH_PG_insert_wirewatch_progress (
- void *cls,
- const char *section,
- uint64_t last_serial)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (section),
- GNUNET_PQ_query_param_uint64 (&last_serial),
- GNUNET_PQ_query_param_end
- };
-
- PREPARE (pg,
- "insert_wirewatch_progress",
- "INSERT INTO merchant_wirewatch"
- " (account_section"
- " ,last_bank_serial)"
- " VALUES"
- " ($1,$2);");
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_non_select (pg->conn,
- "insert_wirewatch_progress",
- params);
-}
diff --git a/src/backenddb/pg_insert_wirewatch_progress.h b/src/backenddb/pg_insert_wirewatch_progress.h
deleted file mode 100644
index 4af11b9e..00000000
--- a/src/backenddb/pg_insert_wirewatch_progress.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 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 as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-/**
- * @file backenddb/pg_insert_wirewatch_progress.h
- * @brief implementation of the insert_wirewatch_progress function for Postgres
- * @author Christian Grothoff
- */
-#ifndef PG_INSERT_WIREWATCH_PROGRESS_H
-#define PG_INSERT_WIREWATCH_PROGRESS_H
-
-#include <taler/taler_util.h>
-#include <taler/taler_json_lib.h>
-#include "taler_merchantdb_plugin.h"
-
-
-/**
- * Insert information about progress made by taler-merchant-wirewatch.
- *
- * @param cls closure
- * @param section configuration section of the taler-merchant-wirewatch
- * @param last_serial last serial imported from the bank
- * @return transaction status
- */
-enum GNUNET_DB_QueryStatus
-TMH_PG_insert_wirewatch_progress (
- void *cls,
- const char *section,
- uint64_t last_serial);
-
-
-#endif
diff --git a/src/backenddb/pg_lookup_instances.c b/src/backenddb/pg_lookup_instances.c
index acf3ada3..d876ad69 100644
--- a/src/backenddb/pg_lookup_instances.c
+++ b/src/backenddb/pg_lookup_instances.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2022 Taler Systems SA
+ Copyright (C) 2022, 2023 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -98,6 +98,8 @@ prepare (struct PostgresClosure *pg)
" h_wire"
",salt"
",payto_uri"
+ ",credit_facade_url"
+ ",credit_facade_credentials"
",active"
" FROM merchant_accounts"
" WHERE merchant_serial=$1");
@@ -165,7 +167,7 @@ call_with_accounts (struct LookupInstancesContext *lic,
* Function to be called with the results of a SELECT statement
* that has returned @a num_results results about accounts.
*
- * @param cls of type `struct FindInstancesContext *`
+ * @param cls of type `struct LookupInstancesContext *`
* @param result the postgres result
* @param num_results the number of results in @a result
*/
@@ -176,8 +178,16 @@ lookup_accounts_cb (void *cls,
{
struct LookupInstancesContext *lic = cls;
char *paytos[num_results];
+ char *facade_urls[num_results];
+ json_t *credentials[num_results];
struct TALER_MERCHANTDB_AccountDetails accounts[num_results];
+ memset (facade_urls,
+ 0,
+ sizeof (facade_urls));
+ memset (credentials,
+ 0,
+ sizeof (credentials));
/* Note: this memset is completely superfluous, but gcc-11 (and gcc-12) have
a bug creating a warning without it! See #7585 */
memset (accounts,
@@ -193,6 +203,14 @@ lookup_accounts_cb (void *cls,
&account->salt),
GNUNET_PQ_result_spec_string ("payto_uri",
&paytos[i]),
+ GNUNET_PQ_result_spec_allow_null (
+ GNUNET_PQ_result_spec_string ("credit_facade_url",
+ &facade_urls[i]),
+ NULL),
+ GNUNET_PQ_result_spec_allow_null (
+ TALER_PQ_result_spec_json ("credit_facade_credentials",
+ &credentials[i]),
+ NULL),
GNUNET_PQ_result_spec_bool ("active",
&account->active),
GNUNET_PQ_result_spec_end
@@ -206,7 +224,11 @@ lookup_accounts_cb (void *cls,
GNUNET_break (0);
lic->qs = GNUNET_DB_STATUS_HARD_ERROR;
for (unsigned int j = 0; j < i; j++)
+ {
GNUNET_free (paytos[j]);
+ GNUNET_free (facade_urls[j]);
+ json_decref (credentials[j]);
+ }
return;
}
account->payto_uri = paytos[i];
@@ -215,7 +237,11 @@ lookup_accounts_cb (void *cls,
num_results,
accounts);
for (unsigned int i = 0; i < num_results; i++)
+ {
GNUNET_free (paytos[i]);
+ GNUNET_free (facade_urls[i]);
+ json_decref (credentials[i]);
+ }
}
@@ -442,4 +468,3 @@ TMH_PG_lookup_instance (void *cls,
return lic.qs;
return qs;
}
-
diff --git a/src/backenddb/pg_select_wirewatch_accounts.c b/src/backenddb/pg_select_wirewatch_accounts.c
new file mode 100644
index 00000000..f3a7e789
--- /dev/null
+++ b/src/backenddb/pg_select_wirewatch_accounts.c
@@ -0,0 +1,147 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2022, 2023 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file backenddb/pg_select_wirewatch_accounts.c
+ * @brief Implementation of the select_wirewatch_accounts function for Postgres
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <taler/taler_error_codes.h>
+#include <taler/taler_dbevents.h>
+#include <taler/taler_pq_lib.h>
+#include "pg_select_wirewatch_accounts.h"
+#include "pg_helper.h"
+
+
+/**
+ * Closure for #handle_results().
+ */
+struct Context
+{
+ /**
+ * Function to call with results.
+ */
+ TALER_MERCHANTDB_WirewatchWorkCallback cb;
+
+ /**
+ * Closure for @e cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Set to true if the parsing failed.
+ */
+ bool failure;
+};
+
+
+/**
+ * Function to be called with the results of a SELECT statement
+ * that has returned @a num_results results about accounts.
+ *
+ * @param cls of type `struct Context *`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+handle_results (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct Context *ctx = cls;
+
+ for (unsigned int i = 0; i < num_results; i++)
+ {
+ char *instance;
+ char *payto_uri;
+ char *facade_url;
+ json_t *credential;
+ uint64_t last_serial;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("instance_id",
+ &instance),
+ GNUNET_PQ_result_spec_string ("payto_uri",
+ &payto_uri),
+ GNUNET_PQ_result_spec_string ("credit_facade_url",
+ &facade_url),
+ GNUNET_PQ_result_spec_allow_null (
+ TALER_PQ_result_spec_json ("credit_facade_credentials",
+ &credential),
+ NULL),
+ GNUNET_PQ_result_spec_uint64 ("last_bank_serial",
+ &last_serial),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ ctx->failure = true;
+ return;
+ }
+ ctx->cb (ctx->cb_cls,
+ instance,
+ payto_uri,
+ facade_url,
+ credential,
+ last_serial);
+ GNUNET_PQ_cleanup_result (rs);
+ }
+}
+
+
+enum GNUNET_DB_QueryStatus
+TMH_PG_select_wirewatch_accounts (
+ void *cls,
+ TALER_MERCHANTDB_WirewatchWorkCallback cb,
+ void *cb_cls)
+{
+ struct PostgresClosure *pg = cls;
+ struct Context ctx = {
+ .cb = cb,
+ .cb_cls = cb_cls
+ };
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ PREPARE (pg,
+ "select_wirewatch_progress",
+ "SELECT"
+ " last_bank_serial"
+ ",instance_id"
+ ",payto_uri"
+ ",credit_facade_url"
+ ",credit_facade_credentials"
+ " FROM merchant_accounts"
+ " JOIN merchant_instances"
+ " USING (merchant_serial)"
+ " WHERE active"
+ " AND credit_facade_url IS NOT NULL");
+ check_connection (pg);
+ qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn,
+ "select_wirewatch_progress",
+ params,
+ &handle_results,
+ &ctx);
+ if (ctx.failure)
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ return qs;
+}
diff --git a/src/backenddb/pg_select_wirewatch_progress.h b/src/backenddb/pg_select_wirewatch_accounts.h
index e2cda0a8..cff263d3 100644
--- a/src/backenddb/pg_select_wirewatch_progress.h
+++ b/src/backenddb/pg_select_wirewatch_accounts.h
@@ -14,12 +14,12 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
- * @file backenddb/pg_select_wirewatch_progress.h
- * @brief implementation of the select_wirewatch_progress function for Postgres
+ * @file backenddb/pg_select_wirewatch_accounts.h
+ * @brief implementation of the select_wirewatch_accounts function for Postgres
* @author Christian Grothoff
*/
-#ifndef PG_SELECT_WIREWATCH_PROGRESS_H
-#define PG_SELECT_WIREWATCH_PROGRESS_H
+#ifndef PG_SELECT_WIREWATCH_ACCOUNTS_H
+#define PG_SELECT_WIREWATCH_ACCOUNTS_H
#include <taler/taler_util.h>
#include <taler/taler_json_lib.h>
@@ -30,15 +30,15 @@
* Select information about progress made by taler-merchant-wirewatch.
*
* @param cls closure
- * @param section configuration section of the taler-merchant-wirewatch
- * @param[out] last_serial set to last serial imported from the bank
+ * @param cb function to call with results
+ * @param cb_cls closure for @a cb
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
-TMH_PG_select_wirewatch_progress (
+TMH_PG_select_wirewatch_accounts (
void *cls,
- const char *section,
- uint64_t *last_serial);
+ TALER_MERCHANTDB_WirewatchWorkCallback cb,
+ void *cb_cls);
#endif
diff --git a/src/backenddb/pg_select_wirewatch_progress.c b/src/backenddb/pg_select_wirewatch_progress.c
deleted file mode 100644
index c8049e14..00000000
--- a/src/backenddb/pg_select_wirewatch_progress.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- This file is part of TALER
- Copyright (C) 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 as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-/**
- * @file backenddb/pg_select_wirewatch_progress.c
- * @brief Implementation of the select_wirewatch_progress function for Postgres
- * @author Christian Grothoff
- */
-#include "platform.h"
-#include <taler/taler_error_codes.h>
-#include <taler/taler_dbevents.h>
-#include <taler/taler_pq_lib.h>
-#include "pg_select_wirewatch_progress.h"
-#include "pg_helper.h"
-
-
-enum GNUNET_DB_QueryStatus
-TMH_PG_select_wirewatch_progress (
- void *cls,
- const char *section,
- uint64_t *last_serial)
-{
- struct PostgresClosure *pg = cls;
- struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (section),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_PQ_ResultSpec rs[] = {
- GNUNET_PQ_result_spec_uint64 ("last_bank_serial",
- last_serial),
- GNUNET_PQ_result_spec_end
- };
-
- PREPARE (pg,
- "select_wirewatch_progress",
- "SELECT last_bank_serial"
- " FROM merchant_wirewatch"
- " WHERE account_section=$1");
- check_connection (pg);
- return GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
- "select_wirewatch_progress",
- params,
- rs);
-}
diff --git a/src/backenddb/pg_update_wirewatch_progress.c b/src/backenddb/pg_update_wirewatch_progress.c
index d702c314..8ffdfe70 100644
--- a/src/backenddb/pg_update_wirewatch_progress.c
+++ b/src/backenddb/pg_update_wirewatch_progress.c
@@ -29,21 +29,27 @@
enum GNUNET_DB_QueryStatus
TMH_PG_update_wirewatch_progress (
void *cls,
- const char *section,
+ const char *instance,
+ const char *payto_uri,
uint64_t last_serial)
{
struct PostgresClosure *pg = cls;
struct GNUNET_PQ_QueryParam params[] = {
- GNUNET_PQ_query_param_string (section),
+ GNUNET_PQ_query_param_string (instance),
+ GNUNET_PQ_query_param_string (payto_uri),
GNUNET_PQ_query_param_uint64 (&last_serial),
GNUNET_PQ_query_param_end
};
PREPARE (pg,
"update_wirewatch_progress",
- "UPDATE merchant_wirewatch"
- " SET last_bank_serial=$2"
- " WHERE account_section=$1");
+ "UPDATE merchant_accounts"
+ " SET last_bank_serial=$3"
+ " WHERE payto_uri=$2"
+ " AND merchant_serial ="
+ " (SELECT merchant_serial"
+ " FROM merchant_instances"
+ " WHERE merchant_id=$1)");
check_connection (pg);
return GNUNET_PQ_eval_prepared_non_select (pg->conn,
"update_wirewatch_progress",
diff --git a/src/backenddb/pg_update_wirewatch_progress.h b/src/backenddb/pg_update_wirewatch_progress.h
index f50e8066..0e762adc 100644
--- a/src/backenddb/pg_update_wirewatch_progress.h
+++ b/src/backenddb/pg_update_wirewatch_progress.h
@@ -30,14 +30,16 @@
* Update information about progress made by taler-merchant-wirewatch.
*
* @param cls closure
- * @param section configuration section of the taler-merchant-wirewatch
- * @param last_serial last serial imported from the bank
+ * @param instance name of the instance to record progress for
+ * @param payto_uri bank account URI to record progress for
+ * @param last_serial latest serial of a transaction that was processed
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
TMH_PG_update_wirewatch_progress (
void *cls,
- const char *section,
+ const char *instance,
+ const char *payto_uri,
uint64_t last_serial);
diff --git a/src/backenddb/plugin_merchantdb_postgres.c b/src/backenddb/plugin_merchantdb_postgres.c
index 4728801f..19bd022a 100644
--- a/src/backenddb/plugin_merchantdb_postgres.c
+++ b/src/backenddb/plugin_merchantdb_postgres.c
@@ -32,9 +32,8 @@
#include "pg_helper.h"
#include "pg_lookup_instances.h"
#include "pg_lookup_transfers.h"
-#include "pg_insert_wirewatch_progress.h"
#include "pg_update_wirewatch_progress.h"
-#include "pg_select_wirewatch_progress.h"
+#include "pg_select_wirewatch_accounts.h"
/**
@@ -7395,8 +7394,8 @@ postgres_connect (void *cls)
GNUNET_PQ_make_prepare ("inactivate_account",
"UPDATE merchant_accounts SET"
" active=FALSE"
- " WHERE h_wire=$2 AND"
- " merchant_serial="
+ " WHERE h_wire=$2"
+ " AND merchant_serial="
" (SELECT merchant_serial"
" FROM merchant_instances"
" WHERE merchant_id=$1)"),
@@ -9802,12 +9801,10 @@ libtaler_plugin_merchantdb_postgres_init (void *cls)
= &TMH_PG_lookup_instance;
plugin->lookup_transfers
= &TMH_PG_lookup_transfers;
- plugin->insert_wirewatch_progress
- = &TMH_PG_insert_wirewatch_progress;
plugin->update_wirewatch_progress
= &TMH_PG_update_wirewatch_progress;
- plugin->select_wirewatch_progress
- = &TMH_PG_select_wirewatch_progress;
+ plugin->select_wirewatch_accounts
+ = &TMH_PG_select_wirewatch_accounts;
plugin->store_wire_fee_by_exchange = &postgres_store_wire_fee_by_exchange;
plugin->insert_reserve = &postgres_insert_reserve;
plugin->activate_reserve = &postgres_activate_reserve;
diff --git a/src/bank/mb_parse.c b/src/bank/mb_parse.c
index eef303f3..bb668e48 100644
--- a/src/bank/mb_parse.c
+++ b/src/bank/mb_parse.c
@@ -21,6 +21,21 @@
*/
#include "platform.h"
#include "taler_merchant_bank_lib.h"
+#include <gnunet/gnunet_json_lib.h>
+
+
+/**
+ * Names of authentication methods available.
+ */
+static const struct
+{
+ const char *m;
+ enum TALER_MERCHANT_BANK_AuthenticationMethod e;
+} methods[] = {
+ { "NONE", TALER_MERCHANT_BANK_AUTH_NONE },
+ { "BASIC", TALER_MERCHANT_BANK_AUTH_BASIC },
+ { NULL, TALER_MERCHANT_BANK_AUTH_NONE }
+};
enum GNUNET_GenericReturnValue
@@ -29,15 +44,6 @@ TALER_MERCHANT_BANK_auth_parse_cfg (
const char *section,
struct TALER_MERCHANT_BANK_AuthenticationData *auth)
{
- const struct
- {
- const char *m;
- enum TALER_MERCHANT_BANK_AuthenticationMethod e;
- } methods[] = {
- { "NONE", TALER_MERCHANT_BANK_AUTH_NONE },
- { "BASIC", TALER_MERCHANT_BANK_AUTH_BASIC },
- { NULL, TALER_MERCHANT_BANK_AUTH_NONE }
- };
char *method;
if (GNUNET_OK !=
@@ -115,6 +121,67 @@ TALER_MERCHANT_BANK_auth_parse_cfg (
}
+enum GNUNET_GenericReturnValue
+TALER_MERCHANT_BANK_auth_parse_json (
+ const json_t *cred,
+ const char *backend_url,
+ struct TALER_MERCHANT_BANK_AuthenticationData *auth)
+{
+ const char *method;
+
+ auth->wire_gateway_url = GNUNET_strdup (backend_url);
+ method = json_string_value (json_object_get (cred,
+ "type"));
+ for (unsigned int i = 0; NULL != methods[i].m; i++)
+ {
+ if (0 == strcasecmp (method,
+ methods[i].m))
+ {
+ switch (methods[i].e)
+ {
+ case TALER_MERCHANT_BANK_AUTH_NONE:
+ auth->method = TALER_MERCHANT_BANK_AUTH_NONE;
+ return GNUNET_OK;
+ case TALER_MERCHANT_BANK_AUTH_BASIC:
+ {
+ const char *username;
+ const char *password;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("username",
+ &username),
+ GNUNET_JSON_spec_string ("password",
+ &password),
+ GNUNET_JSON_spec_end ()
+ };
+ enum GNUNET_GenericReturnValue res;
+ const char *err;
+ unsigned int eline;
+
+ res = GNUNET_JSON_parse (cred,
+ spec,
+ &err,
+ &eline);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Credentials malformed: %s (%u)\n",
+ err,
+ eline);
+ GNUNET_free (auth->wire_gateway_url);
+ return GNUNET_SYSERR;
+ }
+ auth->details.basic.username = GNUNET_strdup (username);
+ auth->details.basic.password = GNUNET_strdup (password);
+ }
+ auth->method = TALER_MERCHANT_BANK_AUTH_BASIC;
+ return GNUNET_OK;
+ }
+ }
+ }
+ return GNUNET_SYSERR;
+}
+
+
void
TALER_MERCHANT_BANK_auth_free (
struct TALER_MERCHANT_BANK_AuthenticationData *auth)
@@ -124,20 +191,11 @@ TALER_MERCHANT_BANK_auth_free (
case TALER_MERCHANT_BANK_AUTH_NONE:
break;
case TALER_MERCHANT_BANK_AUTH_BASIC:
- if (NULL != auth->details.basic.username)
- {
- GNUNET_free (auth->details.basic.username);
- auth->details.basic.username = NULL;
- }
- if (NULL != auth->details.basic.password)
- {
- GNUNET_free (auth->details.basic.password);
- auth->details.basic.password = NULL;
- }
+ GNUNET_free (auth->details.basic.username);
+ GNUNET_free (auth->details.basic.password);
break;
}
GNUNET_free (auth->wire_gateway_url);
- auth->wire_gateway_url = NULL;
}
diff --git a/src/include/taler_merchant_bank_lib.h b/src/include/taler_merchant_bank_lib.h
index e295f0b3..beaaa516 100644
--- a/src/include/taler_merchant_bank_lib.h
+++ b/src/include/taler_merchant_bank_lib.h
@@ -217,6 +217,22 @@ TALER_MERCHANT_BANK_auth_parse_cfg (
/**
+ * Convenience method for parsing JSON with bank
+ * authentication data.
+ *
+ * @param cred configuration to parse
+ * @param backend_url URL of the backend (not in the JSON)
+ * @param[out] auth set to the configuration data found
+ * @return #GNUNET_OK on success
+ */
+enum GNUNET_GenericReturnValue
+TALER_MERCHANT_BANK_auth_parse_json (
+ const json_t *cred,
+ const char *backend_url,
+ struct TALER_MERCHANT_BANK_AuthenticationData *auth);
+
+
+/**
* Free memory inside of @a auth (but not @a auth itself).
* Dual to #TALER_MERCHANT_BANK_auth_parse_cfg().
*
diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h
index c1d5ae27..cffb9acd 100644
--- a/src/include/taler_merchantdb_plugin.h
+++ b/src/include/taler_merchantdb_plugin.h
@@ -99,6 +99,19 @@ struct TALER_MERCHANTDB_AccountDetails
const char *payto_uri;
/**
+ * Where can the taler-merchant-wirewatch helper
+ * download information about incoming transfers?
+ * NULL if not available.
+ */
+ const char *credit_facade_url;
+
+ /**
+ * JSON with credentials to use to access the
+ * @e credit_facade_url.
+ */
+ const json_t *credit_facade_credentials;
+
+ /**
* Is the account set for active use in new contracts?
*/
bool active;
@@ -714,6 +727,27 @@ typedef void
/**
+ * Function called with information about a accounts
+ * the wirewatcher should monitor.
+ *
+ * @param cls closure
+ * @param instance instance that owns the account
+ * @param payto_uri account URI
+ * @param credit_facade_url URL for the credit facade
+ * @param credit_facade_credentials account access credentials
+ * @param last_serial last transaction serial (inclusive) we have seen from this account
+ */
+typedef void
+(*TALER_MERCHANTDB_WirewatchWorkCallback)(
+ void *cls,
+ const char *instance,
+ const char *payto_uri,
+ const char *credit_facade_url,
+ const json_t *credit_facade_credentials,
+ uint64_t last_serial);
+
+
+/**
* Function called with information about a wire transfer.
*
* @param cls closure with a `json_t *` array to build up the response
@@ -1999,46 +2033,35 @@ struct TALER_MERCHANTDB_Plugin
char **order_id);
/**
- * Insert information about progress made by taler-merchant-wirewatch.
- *
- * @param cls closure
- * @param section configuration section of the taler-merchant-wirewatch
- * @param last_serial last serial imported from the bank
- * @return transaction status
- */
- enum GNUNET_DB_QueryStatus
- (*insert_wirewatch_progress)(
- void *cls,
- const char *section,
- uint64_t last_serial);
-
- /**
* Update information about progress made by taler-merchant-wirewatch.
*
* @param cls closure
- * @param section configuration section of the taler-merchant-wirewatch
+ * @param instance which instance does the account belong to
+ * @param payto_uri which account is this about
* @param last_serial last serial imported from the bank
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
(*update_wirewatch_progress)(
void *cls,
- const char *section,
+ const char *instance,
+ const char *payto_uri,
uint64_t last_serial);
+
/**
- * Select information about progress made by taler-merchant-wirewatch.
+ * Select information about accounts which taler-merchant-wirewatch should work on.
*
* @param cls closure
- * @param section configuration section of the taler-merchant-wirewatch
- * @param[out] last_serial set to last serial imported from the bank
+ * @param cb function to call with results
+ * @param cb_cls closure for @a cb
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
- (*select_wirewatch_progress)(
+ (*select_wirewatch_accounts)(
void *cls,
- const char *section,
- uint64_t *last_serial);
+ TALER_MERCHANTDB_WirewatchWorkCallback cb,
+ void *cb_cls);
/**