From 821b2af393c41d6a22da17b529271fec375b31cc Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Fri, 28 Feb 2020 14:19:11 +0100 Subject: add multi-instance and preview support --- src/main.c | 169 +++++++++++++++++++++++++++++++++++++++++++++++++++------- src/qr-show.c | 12 +++-- 2 files changed, 159 insertions(+), 22 deletions(-) diff --git a/src/main.c b/src/main.c index 0b2da81..8247d95 100644 --- a/src/main.c +++ b/src/main.c @@ -291,6 +291,20 @@ struct Product */ char *description; + /** + * Which instance should be used for billing? + * Full URL, replaces the default base URL + * for orders involving this product. NULL if + * we should use the base_url. + */ + char *instance; + + /** + * Preview image to embed in the contract, NULL for + * no preview. Already base64 encoded. + */ + char *preview; + /** * Number of the product in the vending machine */ @@ -883,7 +897,9 @@ show_qrcode (const char *uri) /* turn on backlight if supported */ if (0 < qrDisplay.backlightfd) - (void) write (qrDisplay.backlightfd, &backlight_on, 1); + (void) ! write (qrDisplay.backlightfd, + &backlight_on, + 1); } @@ -932,7 +948,9 @@ cleanup_payment (struct PaymentActivity *pa) qrDisplay.var_info.xres * qrDisplay.var_info.yres * sizeof (uint16_t)); if (0 < qrDisplay.backlightfd) - (void) write (qrDisplay.backlightfd, &backlight_off, 1); + (void) ! write (qrDisplay.backlightfd, + &backlight_off, + 1); #endif GNUNET_free (pa->taler_pay_uri); } @@ -1069,14 +1087,20 @@ shutdown_task (void *cls) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to open /gpio/unexport for cancel button\n"); } - (void) write (cancel_button.cancelbuttonfd, "23", 2); + (void) ! write (cancel_button.cancelbuttonfd, + "23", + 2); close (cancel_button.cancelbuttonfd); } /* free the allocated productes read from config file */ if (NULL != products) { for (unsigned int i = 0; i < products_length; i++) + { GNUNET_free (products[i].description); + GNUNET_free_non_null (products[i].instance); + GNUNET_free_non_null (products[i].preview); + } GNUNET_array_grow (products, products_length, 0); @@ -1431,11 +1455,14 @@ static void check_payment_again (void *cls) { struct PaymentActivity *pa = cls; + struct Product *p = pa->product; pa->delay_pay_task = NULL; GNUNET_assert (NULL == pa->cpo); pa->cpo = TALER_MERCHANT_check_payment (ctx, - backend_base_url, + (NULL == p->instance) + ? backend_base_url + : p->instance, pa->order_id, NULL /* snack machine, no Web crap */, BACKEND_POLL_TIMEOUT, @@ -1526,13 +1553,31 @@ launch_payment (struct Product *product) uuid_s); GNUNET_free (uuid_s); /* create the json object for the order request */ - orderReq = json_pack ("{ s:s, s:o, s:s, s:o }", - "summary", product->description, - "amount", TALER_JSON_from_amount (&product->price), - "fulfillment_url", fulflmntUrl - ,"auto_refund", GNUNET_JSON_from_time_rel ( - MAX_REFUND_DELAY) - ); + if (NULL != product->preview) + { + orderReq = json_pack ("{ s:{s:s}, s:s, s:o, s:s, s:o }", + "summary", + "_", + product->description, + "preview", product->preview, + "amount", TALER_JSON_from_amount (&product->price), + "fulfillment_url", fulflmntUrl + ,"auto_refund", GNUNET_JSON_from_time_rel ( + MAX_REFUND_DELAY) + ); + } + else + { + orderReq = json_pack ("{ s:{s:s}, s:o, s:s, s:o }", + "summary", + "_", + product->description, + "amount", TALER_JSON_from_amount (&product->price), + "fulfillment_url", fulflmntUrl + ,"auto_refund", GNUNET_JSON_from_time_rel ( + MAX_REFUND_DELAY) + ); + } GNUNET_free (fulflmntUrl); if (NULL == orderReq) { @@ -1543,13 +1588,17 @@ launch_payment (struct Product *product) GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Creating order for `%s' at backend `%s'\n", product->description, - backend_base_url); + (NULL == product->instance) + ? backend_base_url + : product->instance); pa = GNUNET_new (struct PaymentActivity); pa->product = product; pa->amount = product->price; /* put the order on the merchant's backend */ pa->po = TALER_MERCHANT_order_put (ctx, - backend_base_url, + (NULL == product->instance) + ? backend_base_url + : product->instance, orderReq, &proposal_cb, pa); @@ -1640,7 +1689,9 @@ vend_failure () mdb.session_running = GNUNET_NO; r = GNUNET_new (struct Refund); r->rio = TALER_MERCHANT_refund_increase (ctx, - backend_base_url, + (NULL == p->instance) + ? backend_base_url + : p->instance, payment_activity->order_id, &payment_activity->amount, "failed to dispense product", @@ -1780,9 +1831,19 @@ cancel_button_pressed (void *cls) { (void) cls; char value; + cancelbutton_task = NULL; + if (1 != + read (cancel_button.cancelbuttonfd, + &value, + 1)) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "read"); + start_read_cancel_button (); + return; + } - read (cancel_button.cancelbuttonfd, &value, 1); lseek (cancel_button.cancelbuttonfd, 0, SEEK_SET); /* This point should only be reached when a order is pending, because * the scheduler read file gets added in the function "launch_payment". @@ -1970,7 +2031,7 @@ write_mdb_command (void *cls) chkSum += mdb.txBuffer[idx] = mdb.cmd->cmd.bin[idx]; for (size_t idx = 0; idx < mdb.cmd->data.bin_size; idx++) chkSum += mdb.txBuffer[idx + mdb.cmd->cmd.bin_size] = - mdb.cmd->data.bin[idx]; + mdb.cmd->data.bin[idx]; mdb.txBuffer[mdb.cmd->cmd.bin_size + mdb.cmd->data.bin_size] = (uint8_t) (chkSum & 0xFF); } @@ -2525,6 +2586,7 @@ read_products (void *cls, { struct Product tmpProduct; char *tmpKey; + char *thumbnail_fn; /* if the current section is not a product skip it */ if (0 != strncmp (section, @@ -2591,6 +2653,73 @@ read_products (void *cls, /* no key */ tmpProduct.key = '\0'; } + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cls, + section, + "instance", + &tmpProduct.instance)) + tmpProduct.instance = NULL; + tmpProduct.preview = NULL; + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cls, + section, + "thumbnail", + &thumbnail_fn)) + { + struct GNUNET_DISK_FileHandle *fh; + + fh = GNUNET_DISK_file_open (thumbnail_fn, + GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_NONE); + if (NULL == fh) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Could not open thumbnail `%s'\n", + thumbnail_fn); + } + else + { + off_t flen; + + if (GNUNET_OK != + GNUNET_DISK_file_handle_size (fh, + &flen)) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, + "stat", + thumbnail_fn); + } + else + { + void *thumb; + size_t len; + ssize_t ret; + + len = (size_t) flen; + thumb = GNUNET_malloc (len); + ret = GNUNET_DISK_file_read (fh, + thumb, + len); + if ( (ret < 0) || + (len != ((size_t) ret)) ) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, + "read", + thumbnail_fn); + } + else + { + tmpProduct.preview + = GNUNET_STRINGS_data_to_string_alloc (thumb, + len); + } + GNUNET_free (thumb); + } + GNUNET_break (GNUNET_OK == + GNUNET_DISK_file_close (fh)); + } + } + GNUNET_free (thumbnail_fn); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cls, section, @@ -2601,6 +2730,8 @@ read_products (void *cls, section, "number"); GNUNET_free (tmpProduct.description); + GNUNET_free_non_null (tmpProduct.instance); + GNUNET_free_non_null (tmpProduct.preview); return; } /* append the temporary product to the existing products */ @@ -2851,7 +2982,7 @@ run (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to open /gpio/export for cancel button\n"); } - (void) write (cancel_button.cancelbuttonfd, "23", 2); + (void) ! write (cancel_button.cancelbuttonfd, "23", 2); close (cancel_button.cancelbuttonfd); cancel_button.cancelbuttonfd = open ("/sys/class/gpio/gpio23/direction", @@ -2861,7 +2992,7 @@ run (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Unable to open /gpio/gpio23/direction for cancel button\n"); } - (void) write (cancel_button.cancelbuttonfd, "in", 2); + (void) ! write (cancel_button.cancelbuttonfd, "in", 2); close (cancel_button.cancelbuttonfd); cancel_button.cancelbuttonfd = open ("/sys/class/gpio/gpio23/value", @@ -2948,7 +3079,7 @@ run (void *cls, backlight_off = '1'; } /* turn off the backlight */ - (void) write (qrDisplay.backlightfd, &backlight_off, 1); + (void) ! write (qrDisplay.backlightfd, &backlight_off, 1); } } else diff --git a/src/qr-show.c b/src/qr-show.c index 0010a9a..728b9ca 100644 --- a/src/qr-show.c +++ b/src/qr-show.c @@ -214,7 +214,9 @@ show_qrcode (const char *uri) QRinput_free (qri); if (0 < qrDisplay.backlightfd) - (void) write (qrDisplay.backlightfd, &backlight_on, 1); + (void) ! write (qrDisplay.backlightfd, + &backlight_on, + 1); } @@ -242,7 +244,9 @@ shutdown_task (void *cls) qrDisplay.var_info.xres * qrDisplay.var_info.yres * sizeof (uint16_t)); if (0 < qrDisplay.backlightfd) - (void) write (qrDisplay.backlightfd, &backlight_off, 1); + (void) ! write (qrDisplay.backlightfd, + &backlight_off, + 1); if (NULL != qrDisplay.memory) { /* free the display data */ @@ -382,7 +386,9 @@ run (void *cls, backlight_on = '0'; backlight_off = '1'; } - (void) write (qrDisplay.backlightfd, &backlight_off, 1); + (void) ! write (qrDisplay.backlightfd, + &backlight_off, + 1); } } else -- cgit v1.2.3