summaryrefslogtreecommitdiff
path: root/cethcan
diff options
context:
space:
mode:
authorDavid Lamparter <equinox@diac24.net>2013-03-26 21:26:32 +0100
committerDavid Lamparter <equinox@diac24.net>2013-03-26 21:26:32 +0100
commitd18e85802a7878450d84bb9190cce0e368c55515 (patch)
treeecfa6a7670fa63c07c1be45add44b542bae891a0 /cethcan
parentac8beb0cb06e8aef35d9cfa134111e5c6ae09935 (diff)
cethcan: long poll
Diffstat (limited to 'cethcan')
-rw-r--r--cethcan/Makefile2
-rw-r--r--cethcan/cethcan.h3
-rw-r--r--cethcan/http.c112
-rw-r--r--cethcan/light.c8
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 <event2/http.h>
#include <event2/buffer.h>
+#include <openssl/sha.h>
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();
}
}