Created
January 30, 2014 01:36
-
-
Save theonewolf/8701072 to your computer and use it in GitHub Desktop.
hiredis hack to handle user context on connect/disconnect callbacks
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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