From 820e76108bc85051d64431495d70f27379756cc8 Mon Sep 17 00:00:00 2001 From: Julien Dessaux Date: Thu, 12 Sep 2019 18:05:01 +0200 Subject: Added liveapi support, and the maar tool (mark all as read) --- liveapi/liveapi.c | 224 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 224 insertions(+) create mode 100644 liveapi/liveapi.c (limited to 'liveapi/liveapi.c') diff --git a/liveapi/liveapi.c b/liveapi/liveapi.c new file mode 100644 index 0000000..b0520ea --- /dev/null +++ b/liveapi/liveapi.c @@ -0,0 +1,224 @@ +#include +#include +#include +#include +#include + +#include +#include "libuwsc/uwsc.h" + +#include "common/config.h" +#include "common/util.h" +#include "liveapi.h" +#include "messages.h" +#include "stdin.h" + +static struct uwsc_client * webclient; +static struct ev_loop *loop = NULL; +static char stepping = 1; + +static const char * _authToken; + +struct result { + int id; + cJSON* json; + UT_hash_handle hh; +}; + +static struct result * results = NULL; + +void liveapi_activate_stdin(liveapi_stdin_cb * cb) +{ + liveapi_activate_stdin_with_callback(webclient, cb); +} + +static void liveapi_send(const char* msg) +{ +#ifdef DEBUG_WEBSOCKETS + printf("==>:%s\n", msg); +#endif + webclient->send_ex(webclient, UWSC_OP_TEXT, 1, strlen(msg), msg); + // TODO handle errors +} + +void liveapi_send_json(size_t id, cJSON* json) +{ + char * msg = cJSON_Print(json); + if (id > 0) { + struct result * result = malloc(sizeof(struct result)); + result->id = id; + result->json = json; + HASH_ADD_INT(results, id, result); + } + liveapi_send(msg); + if (id == 0) + cJSON_Delete(json); + free(msg); +} + +static void uwsc_onopen(struct uwsc_client *cl UNUSED) +{ + uwsc_log_info("onopen\n"); +} + +static void uwsc_onmessage(struct uwsc_client *cl, + void *data, size_t len, bool binary) +{ +#ifdef DEBUG_WEBSOCKETS + printf("<==:"); +#endif + + if (binary) { + fprintf(stderr, "Websocket binary messages are not unsupported\n"); +#ifdef DEBUG_WEBSOCKETS + size_t i; + uint8_t *p = data; + + for (i = 0; i < len; i++) { + printf("%02hhX ", p[i]); + if (i % 16 == 0 && i > 0) + puts(""); + } + puts(""); +#endif + } else { +#ifdef DEBUG_WEBSOCKETS + printf("%.*s\n", (int)len, (char *)data); +#endif + char* buffer = malloc (len + 1); + strncpy(buffer, data, len); + buffer[len] = 0; + cJSON* json = cJSON_Parse(buffer); + if (json == NULL) { + const char *error_ptr = cJSON_GetErrorPtr(); + if (error_ptr != NULL) + fprintf(stderr, "Json parsing error reading websocket message: %s\n", error_ptr); + fprintf(stderr, "Error while parsing websocket message, couldn't parse json output :\n%s\n", buffer); + goto onmessage_json_cleanup; + } + + + const cJSON* server_id = cJSON_GetObjectItemCaseSensitive(json, "server_id"); + if (cJSON_IsString(server_id) && server_id->valuestring != NULL) { + liveapi_connect(); + goto onmessage_json_cleanup; + } + const cJSON* msg = cJSON_GetObjectItemCaseSensitive(json, "msg"); + if (cJSON_IsString(msg) && msg->valuestring != NULL) { + if (strcmp(msg->valuestring, "ping") == 0) { + liveapi_send("{ \"msg\": \"pong\" }"); + } else if (strcmp(msg->valuestring, "connected") == 0) { + liveapi_login(_authToken); + ev_break(cl->loop, EVBREAK_ALL); + } else if (strcmp(msg->valuestring, "result") == 0) { + const cJSON* jid = cJSON_GetObjectItemCaseSensitive(json, "id"); + if (!cJSON_IsString(jid) || jid->valuestring == NULL) { + fprintf(stderr, "Invalid websocket result : %s\n", buffer); + goto onmessage_json_cleanup; + } + size_t id = (size_t) strtoll(jid->valuestring, NULL, 10); + struct result * result = NULL; + HASH_FIND_INT(results, &id, result); + if (result == NULL) { + fprintf(stderr, "Got a websocket result message that doesn't match any method we sent : %s\n", buffer); + goto onmessage_json_cleanup; + } + cJSON_Delete(result->json); + HASH_DEL(results, result); + free(result); + // if we were stepping and got no more results we break out of the loop + if (stepping == 1 && HASH_COUNT(results) == 0) + ev_break(cl->loop, EVBREAK_ALL); + } else { + fprintf(stderr, "Unhandled websocket message : %s\n", msg->valuestring); + } + } else { + fprintf(stderr, "Unhandled websocket without msg : %s\n", buffer); + } +onmessage_json_cleanup: + cJSON_Delete(json); + free(buffer); + } +} + +static void uwsc_onerror(struct uwsc_client *cl, int err, const char *msg) +{ + uwsc_log_err("onerror:%d: %s\n", err, msg); + ev_break(cl->loop, EVBREAK_ALL); +} + +static void uwsc_onclose(struct uwsc_client *cl, int code, const char *reason) +{ + uwsc_log_err("onclose:%d: %s\n", code, reason); + ev_break(cl->loop, EVBREAK_ALL); +} + +static void signal_cb(struct ev_loop *loop, ev_signal *w, int revents) +{ + if (w->signum == SIGINT) { + (void) loop; + //ev_break(loop, EVBREAK_ALL); + uwsc_log_info("Normal quit\n"); + webclient->send_close(webclient, 0, "got signal"); + } + (void) revents; +} + +char liveapi_init(const char * authToken) +{ + _authToken = authToken; + + const char *url = config_get_wss_url(); + loop = EV_DEFAULT; + struct ev_signal signal_watcher; + int ping_interval = 10; /* second */ + + uwsc_log_info("Libuwsc: %s\n", UWSC_VERSION_STRING); + + webclient = uwsc_new(loop, url, ping_interval, NULL); + if (!webclient) + return -1; + + uwsc_log_info("Start connect...\n"); + + webclient->onopen = uwsc_onopen; + webclient->onmessage = uwsc_onmessage; + webclient->onerror = uwsc_onerror; + webclient->onclose = uwsc_onclose; + + ev_signal_init(&signal_watcher, signal_cb, SIGINT); + ev_signal_start(loop, &signal_watcher); + + ev_run(loop, 0); + + return 0; +} + +char liveapi_loop(void) +{ + stepping = 0; + ev_run(loop, 0); + return 0; +} + +char liveapi_step(void) +{ + if (HASH_COUNT(results) > 0) { + stepping = 1; + ev_run(loop, 0); + } + return 0; +} + +void liveapi_clean(void) +{ + struct result *s, *tmp; + + HASH_ITER(hh, results, s, tmp) { + cJSON_Delete(s->json); + HASH_DELETE(hh, results, s); + free(s); + } + + free(webclient); +} -- cgit v1.2.3