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 *