summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2024-01-14 00:43:37 +0100
committerChristian Grothoff <christian@grothoff.org>2024-01-14 00:43:37 +0100
commitaa9c8a4a51cbbd80baa7e53d114c84ac3bfdb3b3 (patch)
tree85210c78f91d9b7426f4b396b167e994c13b6036
parent74635648a0c6ab901dcbbd5a69a605a5fb29e0e6 (diff)
downloadtaler-mdb-aa9c8a4a51cbbd80baa7e53d114c84ac3bfdb3b3.tar.gz
taler-mdb-aa9c8a4a51cbbd80baa7e53d114c84ac3bfdb3b3.tar.bz2
taler-mdb-aa9c8a4a51cbbd80baa7e53d114c84ac3bfdb3b3.zip
add error display logic to main code
-rw-r--r--contrib/Makefile.am1
-rwxr-xr-xcontrib/taler-mdb-ads.sh56
-rwxr-xr-x[-rw-r--r--]contrib/taler-mdb-show.sh4
-rw-r--r--debian/etc/taler-mdb.conf3
-rw-r--r--src/.gitignore1
-rw-r--r--src/taler-mdb.c201
6 files changed, 245 insertions, 21 deletions
diff --git a/contrib/Makefile.am b/contrib/Makefile.am
index 2d6d46b..d0e7036 100644
--- a/contrib/Makefile.am
+++ b/contrib/Makefile.am
@@ -13,6 +13,7 @@ img_DATA = \
png/maintenance.png
bin_SCRIPTS = \
+ taler-mdb-ads.sh \
taler-mdb-show.sh \
taler-mdb-network-check.sh
diff --git a/contrib/taler-mdb-ads.sh b/contrib/taler-mdb-ads.sh
new file mode 100755
index 0000000..f097ba2
--- /dev/null
+++ b/contrib/taler-mdb-ads.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+
+set -eu
+
+function cleanup()
+{
+ taler-mdb-display -c "$CONF" -i
+ exit 0
+}
+
+trap cleanup EXIT
+
+CONF="$HOME/.config/taler.conf"
+
+# Parse command-line options
+while getopts ':c:h' OPTION; do
+ case "$OPTION" in
+ c)
+ CONF="$OPTARG"
+ ;;
+ h)
+ echo 'Supported options:'
+ # shellcheck disable=SC2016
+ echo ' -c $CONF -- set configuration'
+ ;;
+ ?)
+ exit_fail "Unrecognized command line option"
+ ;;
+ esac
+done
+shift $((OPTIND - 1))
+
+taler-mdb-display -c "$CONF"
+
+FBDEV=$(taler-config -c "$CONF" -s taler-mdb -o FRAMEBUFFER_DEVICE)
+
+DATA_HOME=$(taler-config -c "$CONF" -s paths -o TALER_DATA_HOME)
+
+while true
+do
+ HOUR=$(date +%H)
+ if [[ HOUR -ge 8 && HOUR -lt 22 ]]
+ then
+ taler-mdb-display -c "$CONF"
+ for AD in $(ls "${DATA_HOME}/ads/*" | shuf)
+ do
+ DELAY=$(echo "$AD" | awk -F'[-.]' '{print $(NF-1)}')
+ fbi -d "$FBDEV" -a -m "768x576-75" -vt 2 -nocomments -noverbose "$AD"
+ sleep "$DELAY"
+ done
+ taler-mdb-display -c "$CONF" -i
+ else
+ # Night time, save power!
+ sleep 600
+ fi
+done
diff --git a/contrib/taler-mdb-show.sh b/contrib/taler-mdb-show.sh
index 7073b9f..c06a089 100644..100755
--- a/contrib/taler-mdb-show.sh
+++ b/contrib/taler-mdb-show.sh
@@ -34,7 +34,9 @@ taler-mdb-display -c "$CONF"
FBDEV=$(taler-config -c "$CONF" -s taler-mdb -o FRAMEBUFFER_DEVICE)
-fbi -d "$FBDEV" -a -m "768x576-75" -vt 2 -nocomments -noverbose "$1.png"
+DATA_HOME=$(taler-config -c "$CONF" -s paths -o TALER_DATA_HOME)
+
+fbi -d "$FBDEV" -a -m "768x576-75" -vt 2 -nocomments -noverbose "${DATA_HOME}/mdb/$1.png"
while true
do
diff --git a/debian/etc/taler-mdb.conf b/debian/etc/taler-mdb.conf
index 94dfcdd..561256b 100644
--- a/debian/etc/taler-mdb.conf
+++ b/debian/etc/taler-mdb.conf
@@ -7,6 +7,9 @@ BACKEND_BASE_URL = http://backend.demo.taler.net/
# Secret key to talk to *all* instances we use.
BACKEND_AUTHORIZATION = "Bearer secret-token:sandbox"
+# Program to use to show ads.
+ADVERTISEMENT_COMMAND = taler-mdb-ads.sh -c /etc/taler-mdb.conf
+
# Message to diplay after purchase is completed,
FULFILLMENT_MSG = Enjoy your ${PRODUCT_DESCRIPTION}
diff --git a/src/.gitignore b/src/.gitignore
index f66074a..c6b6bf5 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -1,3 +1,4 @@
*.o
taler-nfc
taler-coin-acceptor
+taler-mdb-display
diff --git a/src/taler-mdb.c b/src/taler-mdb.c
index 431a505..3acd633 100644
--- a/src/taler-mdb.c
+++ b/src/taler-mdb.c
@@ -84,6 +84,12 @@ along with
GNUNET_TIME_UNIT_MINUTES, 2)
/**
+ * How long to show a transient error.
+ */
+#define ERR_DELAY GNUNET_TIME_relative_multiply ( \
+ GNUNET_TIME_UNIT_SECONDS, 30)
+
+/**
* How long could it take at most for us to notify the Taler merchant
* backend to grant a refund to a user if dispensing the product
* failed? (Very conservative value here, for vending machines brewing
@@ -634,16 +640,33 @@ static struct GNUNET_SCHEDULER_Task *keyboard_task;
static struct GNUNET_SCHEDULER_Task *cancelbutton_task;
/**
+ * Task to stop showing transient errors.
+ */
+static struct GNUNET_SCHEDULER_Task *err_stop_task;
+
+/**
* Handle to the process showing messages/advertisements
* while we are inactive.
*/
static struct GNUNET_OS_Process *adv_child;
/**
- * Name of the process to run when advertising is enabled.
+ * Handle to the process showing error messages
+ * while we have one.
+ */
+static struct GNUNET_OS_Process *err_child;
+
+/**
+ * Command to run when advertising is enabled.
+ * Can be NULL.
+ */
+static char *adv_process_command;
+
+/**
+ * Command to run when advertising is enabled.
* Can be NULL.
*/
-static char *adv_process_filename;
+static char *err_process_command;
/**
* Taler Backend url read from configuration file
@@ -817,6 +840,135 @@ static struct Display qrDisplay;
/**
+ * Start process using the @a command command-line.
+ *
+ * @param command command to run
+ * @param ... extra arguments to pass
+ * @return process handle, NULL on failure
+ */
+static struct GNUNET_OS_Process *
+start_command (const char *command,
+ ...)
+{
+ char **argv = NULL;
+ unsigned int argc = 0;
+ char *cpy = GNUNET_strdup (adv_process_command);
+ struct GNUNET_OS_Process *ret;
+ va_list ap;
+ const char *arg;
+
+ for (const char *tok = strtok (cpy, " ");
+ NULL != tok;
+ tok = strtok (NULL, " "))
+ {
+ GNUNET_array_append (argv,
+ argc,
+ GNUNET_strdup (tok));
+ }
+ va_start (ap,
+ command);
+ while (NULL != (arg = va_arg (ap,
+ const char *)))
+ {
+ GNUNET_array_append (argv,
+ argc,
+ GNUNET_strdup (arg));
+ }
+ va_end (ap);
+ GNUNET_array_append (argv,
+ argc,
+ NULL);
+ ret = GNUNET_OS_start_process_vap (GNUNET_OS_INHERIT_STD_NONE,
+ NULL,
+ NULL,
+ NULL,
+ argv[0],
+ argv);
+ for (unsigned int i = 0; i<argc; i++)
+ GNUNET_free (argv[i]);
+ GNUNET_array_grow (argv,
+ argc,
+ 0);
+ GNUNET_free (cpy);
+ return ret;
+}
+
+
+/**
+ * Stop the process showing an error.
+ */
+static void
+hide_error (void)
+{
+ if (NULL == err_child)
+ return;
+ if (NULL != err_stop_task)
+ {
+ GNUNET_SCHEDULER_cancel (err_stop_task);
+ err_stop_task = NULL;
+ }
+ GNUNET_break (0 ==
+ GNUNET_OS_process_kill (err_child,
+ SIGTERM));
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_OS_process_wait (err_child));
+ GNUNET_OS_process_destroy (err_child);
+ err_child = NULL;
+}
+
+
+/**
+ * Show an error using the respective error process
+ * command.
+ *
+ * @param err_type type of the error to pass to the command
+ */
+static void
+show_error (const char *err_type)
+{
+ hide_error (); /* just to be sure */
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Showing error `%s'\n",
+ err_type);
+ if (NULL == err_process_command)
+ {
+ return;
+ }
+ err_child = start_command (err_process_command,
+ err_type,
+ NULL);
+}
+
+
+/**
+ * Task to stop the process showing an error.
+ *
+ * @param cls NULL
+ */
+static void
+do_hide_error (void *cls)
+{
+ err_stop_task = NULL;
+ hide_error ();
+}
+
+
+/**
+ * Briefly show a temporary error.
+ *
+ * @param err_type error to show
+ */
+static void
+temporary_error (const char *err_type)
+{
+ show_error (err_type);
+ err_stop_task = GNUNET_SCHEDULER_add_delayed (ERR_DELAY,
+ &do_hide_error,
+ NULL);
+}
+
+
+/**
* Stop the advertising process.
*/
static void
@@ -841,15 +993,10 @@ static void
start_advertising (void)
{
stop_advertising (); /* just to be sure */
- if (NULL == adv_process_filename)
+ if (NULL == adv_process_command)
return;
- adv_child = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_NONE,
- NULL,
- NULL,
- NULL,
- adv_process_filename,
- adv_process_filename,
- NULL);
+ adv_child = start_command (adv_process_command,
+ NULL);
}
@@ -874,6 +1021,7 @@ show_qrcode (const char *uri)
const char *dddash;
stop_advertising ();
+ hide_error ();
if (0 > qrDisplay.devicefd)
return; /* no display, no dice */
/* find the fourth '/' in the payto://pay/hostname/-uri */
@@ -1149,6 +1297,7 @@ mdb_shutdown (void)
GNUNET_SCHEDULER_cancel (mdb.wtask);
mdb.wtask = NULL;
}
+ hide_error ();
stop_advertising ();
if (disable_mdb)
return;
@@ -1385,8 +1534,12 @@ wallet_select_aid (void *cls)
pa->task = NULL;
/* append the taler wallet aid to the select file command */
- memcpy (message, select_file, sizeof (select_file));
- memcpy (&message[sizeof (select_file)], taler_aid, sizeof (taler_aid));
+ memcpy (message,
+ select_file,
+ sizeof (select_file));
+ memcpy (&message[sizeof (select_file)],
+ taler_aid,
+ sizeof (taler_aid));
/* send the select file command via nfc */
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -1567,6 +1720,7 @@ check_payment_cb (void *cls,
hr->http_status,
(int) hr->ec);
mdb.cmd = &cmd_reader_display_backend_not_reachable;
+ temporary_error ("backend-unexpected-failure");
run_mdb_event_loop ();
cleanup_payment (pa);
GNUNET_assert (payment_activity == pa);
@@ -1575,9 +1729,8 @@ check_payment_cb (void *cls,
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Backend request to /check-payment returned: %u/%d\n",
- hr->http_status,
- (int) osr->details.ok.status);
+ "Backend request to /check-payment returned: %u\n",
+ hr->http_status);
if ( (MHD_HTTP_OK == hr->http_status) &&
(TALER_MERCHANT_OSC_PAID == osr->details.ok.status) )
{
@@ -1674,6 +1827,7 @@ proposal_cb (void *cls,
json_dumpf (por->hr.reply,
stderr,
0);
+ temporary_error ("backend-temporary-failure");
mdb.cmd = &cmd_reader_display_backend_not_reachable;
run_mdb_event_loop ();
cleanup_payment (pa);
@@ -1832,6 +1986,7 @@ launch_payment (struct Product *product)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"TALER_MERCHANT_order_put failed (out of memory?)\n");
+ temporary_error ("internal-failure");
cleanup_payment (pa);
return NULL;
}
@@ -2429,8 +2584,8 @@ handle_command (const char *hex,
"Received command with wrong checksum `%.*s'\n",
(int) hex_len,
hex);
+ temporary_error ("err-num-read-fail");
break;
-
}
unsigned int product;
@@ -2466,6 +2621,7 @@ handle_command (const char *hex,
"Product %s sold out, denying vend\n",
products[i].description);
mdb.cmd = &cmd_reader_display_sold_out;
+ temporary_error ("err-sold-out");
return;
}
payment_activity = launch_payment (&products[i]);
@@ -2476,6 +2632,7 @@ handle_command (const char *hex,
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Unknown product %u selected on MDB, denying vend\n",
product);
+ temporary_error ("unknown-product");
mdb.cmd = &cmd_deny_vend;
break;
}
@@ -3203,10 +3360,14 @@ run (void *cls,
global_ret = EXIT_FAILURE;
return;
}
- (void) GNUNET_CONFIGURATION_get_value_filename (cfg,
- "taler-mdb",
- "ADVERTISEMENT_BINARY",
- &adv_process_filename);
+ (void) GNUNET_CONFIGURATION_get_value_string (cfg,
+ "taler-mdb",
+ "ADVERTISEMENT_COMMAND",
+ &adv_process_command);
+ (void) GNUNET_CONFIGURATION_get_value_string (cfg,
+ "taler-mdb",
+ "FAIL_COMMAND",
+ &err_process_command);
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (cfg,
"taler-mdb",