diff options
-rw-r--r-- | event-httpd.c | 14 | ||||
-rw-r--r-- | resource.c | 34 | ||||
-rw-r--r-- | resource.h | 3 |
3 files changed, 44 insertions, 7 deletions
diff --git a/event-httpd.c b/event-httpd.c index 27590dd..865f82f 100644 --- a/event-httpd.c +++ b/event-httpd.c @@ -97,19 +97,28 @@ static void update(GObject *source, GAsyncResult *res, gpointer user_data) GError *error = NULL; char *line; gsize len; + int r; line = g_data_input_stream_read_line_finish(c->data, res, &len, &error); if (error || !line) { + if (c->resource->ops->update_close) + c->resource->ops->update_close(c, c->resource); + if (error) g_free(error); close_client(c); return; } - c->resource->ops->update(c, c->resource, line); + r = c->resource->ops->update(c, c->resource, line); g_free(line); + // If the update function returns an error, close this connection. + // This could be because we have a "newer" updater, or an error. + if (r == -1) + close_client(c); + g_data_input_stream_read_line_async(c->data, 0, NULL, update, c); } @@ -257,6 +266,9 @@ static void receive(GObject *source, GAsyncResult *res, gpointer user_data) return; } + if (resource->ops->update_open) + resource->ops->update_open(c, resource); + g_data_input_stream_read_line_async(c->data, 0, NULL, update, c); break; @@ -73,6 +73,20 @@ static int object_v1_get(struct client *c, struct resource *r) return 1; } +static void object_v1_close(struct client *c, struct resource *r) +{ + struct resource_object *obj = r->data; + + // Remove this client from the object list + resource_obj_del_client(obj, c); +} + +static void object_v1_update_open(struct client *c, struct resource *r) +{ + // Keep track of the latest updater + r->updater = c; +} + // Update all attached clients with the new resource object data static int object_v1_update(struct client *c, struct resource *r, const char *m) { @@ -80,6 +94,12 @@ static int object_v1_update(struct client *c, struct resource *r, const char *m) GString *string; char *n; + // Only allow the latest updater to provide updates, in case we + // end up with multiple connections. This also allows us to quickly + // release the resources of a stale connection. + if (r->updater != c) + return -1; + // Remove any trailing whitespace. n = g_strchomp(g_strdup(m)); @@ -97,18 +117,20 @@ static int object_v1_update(struct client *c, struct resource *r, const char *m) return 0; } -static void object_v1_close(struct client *c, struct resource *r) +static void object_v1_update_close(struct client *c, struct resource *r) { - struct resource_object *obj = r->data; - - // Remove this client from the object list - resource_obj_del_client(obj, c); + // If the updater goes away, clear the data so we don't serve + // stale data. + if (r->updater == c) + r->updater = NULL; } static const struct resource_ops resource_v1_ops = { .get = object_v1_get, - .update = object_v1_update, .close = object_v1_close, + .update_open = object_v1_update_open, + .update = object_v1_update, + .update_close = object_v1_update_close, }; static struct resource resource_position1 = { @@ -9,11 +9,14 @@ struct resource; struct resource_ops { int (*get)(struct client *c, struct resource *r); void (*close)(struct client *c, struct resource *r); + void (*update_open)(struct client *c, struct resource *r); int (*update)(struct client *c, struct resource *r, const char *m); + void (*update_close)(struct client *c, struct resource *r); }; struct resource { const struct resource_ops *ops; + struct client *updater; void *data; }; |