Skip to content

Instantly share code, notes, and snippets.

@theonewolf
Created January 30, 2014 01:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save theonewolf/8701072 to your computer and use it in GitHub Desktop.
Save theonewolf/8701072 to your computer and use it in GitHub Desktop.
hiredis hack to handle user context on connect/disconnect callbacks
diff --git a/async.c b/async.c
index 923a329..a3fc05f 100644
--- a/async.c
+++ b/async.c
@@ -127,8 +127,13 @@ static redisAsyncContext *redisAsyncInitialize(redisContext *c) {
ac->ev.delWrite = NULL;
ac->ev.cleanup = NULL;
- ac->onConnect = NULL;
- ac->onDisconnect = NULL;
+ ac->onConnect.next = NULL;
+ ac->onConnect.fn.connectcb = NULL;
+ ac->onConnect.privdata= NULL;
+
+ ac->onDisconnect.next = NULL;
+ ac->onDisconnect.fn.disconnectcb = NULL;
+ ac->onDisconnect.privdata = NULL;
ac->replies.head = NULL;
ac->replies.tail = NULL;
@@ -183,9 +188,10 @@ redisAsyncContext *redisAsyncConnectUnix(const char *path) {
return ac;
}
-int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn) {
- if (ac->onConnect == NULL) {
- ac->onConnect = fn;
+int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn, void *privdata) {
+ if (ac->onConnect.fn.connectcb == NULL) {
+ ac->onConnect.fn.connectcb = fn;
+ ac->onConnect.privdata = privdata;
/* The common way to detect an established connection is to wait for
* the first write event to be fired. This assumes the related event
@@ -196,9 +202,10 @@ int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn
return REDIS_ERR;
}
-int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn) {
- if (ac->onDisconnect == NULL) {
- ac->onDisconnect = fn;
+int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn, void *privdata) {
+ if (ac->onDisconnect.fn.disconnectcb == NULL) {
+ ac->onDisconnect.fn.disconnectcb = fn;
+ ac->onDisconnect.privdata = privdata;
return REDIS_OK;
}
return REDIS_ERR;
@@ -245,9 +252,9 @@ static int __redisShiftCallback(redisCallbackList *list, redisCallback *target)
static void __redisRunCallback(redisAsyncContext *ac, redisCallback *cb, redisReply *reply) {
redisContext *c = &(ac->c);
- if (cb->fn != NULL) {
+ if (cb->fn.replycb != NULL) {
c->flags |= REDIS_IN_CALLBACK;
- cb->fn(ac,reply,cb->privdata);
+ cb->fn.replycb(ac,reply,cb->privdata);
c->flags &= ~REDIS_IN_CALLBACK;
}
}
@@ -285,11 +292,11 @@ static void __redisAsyncFree(redisAsyncContext *ac) {
/* Execute disconnect callback. When redisAsyncFree() initiated destroying
* this context, the status will always be REDIS_OK. */
- if (ac->onDisconnect && (c->flags & REDIS_CONNECTED)) {
+ if (ac->onDisconnect.fn.disconnectcb && (c->flags & REDIS_CONNECTED)) {
if (c->flags & REDIS_FREEING) {
- ac->onDisconnect(ac,REDIS_OK);
+ ac->onDisconnect.fn.disconnectcb(ac,REDIS_OK, ac->onDisconnect.privdata);
} else {
- ac->onDisconnect(ac,(ac->err == 0) ? REDIS_OK : REDIS_ERR);
+ ac->onDisconnect.fn.disconnectcb(ac,(ac->err == 0) ? REDIS_OK : REDIS_ERR, ac->onDisconnect.privdata);
}
}
@@ -444,7 +451,7 @@ void redisProcessCallbacks(redisAsyncContext *ac) {
__redisGetSubscribeCallback(ac,reply,&cb);
}
- if (cb.fn != NULL) {
+ if (cb.fn.replycb != NULL) {
__redisRunCallback(ac,&cb,reply);
c->reader->fn->freeObject(reply);
@@ -478,14 +485,14 @@ static int __redisAsyncHandleConnect(redisAsyncContext *ac) {
if (errno == EINPROGRESS)
return REDIS_OK;
- if (ac->onConnect) ac->onConnect(ac,REDIS_ERR);
+ if (ac->onConnect.fn.connectcb) ac->onConnect.fn.connectcb(ac,REDIS_ERR, ac->onConnect.privdata);
__redisAsyncDisconnect(ac);
return REDIS_ERR;
}
/* Mark context as connected. */
c->flags |= REDIS_CONNECTED;
- if (ac->onConnect) ac->onConnect(ac,REDIS_OK);
+ if (ac->onConnect.fn.connectcb) ac->onConnect.fn.connectcb(ac,REDIS_OK, ac->onConnect.privdata);
return REDIS_OK;
}
@@ -572,7 +579,7 @@ static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
if (c->flags & (REDIS_DISCONNECTING | REDIS_FREEING)) return REDIS_ERR;
/* Setup callback */
- cb.fn = fn;
+ cb.fn.replycb = fn;
cb.privdata = privdata;
/* Find out which command will be appended. */
diff --git a/async.h b/async.h
index 268274e..fb2345c 100644
--- a/async.h
+++ b/async.h
@@ -40,11 +40,21 @@ extern "C" {
struct redisAsyncContext; /* need forward declaration of redisAsyncContext */
struct dict; /* dictionary header is included in async.c */
-/* Reply callback prototype and container */
+/* Connection callback prototypes */
+typedef void (redisDisconnectCallback)(const struct redisAsyncContext*, int status, void*);
+typedef void (redisConnectCallback)(const struct redisAsyncContext*, int status, void*);
+
+/* Reply callback prototype */
typedef void (redisCallbackFn)(struct redisAsyncContext*, void*, void*);
+
+/* Callback container */
typedef struct redisCallback {
struct redisCallback *next; /* simple singly linked list */
- redisCallbackFn *fn;
+ union {
+ redisCallbackFn * replycb;
+ redisDisconnectCallback * disconnectcb;
+ redisConnectCallback * connectcb;
+ } fn;
void *privdata;
} redisCallback;
@@ -53,10 +63,6 @@ typedef struct redisCallbackList {
redisCallback *head, *tail;
} redisCallbackList;
-/* Connection callback prototypes */
-typedef void (redisDisconnectCallback)(const struct redisAsyncContext*, int status);
-typedef void (redisConnectCallback)(const struct redisAsyncContext*, int status);
-
/* Context for an async connection to Redis */
typedef struct redisAsyncContext {
/* Hold the regular context, so it can be realloc'ed. */
@@ -84,10 +90,10 @@ typedef struct redisAsyncContext {
/* Called when either the connection is terminated due to an error or per
* user request. The status is set accordingly (REDIS_OK, REDIS_ERR). */
- redisDisconnectCallback *onDisconnect;
+ redisCallback onDisconnect;
/* Called when the first write event was received. */
- redisConnectCallback *onConnect;
+ redisCallback onConnect;
/* Regular command callbacks */
redisCallbackList replies;
@@ -103,8 +109,8 @@ typedef struct redisAsyncContext {
/* Functions that proxy to hiredis */
redisAsyncContext *redisAsyncConnect(const char *ip, int port);
redisAsyncContext *redisAsyncConnectUnix(const char *path);
-int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn);
-int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
+int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn, void *privdata);
+int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn, void *privdata);
void redisAsyncDisconnect(redisAsyncContext *ac);
void redisAsyncFree(redisAsyncContext *ac);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment