Mercurial > sci
changeset 56:308aa1086702
lib: cleanup apic
author | David Demelier <markand@malikania.fr> |
---|---|
date | Wed, 17 Aug 2022 12:51:04 +0200 |
parents | 38901547a76c |
children | bc617784ec97 |
files | libsci/apic.c |
diffstat | 1 files changed, 76 insertions(+), 69 deletions(-) [+] |
line wrap: on
line diff
--- a/libsci/apic.c Wed Aug 17 11:13:36 2022 +0200 +++ b/libsci/apic.c Wed Aug 17 12:51:04 2022 +0200 @@ -27,11 +27,22 @@ #include "apic.h" #include "util.h" -struct curlpack { +struct context { + /* Output */ + FILE *fp; + char *out; + size_t outsz; + + /* HTTP requester. */ + char url[1024]; + char keyhdr[128]; CURL *curl; CURLcode code; struct curl_slist *headers; - char keyhdr[128]; + + /* JSON stuff. */ + json_t *doc; + json_error_t error; }; struct apiconf apiconf = { @@ -47,99 +58,95 @@ return w; } -static inline char * -create_url(const char *fmt, va_list args) +static inline void +init_url(struct context *ctx, const char *fmt, va_list ap) { - static _Thread_local char ret[1024]; char page[128]; - va_list ap; - ret[0] = 0; - va_copy(ap, args); vsnprintf(page, sizeof (page), fmt, ap); - va_end(ap); - - snprintf(ret, sizeof (ret), "%s/%s", apiconf.baseurl, page); - - return ret; + snprintf(ctx->url, sizeof (ctx->url), "%s/%s", apiconf.baseurl, page); } -static inline FILE * -create_file(char **buf, size_t *bufsz) +static inline void +init_output(struct context *ctx) { - FILE *fp; - - *buf = NULL; - *bufsz = 0; - - if (!(fp = open_memstream(buf, bufsz))) - util_die("open_memstream: %s\n", strerror(errno)); - - return fp; + ctx->fp = util_open_memstream(&ctx->out, &ctx->outsz); } static void -create_curl(struct curlpack *pack, FILE *fp, const char *body, const char *url) +init_curl(struct context *ctx, const char *body) { /* Create API key string. */ - snprintf(pack->keyhdr, sizeof (pack->keyhdr), "X-Api-Key: %s", apiconf.key); + snprintf(ctx->keyhdr, sizeof (ctx->keyhdr), "X-Api-Key: %s", apiconf.key); + + ctx->headers = curl_slist_append(ctx->headers, "Content-Type: application/json"); + ctx->headers = curl_slist_append(ctx->headers, ctx->keyhdr); - pack->headers = curl_slist_append(pack->headers, "Content-Type: application/json"); - pack->headers = curl_slist_append(pack->headers, pack->keyhdr); - pack->curl = curl_easy_init(); - curl_easy_setopt(pack->curl, CURLOPT_HTTPHEADER, pack->headers); - curl_easy_setopt(pack->curl, CURLOPT_URL, url); - curl_easy_setopt(pack->curl, CURLOPT_FOLLOWLOCATION, 1L); - curl_easy_setopt(pack->curl, CURLOPT_TIMEOUT, 3L); - curl_easy_setopt(pack->curl, CURLOPT_WRITEFUNCTION, writer); - curl_easy_setopt(pack->curl, CURLOPT_WRITEDATA, fp); - curl_easy_setopt(pack->curl, CURLOPT_NOSIGNAL, 1L); + ctx->curl = curl_easy_init(); + curl_easy_setopt(ctx->curl, CURLOPT_HTTPHEADER, ctx->headers); + curl_easy_setopt(ctx->curl, CURLOPT_URL, ctx->url); + curl_easy_setopt(ctx->curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(ctx->curl, CURLOPT_TIMEOUT, 3L); + curl_easy_setopt(ctx->curl, CURLOPT_WRITEFUNCTION, writer); + curl_easy_setopt(ctx->curl, CURLOPT_WRITEDATA, ctx->fp); + curl_easy_setopt(ctx->curl, CURLOPT_NOSIGNAL, 1L); /* Assume POST request if there is a body. */ if (body) { - curl_easy_setopt(pack->curl, CURLOPT_POSTFIELDS, body); - curl_easy_setopt(pack->curl, CURLOPT_POSTFIELDSIZE, strlen(body)); + curl_easy_setopt(ctx->curl, CURLOPT_POSTFIELDS, body); + curl_easy_setopt(ctx->curl, CURLOPT_POSTFIELDSIZE, strlen(body)); } +} - pack->code = curl_easy_perform(pack->curl); +static void +invoke(struct apic *req, struct context *ctx) +{ + ctx->code = curl_easy_perform(ctx->curl); + + /* Close file descriptor to get its output. */ + fclose(ctx->fp); + ctx->fp = NULL; + + if (ctx->code != CURLE_OK) + snprintf(req->error, sizeof (req->error), "%s", curl_easy_strerror(ctx->code)); + else { + curl_easy_getinfo(ctx->curl, CURLINFO_RESPONSE_CODE, &req->status); + + if (req->status != 200) + snprintf(req->error, sizeof (req->error), "HTTP returned %ld", req->status); + else if (ctx->out[0] && !(ctx->doc = json_loads(ctx->out, 0, &ctx->error))) + snprintf(req->error, sizeof (req->error), "JSON parse error: %s", ctx->error.text); + } +} + +static void +finish(struct context *ctx) +{ + if (ctx->fp) + fclose(ctx->fp); + + free(ctx->out); + + if (ctx->curl) + curl_easy_cleanup(ctx->curl); + if (ctx->headers) + curl_slist_free_all(ctx->headers); } static json_t * perform(struct apic *req, const char *body, const char *fmt, va_list ap) { - FILE *fp; - char *response, *url; - size_t responsesz; - json_t *doc = NULL; - json_error_t error; - struct curlpack curl = {0}; + struct context ctx = {0}; - memset(req, 0, sizeof (*req)); - - url = create_url(fmt, ap); - fp = create_file(&response, &responsesz); - create_curl(&curl, fp, body, url); - - /* Perform that request now. */ - fclose(fp); + init_url(&ctx, fmt, ap); + init_output(&ctx); + init_curl(&ctx, body); - if (curl.code != CURLE_OK) - snprintf(req->error, sizeof (req->error), "%s", curl_easy_strerror(curl.code)); - else { - curl_easy_getinfo(curl.curl, CURLINFO_RESPONSE_CODE, &req->status); + /* Perform that request now to obtain data. */ + invoke(req, &ctx); + finish(&ctx); - if (req->status != 200) - snprintf(req->error, sizeof (req->error), "HTTP returned %ld", req->status); - else if (response[0] && !(doc = json_loads(response, 0, &error))) - snprintf(req->error, sizeof (req->error), "JSON parse error: %s", error.text); - } - - curl_easy_cleanup(curl.curl); - curl_slist_free_all(curl.headers); - - free(response); - - return doc; + return ctx.doc; } static json_t *