diff --git a/README.md b/README.md index b0b2aff..ff50d13 100644 --- a/README.md +++ b/README.md @@ -372,6 +372,8 @@ the disconnect callback is a good point to do so. Setting the connect or disconnect callbacks can only be done once per context. For subsequent calls the api will return `REDIS_ERR`. The function to set the callbacks have the following prototype: ```c +/* Alternatively you can use redisAsyncSetConnectCallbackNC which will be passed a non-const + redisAsyncContext* on invocation (e.g. allowing writes to the privdata member). */ int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn); int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn); ``` diff --git a/async.c b/async.c index 73b7980..ae097df 100644 --- a/async.c +++ b/async.c @@ -140,6 +140,7 @@ static redisAsyncContext *redisAsyncInitialize(redisContext *c) { ac->ev.scheduleTimer = NULL; ac->onConnect = NULL; + ac->onConnectNC = NULL; ac->onDisconnect = NULL; ac->replies.head = NULL; @@ -226,17 +227,34 @@ redisAsyncContext *redisAsyncConnectUnix(const char *path) { return redisAsyncConnectWithOptions(&options); } -int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn) { - if (ac->onConnect == NULL) { - ac->onConnect = fn; +static int +redisAsyncSetConnectCallbackImpl(redisAsyncContext *ac, redisConnectCallback *fn, + redisConnectCallbackNC *fn_nc) +{ + /* If either are already set, this is an error */ + if (ac->onConnect || ac->onConnectNC) + return REDIS_ERR; - /* The common way to detect an established connection is to wait for - * the first write event to be fired. This assumes the related event - * library functions are already set. */ - _EL_ADD_WRITE(ac); - return REDIS_OK; + if (fn) { + ac->onConnect = fn; + } else if (fn_nc) { + ac->onConnectNC = fn_nc; } - return REDIS_ERR; + + /* The common way to detect an established connection is to wait for + * the first write event to be fired. This assumes the related event + * library functions are already set. */ + _EL_ADD_WRITE(ac); + + return REDIS_OK; +} + +int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn) { + return redisAsyncSetConnectCallbackImpl(ac, fn, NULL); +} + +int redisAsyncSetConnectCallbackNC(redisAsyncContext *ac, redisConnectCallbackNC *fn) { + return redisAsyncSetConnectCallbackImpl(ac, NULL, fn); } int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn) { @@ -305,14 +323,23 @@ static void __redisRunPushCallback(redisAsyncContext *ac, redisReply *reply) { static void __redisRunConnectCallback(redisAsyncContext *ac, int status) { - if (ac->onConnect) { - if (!(ac->c.flags & REDIS_IN_CALLBACK)) { - ac->c.flags |= REDIS_IN_CALLBACK; + if (ac->onConnect == NULL && ac->onConnectNC == NULL) + return; + + if (!(ac->c.flags & REDIS_IN_CALLBACK)) { + ac->c.flags |= REDIS_IN_CALLBACK; + if (ac->onConnect) { ac->onConnect(ac, status); - ac->c.flags &= ~REDIS_IN_CALLBACK; } else { - /* already in callback */ + ac->onConnectNC(ac, status); + } + ac->c.flags &= ~REDIS_IN_CALLBACK; + } else { + /* already in callback */ + if (ac->onConnect) { ac->onConnect(ac, status); + } else { + ac->onConnectNC(ac, status); } } } diff --git a/async.h b/async.h index 690b31f..4f94660 100644 --- a/async.h +++ b/async.h @@ -57,7 +57,8 @@ typedef struct redisCallbackList { /* Connection callback prototypes */ typedef void (redisDisconnectCallback)(const struct redisAsyncContext*, int status); -typedef void (redisConnectCallback)(struct redisAsyncContext*, int status); +typedef void (redisConnectCallback)(const struct redisAsyncContext*, int status); +typedef void (redisConnectCallbackNC)(struct redisAsyncContext *, int status); typedef void(redisTimerCallback)(void *timer, void *privdata); /* Context for an async connection to Redis */ @@ -93,6 +94,7 @@ typedef struct redisAsyncContext { /* Called when the first write event was received. */ redisConnectCallback *onConnect; + redisConnectCallbackNC *onConnectNC; /* Regular command callbacks */ redisCallbackList replies; @@ -121,6 +123,7 @@ redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port, const char *source_addr); redisAsyncContext *redisAsyncConnectUnix(const char *path); int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn); +int redisAsyncSetConnectCallbackNC(redisAsyncContext *ac, redisConnectCallbackNC *fn); int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn); redisAsyncPushFn *redisAsyncSetPushCallback(redisAsyncContext *ac, redisAsyncPushFn *fn); diff --git a/test.c b/test.c index fccaca4..b901752 100644 --- a/test.c +++ b/test.c @@ -2008,7 +2008,7 @@ static redisAsyncContext *do_aconnect(struct config config, astest_no testno) { redisOptions options = {0}; memset(&astest, 0, sizeof(astest)); - + astest.testno = testno; astest.connect_status = astest.disconnect_status = -2; @@ -2039,7 +2039,7 @@ static redisAsyncContext *do_aconnect(struct config config, astest_no testno) c->data = &astest; c->dataCleanup = asCleanup; redisPollAttach(c); - redisAsyncSetConnectCallback(c, connectCallback); + redisAsyncSetConnectCallbackNC(c, connectCallback); redisAsyncSetDisconnectCallback(c, disconnectCallback); return c; } @@ -2058,7 +2058,7 @@ static void test_async_polling(struct config config) { int status; redisAsyncContext *c; struct config defaultconfig = config; - + test("Async connect: "); c = do_aconnect(config, ASTEST_CONNECT); assert(c); @@ -2095,7 +2095,7 @@ static void test_async_polling(struct config config) { test_cond(astest.connect_status == REDIS_ERR); config = defaultconfig; } - + /* Test a ping/pong after connection */ test("Async PING/PONG: "); c = do_aconnect(config, ASTEST_PINGPONG);