summaryrefslogtreecommitdiff
path: root/src/backend/taler-merchant-wirewatch.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/taler-merchant-wirewatch.c')
-rw-r--r--src/backend/taler-merchant-wirewatch.c326
1 files changed, 197 insertions, 129 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",