From d18e85802a7878450d84bb9190cce0e368c55515 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 26 Mar 2013 21:26:32 +0100 Subject: cethcan: long poll --- cethcan/Makefile | 2 +- cethcan/cethcan.h | 3 ++ cethcan/http.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++- cethcan/light.c | 8 +++- 4 files changed, 121 insertions(+), 4 deletions(-) diff --git a/cethcan/Makefile b/cethcan/Makefile index 633c2f6..ca4a433 100644 --- a/cethcan/Makefile +++ b/cethcan/Makefile @@ -4,7 +4,7 @@ love: cethcan PKGS="libevent jansson" cethcan: main.o can.o ether.o light.o http.o - gcc -g -o $@ `pkg-config --libs $(PKGS)` $^ + gcc -g -o $@ `pkg-config --libs $(PKGS)` -lcrypto $^ clean: rm -f *.o *.y.c *.y.h *.l.c cethcan diff --git a/cethcan/cethcan.h b/cethcan/cethcan.h index 64d185b..fd821fc 100644 --- a/cethcan/cethcan.h +++ b/cethcan/cethcan.h @@ -52,6 +52,7 @@ struct can_message { enum json_subtype { JSON_NORMAL = 0, + JSON_LONGPOLL = 1, }; typedef void (*can_handler)(void *arg, struct can_message *msg); @@ -74,6 +75,8 @@ extern void can_broadcast(struct can_user *origin, struct can_message *msg); extern void can_json(json_t *json, enum json_subtype type); extern void can_init(void); +extern void json_bump_longpoll(void); + extern int ether_init(json_t *config); extern int light_init_conf(json_t *config); extern void http_init(void); diff --git a/cethcan/http.c b/cethcan/http.c index e5f7ddb..8316abc 100644 --- a/cethcan/http.c +++ b/cethcan/http.c @@ -2,6 +2,7 @@ #include #include +#include static struct evhttp *evhttp; @@ -16,18 +17,127 @@ static void http_json_basic(struct evhttp_request *req, void *arg) struct evkeyvalq *outhdr = evhttp_request_get_output_headers(req); struct evbuffer *out = evbuffer_new(); - evhttp_add_header(outhdr, "Content-Type", "text/plain; charset=utf-8"); + evhttp_add_header(outhdr, "Content-Type", "application/json; charset=utf-8"); json_t *jsout = json_object(); can_json(jsout, JSON_NORMAL); json_dump_callback(jsout, evb_json_add, out, JSON_SORT_KEYS | JSON_INDENT(4)); + json_decref(jsout); + evhttp_send_reply(req, 200, "OK", out); evbuffer_free(out); } +static void http_json_bump(struct evhttp_request *req, void *arg) +{ + struct evkeyvalq *outhdr = evhttp_request_get_output_headers(req); + struct evbuffer *out = evbuffer_new(); + + evhttp_add_header(outhdr, "Content-Type", "text/plain; charset=utf-8"); + evbuffer_add_printf(out, "OK"); + evhttp_send_reply(req, 200, "OK", out); + evbuffer_free(out); + + json_bump_longpoll(); +} + +struct longpoll { + struct longpoll *next; + struct evhttp_request *req; +}; +static struct longpoll *longpolls = NULL, **plongpoll = &longpolls; +static size_t longpoll_count = 0; + +static char *longpollbuf = NULL; +static size_t longpollbuflen = 0; +static char longpollhash[SHA_DIGEST_LENGTH * 2 + 1] = ""; + +static void http_json_longpoll(struct evhttp_request *req, void *arg) +{ + struct evkeyvalq *outhdr = evhttp_request_get_output_headers(req); + struct evbuffer *out; + struct longpoll *lp; + const char *query; + + evhttp_add_header(outhdr, "Content-Type", "application/json; charset=utf-8"); + + query = evhttp_uri_get_query(evhttp_request_get_evhttp_uri(req)); + if (query && !strcmp(query, longpollhash)) { + lprintf("long poll"); + evhttp_send_reply_start(req, 200, "OK Long Poll"); + evhttp_request_own(req); + + lp = calloc(sizeof(*lp), 1); + lp->req = req; + *plongpoll = lp; + plongpoll = &lp->next; + longpoll_count++; + return; + } + + out = evbuffer_new(); + evbuffer_add(out, longpollbuf, longpollbuflen); + evhttp_send_reply(req, 200, "OK Short Poll", out); + evbuffer_free(out); +} + +static void longpoll_updatedata(void) +{ + json_t *jsout, *jswrap; + char *data; + unsigned char digest[SHA_DIGEST_LENGTH]; + + if (longpollbuf) + free(longpollbuf); + + jsout = json_object(); + can_json(jsout, JSON_LONGPOLL); + data = json_dumps(jsout, JSON_SORT_KEYS | JSON_INDENT(4)); + SHA1((unsigned char *)data, strlen(data), digest); + free(data); + + for (size_t i = 0; i < SHA_DIGEST_LENGTH; i++) + sprintf(longpollhash + i * 2, "%02x", digest[i]); + + jswrap = json_object(); + json_object_set_new(jswrap, "data", jsout); + json_object_set_new(jswrap, "ref", json_string(longpollhash)); + longpollbuf = json_dumps(jswrap, JSON_SORT_KEYS | JSON_INDENT(4)); + longpollbuflen = strlen(longpollbuf); + json_decref(jswrap); +} + +void json_bump_longpoll(void) +{ + struct longpoll *lp, *lpnext; + struct evbuffer *out; + + longpoll_updatedata(); + + out = evbuffer_new(); + for (lp = longpolls; lp; lp = lpnext) { + lpnext = lp->next; + + evbuffer_add(out, longpollbuf, longpollbuflen); + evhttp_send_reply_chunk(lp->req, out); + /* send_reply_end calls request_free() */ + evhttp_send_reply_end(lp->req); + free(lp); + } + evbuffer_free(out); + + longpolls = NULL; + plongpoll = &longpolls; + longpoll_count = 0; +} + void http_init(void) { evhttp = evhttp_new(ev_base); evhttp_set_cb(evhttp, "/", http_json_basic, NULL); + evhttp_set_cb(evhttp, "/longpoll", http_json_longpoll, NULL); + evhttp_set_cb(evhttp, "/bump", http_json_bump, NULL); evhttp_bind_socket(evhttp, "127.0.0.1", 34999); + + longpoll_updatedata(); } diff --git a/cethcan/light.c b/cethcan/light.c index cb3e94f..cd646d8 100644 --- a/cethcan/light.c +++ b/cethcan/light.c @@ -23,11 +23,13 @@ static void light_json_handler(void *arg, json_t *json, enum json_subtype type) json_object_set_new(lobj, "addr", json_integer(l->logical_addr)); json_object_set_new(lobj, "actual", json_integer(l->actual.val)); - json_object_set_new(lobj, "actual_ts", json_integer(l->actual.valid)); + if (type != JSON_LONGPOLL) + json_object_set_new(lobj, "actual_ts", json_integer(l->actual.valid)); json_object_set_new(lobj, "actual_tschg", json_integer(l->actual.change)); json_object_set_new(lobj, "set", json_integer(l->set.val)); - json_object_set_new(lobj, "set_ts", json_integer(l->set.valid)); + if (type != JSON_LONGPOLL) + json_object_set_new(lobj, "set_ts", json_integer(l->set.valid)); json_object_set_new(lobj, "set_tschg", json_integer(l->set.change)); json_object_set_new(json, l->name, lobj); @@ -59,6 +61,8 @@ static void light_can_handler(void *arg, struct can_message *msg) v->val = dval; time(&v->change); lprintf("%s: set %02x", l->u->name, dval); + + json_bump_longpoll(); } } -- cgit v1.2.1