From fc720a141bfcbe915cded0d78a5fd5aac358b6e1 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 26 Sep 2021 13:18:15 +0100 Subject: resource: provide "backend" status events Provide status events for the backend connection state, so the web clients know whether anything is connected and when the last connect or disconnect event happened. Signed-off-by: Russell King --- resource.c | 56 ++++++++++++++++++++++++++++++++++++++++++-------------- resource.h | 1 + 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/resource.c b/resource.c index 8c67635..c89e188 100644 --- a/resource.c +++ b/resource.c @@ -12,23 +12,17 @@ struct resource_object { static struct resource_object position_object; static struct resource_object signal_object; -static void resource_obj_send(struct client *c, struct resource_object *obj) +static void resource_obj_send_one(gpointer data, gpointer user_data) { - GString *string = obj->string; - - if (!string) - return; + GString *string = user_data; + struct client *c = data; respond_chunk(c, string); } -// Update this client with the new resource object data -static void resource_obj_update(gpointer data, gpointer user_data) +static void resource_obj_send_all(struct resource_object *obj, GString *str) { - struct resource_object *obj = user_data; - struct client *c = data; - - resource_obj_send(c, obj); + g_list_foreach(obj->client_list, resource_obj_send_one, str); } static void resource_obj_set_string(struct resource_object *obj, GString *str) @@ -39,7 +33,7 @@ static void resource_obj_set_string(struct resource_object *obj, GString *str) obj->string = str; g_string_free(old, TRUE); - g_list_foreach(obj->client_list, resource_obj_update, obj); + resource_obj_send_all(obj, str); } static void resource_obj_add_client(struct resource_object *obj, @@ -54,10 +48,23 @@ static void resource_obj_del_client(struct resource_object *obj, obj->client_list = g_list_remove(obj->client_list, c); } +static GString *object_backend_status(struct resource *r) +{ + GString *str; + + str = g_string_new("event: backend\n"); + g_string_append_printf(str, + "data: {\"status\":\"%s\",\"timestamp\":%ld}\n\n", + r->updater ? "connected" : "disconnected", + r->updater_time); + + return str; +} static int object_v1_get(struct client *c, struct resource *r) { struct resource_object *obj = r->data; + GString *str; respond_header(c, 200, "OK", "Cache-Control: no-cache\r\n" @@ -65,7 +72,13 @@ static int object_v1_get(struct client *c, struct resource *r) "Content-Type: text/event-stream; charset=UTF-8\r\n" "Transfer-Encoding: chunked\r\n"); - resource_obj_send(c, obj); + str = object_backend_status(r); + g_string_append(str, "retry: 10000\n"); + if (obj->string) + g_string_append_len(str, obj->string->str, + obj->string->len); + respond_chunk(c, str); + g_string_free(str, TRUE); // Add this client to the object list so it receives updates resource_obj_add_client(obj, c); @@ -83,8 +96,15 @@ static void object_v1_close(struct client *c, struct resource *r) static void object_v1_update_open(struct client *c, struct resource *r) { + GString *str; + // Keep track of the latest updater r->updater = c; + time(&r->updater_time); + + str = object_backend_status(r); + resource_obj_send_all(r->data, str); + g_string_free(str, TRUE); } // Update all attached clients with the new resource object data @@ -119,10 +139,18 @@ static int object_v1_update(struct client *c, struct resource *r, const char *m) static void object_v1_update_close(struct client *c, struct resource *r) { + GString *str; + // If the updater goes away, clear the data so we don't serve // stale data. - if (r->updater == c) + if (r->updater == c) { r->updater = NULL; + time(&r->updater_time); + + str = object_backend_status(r); + resource_obj_send_all(r->data, str); + g_string_free(str, TRUE); + } } static const struct resource_ops resource_v1_ops = { diff --git a/resource.h b/resource.h index 657397b..99bcfed 100644 --- a/resource.h +++ b/resource.h @@ -17,6 +17,7 @@ struct resource_ops { struct resource { const struct resource_ops *ops; struct client *updater; + time_t updater_time; void *data; }; -- cgit