diff options
Diffstat (limited to 'src/backend/taler-merchant-webhook.c')
-rw-r--r-- | src/backend/taler-merchant-webhook.c | 181 |
1 files changed, 162 insertions, 19 deletions
diff --git a/src/backend/taler-merchant-webhook.c b/src/backend/taler-merchant-webhook.c index 7df1ad8e..42600a5a 100644 --- a/src/backend/taler-merchant-webhook.c +++ b/src/backend/taler-merchant-webhook.c @@ -28,6 +28,21 @@ #include "taler_json_lib.h" +struct Work_response +{ + struct Work_response *next; + struct Work_response *prev; + struct GNUNET_CURL_Job *job; + uint64_t webhook_serial; + char *body; + struct curl_slist *job_headers; +}; + + +static struct Work_response *w_head; + +static struct Work_response *w_tail; + /** * The exchange's configuration. */ @@ -72,6 +87,8 @@ static int test_mode; static void shutdown_task (void *cls) { + struct Work_response *w; + (void) cls; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Running shutdown\n"); @@ -80,6 +97,16 @@ shutdown_task (void *cls) GNUNET_SCHEDULER_cancel (task); task = NULL; } + while (NULL != (w = w_head)) + { + GNUNET_CONTAINER_DLL_remove (w_head, + w_tail, + w); + GNUNET_CURL_job_cancel (w->job); + curl_slist_free (w->job_headers); + GNUNET_free (w->body); + GNUNET_free (w); + } db_plugin->rollback (db_plugin->cls); /* just in case */ TALER_MERCHANTDB_plugin_unload (db_plugin); db_plugin = NULL; @@ -105,15 +132,61 @@ shutdown_task (void *cls) static void select_work (void *cls); +//http request and delete or update in function of the http. And do select work again -void -handle_webhook_response (void *cls) +/** + * Function to call upon completion of a raw job. + * + * @param cls closure + * @param response_code HTTP response code from server, 0 on hard error + * @param body http body of the response + * @param body_size number of bytes in @a body + */ +static void +handle_webhook_response (void *cls, + long response_code, + const void *body, + size_t body_size) { - cls->webhook_serial; - // update DB status on the webhook! (delete or update webhook) + struct Work_response *w = cls; + struct GNUNET_TIME_Relative next_attempt; - task = GNUNET_SCHEDULER_add_now (&select_work, - NULL); + (void) body; + (void) body_size; + job = NULL; + // update DB status on the webhook! (delete or update webhook) + if (2 == response_code / 100) /* any 2xx http status code is OK! */ + { + db_plugib->delete_pending_webhook (db_plugin->cls, + w->webhook_serial); + } + else + { + switch (response_code) + { + case MHD_HTTP_BAD_REQUEST: + next_attempt = GNUNET_TIME_UNIT_FOREVER_REL; // never try again + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + next_attempt = GNUNET_TIME_UNIT_MINUTES; + break; + default: + next_attempt = GNUNET_TIME_UNIT_HOURS; + break; + } + db_plugin->update_pending_webhook (db_plugin->cls, + w->webhook_serial, + GNUNET_TIME_relative_to_absolute (next_attempt)); + } + GNUNET_CONTAINER_DLL_remove (w_head, + w_tail, + w); + GNUNET_free (w->body); + curl_slist_free_all (w->job_headers); + GNUNET_free (w); + if (NULL == w_head) + task = GNUNET_SCHEDULER_add_now (&select_work, + NULL); } @@ -129,35 +202,93 @@ handle_webhook_response (void *cls) * @param header of the webhook * @param body of the webhook */ +// initialisation curl, and do the job static void cb (void *cls, uint64_t webhook_serial, - struct GNUNET_TIME_Absolute - next_attempt, + struct GNUNET_TIME_Absolute next_attempt, uint32_t retries, const char *url, const char *http_method, const char *header, const char *body) { + struct Work_response *w = GNUNET_new (struct Work_response); CURL *eh; + struct curl_slist *job_headers = NULL; + GNUNET_CONTAINER_DLL_insert (w_head, + w_tail, + w); + w->webhook_serial = webhook_serial; eh = curl_easy_new (); - + GNUNET_assert (NULL != eh); GNUNET_assert (CURLE_OK == curl_easy_setopt (eh, CURLOPT_CUSTOMREQUEST, - method)); + http_method)); GNUNET_assert (CURLE_OK == curl_easy_setopt (eh, CURLOPT_URL, url)); - // run the job - job = GNUNET_CURL_job_add2 (ctx, - eh, - ofh->post_ctx.headers, - &handle_webhook_response, - NULL /* pass struct with webhook ID for update!*/); + // FIXME: convert header to job_headers! + + w->body = GNUNET_strdup (body); + GNUNET_assert (CURLE_OK == + curl_easy_setopt (eh, + CURLOPT_POSTFIELDS, + w->body)); + w->job_headers = job_headers; + w->job = GNUNET_CURL_job_add_raw (ctx, + eh, + job_headers, + &handle_webhook_response, + w); + if (NULL == w->job) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to start the curl job for webhook #%llu\n", + (unsigned long long) webhook_serial); + curl_slist_free_all (w->job_headers); + GNUNET_free (w->body); + GNUNET_CONTAINER_DLL_remove (w_head, + w_tail, + w); + GNUNET_free (w); + GNUNET_SCHEDULER_shutdown (); + return; + } +} + + +/** + * Typically called by `lookup_pending_webhooks`. + * + * @param cls a `json_t *` JSON array to build + * @param webhook_serial reference to the configured webhook template. + * @param next_attempt is the time we should make the next request to the webhook. + * @param retries how often have we tried this request to the webhook. + * @param url to make request to + * @param http_method use for the webhook + * @param header of the webhook + * @param body of the webhook + */ +// initialisation curl, and do the job +static void +cb_future (void *cls, + uint64_t webhook_serial, + struct GNUNET_TIME_Absolute next_attempt, + uint32_t retries, + const char *url, + const char *http_method, + const char *header, + const char *body) +{ + (void) webhook_serial; + + task = GNUNET_SCHEDULER_add_at (next_attempt, + &select_work, + NULL); } @@ -166,6 +297,7 @@ cb (void *cls, * * @param cls NULL */ +// do the action of the pending webhook static void select_work (void *cls) { @@ -188,12 +320,23 @@ select_work (void *cls) switch (qs) { // FIXME: handle qs - case 1: - // wait for completion, then select more work. case 0: - db_plugin->lookup_future_webhook (...); + qs = db_plugin->lookup_future_webhook (db_plugin->cls, + &cb_future, + NULL); + switch (qs) { + // ... + } + return; case -1 / -2: // shutdown. + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed!\n"); + global_ret = EXIT_FAILURE; + GNUNET_SCHEDULER_shutdown (); + return; + default: + return; // wait for completion, then select more work. } } |