summaryrefslogtreecommitdiff
path: root/extra
diff options
context:
space:
mode:
authorPieter Noordhuis <pcnoordhuis@gmail.com>2010-10-07 17:48:03 +0200
committerPieter Noordhuis <pcnoordhuis@gmail.com>2010-10-07 17:48:03 +0200
commit96510ce86ade991a7dc968587c3c618cc9bf5a88 (patch)
tree480e89c73ce3880773351cd1315ebb4aa2450fac /extra
parentb60952f22ade00bebd08530e568ed31eeadd8797 (diff)
Factor out reusable include for libevent
Diffstat (limited to 'extra')
-rw-r--r--extra/hiredis/libevent.h95
1 files changed, 95 insertions, 0 deletions
diff --git a/extra/hiredis/libevent.h b/extra/hiredis/libevent.h
new file mode 100644
index 0000000..c9bf4f1
--- /dev/null
+++ b/extra/hiredis/libevent.h
@@ -0,0 +1,95 @@
+#include <event.h>
+#include <hiredis.h>
+
+/* Prototype for the error callback. */
+typedef void (redisErrorCallback)(redisContext*);
+
+/* This struct enables us to pass both the events and the
+ * redisContext to the read and write handlers. */
+typedef struct redisEvents {
+ redisContext *context;
+ redisErrorCallback *err;
+ struct event rev, wev;
+} redisEvents;
+
+void redisLibEventRead(int fd, short event, void *arg) {
+ ((void)fd); ((void)event);
+ redisEvents *e = arg;
+
+ /* Always re-schedule read events */
+ event_add(&e->rev,NULL);
+
+ if (redisBufferRead(e->context) == REDIS_ERR) {
+ /* Handle error. */
+ e->err(e->context);
+ } else {
+ /* If processing the replies/callbacks results in an error,
+ * invoke the error callback and abort. */
+ if (redisProcessCallbacks(e->context) == REDIS_ERR) {
+ e->err(e->context);
+ }
+ }
+}
+
+void redisLibEventWrite(int fd, short event, void *arg) {
+ ((void)fd); ((void)event);
+ redisEvents *e = arg;
+ int done = 0;
+
+ if (redisBufferWrite(e->context, &done) == REDIS_ERR) {
+ /* Handle error */
+ e->err(e->context);
+ } else {
+ /* Schedule write event again when writing is not done. */
+ if (!done) {
+ event_add(&e->wev,NULL);
+ } else {
+ event_add(&e->rev,NULL);
+ }
+ }
+}
+
+/* Schedule to be notified on a write event, so the outgoing buffer
+ * can be flushed to the socket. */
+void redisLibEventOnWrite(redisContext *c, void *privdata) {
+ ((void)c);
+ redisEvents *e = privdata;
+ event_add(&e->wev,NULL);
+}
+
+/* Remove event handlers when the context gets disconnected. */
+void redisLibEventOnDisconnect(redisContext *c, void *privdata) {
+ ((void)c);
+ redisEvents *e = privdata;
+ event_del(&e->rev);
+ event_del(&e->wev);
+}
+
+/* Free the redisEvents struct when the context is free'd. */
+void redisLibEventOnFree(redisContext *c, void *privdata) {
+ ((void)c);
+ redisEvents *e = privdata;
+ free(e);
+}
+
+redisContext *redisLibEventConnect(const char *ip, int port, redisErrorCallback *err) {
+ redisEvents *e;
+ redisContext *c = redisConnectNonBlock(ip, port, NULL);
+ if (c->error != NULL) {
+ err(c);
+ return NULL;
+ }
+
+ /* Create container for context and r/w events */
+ e = malloc(sizeof(*e));
+ e->context = c;
+ e->err = err;
+
+ /* Register callbacks and events */
+ redisSetDisconnectCallback(e->context, redisLibEventOnDisconnect, e);
+ redisSetCommandCallback(e->context, redisLibEventOnWrite, e);
+ redisSetFreeCallback(e->context, redisLibEventOnFree, e);
+ event_set(&e->rev, e->context->fd, EV_READ, redisLibEventRead, e);
+ event_set(&e->wev, e->context->fd, EV_WRITE, redisLibEventWrite, e);
+ return e->context;
+}