summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--event-httpd.c14
-rw-r--r--resource.c34
-rw-r--r--resource.h3
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;
diff --git a/resource.c b/resource.c
index bc5dfdd..8c67635 100644
--- a/resource.c
+++ b/resource.c
@@ -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 = {
diff --git a/resource.h b/resource.h
index c3a1907..657397b 100644
--- a/resource.h
+++ b/resource.h
@@ -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;
};