diff options
Diffstat (limited to 'resource.c')
-rw-r--r-- | resource.c | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/resource.c b/resource.c new file mode 100644 index 0000000..c1473e7 --- /dev/null +++ b/resource.c @@ -0,0 +1,105 @@ +// Copyright (C) 2021 Russell King. +// Licensed under GPL version 2. See COPYING. +#include <gio/gio.h> +#include "event-httpd.h" +#include "resource.h" + +struct resource_object { + GList *client_list; + char *str; +}; + +static struct resource_object position_object; +static struct resource_object signal_object; + +static void object_v1_send(struct client *c, struct resource_object *obj) +{ + const char *str = obj->str; + GString *s; + + if (!str) + return; + + // Format the text/event-stream response + // The double newline terminates this event + // See https://www.html5rocks.com/en/tutorials/eventsource/basics/ + s = g_string_sized_new(1024); + g_string_printf(s, "data:%s\n", str); + g_string_append_c(s, '\n'); + + respond_chunk(c, s); + g_string_free(s, TRUE); +} + +static int object_v1_get(struct client *c, struct resource *r) +{ + struct resource_object *obj = r->data; + + respond_header(c, 200, "OK", + "Cache-Control: no-cache\r\n" + "Connection: keep-alive\r\n" + "Content-Type: text/event-stream; charset=UTF-8\r\n" + "Transfer-Encoding: chunked\r\n"); + + object_v1_send(c, obj); + + // Add this client to the object list so it receives updates + obj->client_list = g_list_append(obj->client_list, c); + + return 1; +} + +// Update this client with the new resource object data +static void object_v1_client_update(gpointer data, gpointer user_data) +{ + struct resource_object *obj = user_data; + struct client *c = data; + + object_v1_send(c, obj); +} + +// Update all attached clients with the new resource object data +static int object_v1_update(struct client *c, struct resource *r, const char *m) +{ + struct resource_object *obj = r->data; + char *n, *o; + + n = g_strdup(m); + g_strchomp(n); + o = obj->str; + obj->str = n; + if (o) + g_free(o); + + g_list_foreach(obj->client_list, object_v1_client_update, obj); + + return 0; +} + +static void object_v1_close(struct client *c, struct resource *r) +{ + struct resource_object *obj = r->data; + + // Remove this client from the object list + obj->client_list = g_list_remove(obj->client_list, c); +} + +static struct resource resource_position1 = { + .get = object_v1_get, + .update = object_v1_update, + .close = object_v1_close, + .data = &position_object, +}; + +static struct resource resource_signal1 = { + .get = object_v1_get, + .update = object_v1_update, + .close = object_v1_close, + .data = &signal_object, +}; + +void resource_init(GHashTable *hash) +{ + g_hash_table_insert(hash, "/api/1/position", &resource_position1); + g_hash_table_insert(hash, "/api/1/signal", &resource_signal1); +} |