static int lconn_get_reply(lua_State * L) { redisContext * pContext = check_connection(L, 1); int nret = 0; redisReply * pReply = NULL; int ok = redisGetReply(pContext, (void **)&pReply); if (ok != REDIS_OK || pReply == NULL) { /* TODO: Shouldn't we clear the context error state somehow after this? */ return push_error(L, pContext); } nret = push_reply(L, pReply); /* * TODO: Not entirely safe: if above code throws error, reply object is leaked. */ freeReplyObject(pReply); pReply = NULL; return nret; }
static void on_redis_response(redisAsyncContext *context, void *reply, void *privdata) { redisReply *redisReply = reply; luv_ref_t *ref = privdata; int replyArgsCount = 0; lua_State *L = ref->L; lua_rawgeti(L, LUA_REGISTRYINDEX, ref->r); luaL_unref(L, LUA_REGISTRYINDEX, ref->r); ref_free(ref); if (redisReply == NULL) { luv_push_async_hiredis_error(L, context, "on_redis_response"); lua_pushnil(L); luv_acall(L, 2, 0, "on_redis_response"); } else { if (redisReply->type != REDIS_REPLY_ERROR) { lua_pushnil(L); ++replyArgsCount; } replyArgsCount += push_reply(L, redisReply); luv_acall(L, replyArgsCount, 0, "on_redis_response"); } }
static int lconn_command(lua_State * L) { redisContext * pContext = check_connection(L, 1); const char * argv[LUAHIREDIS_MAXARGS]; size_t argvlen[LUAHIREDIS_MAXARGS]; int nargs = load_args(L, pContext, 2, argv, argvlen); int nret = 0; redisReply * pReply = (redisReply *)redisCommandArgv( pContext, nargs, argv, argvlen ); if (pReply == NULL) { /* TODO: Shouldn't we clear the context error state somehow after this? */ return push_error(L, pContext); } nret = push_reply(L, pReply); /* * TODO: Not entirely safe: if above code throws error, reply object is leaked. */ freeReplyObject(pReply); pReply = NULL; return nret; }
static int lconn_get_reply(lua_State * L) { redisContext * pContext = check_connection(L, 1); /* int base = lua_gettop(L); */ int nret = 0; redisReply * pReply = NULL; int ok = redisGetReply(pContext, (void **)&pReply); if (ok != REDIS_OK || pReply == NULL) { /* TODO: Shouldn't we clear the context error state somehow after this? */ return push_error(L, pContext); } /* if (lua_gettop(L) != base) { freeReplyObject(pReply); return luaL_error( L, "lhrstackerror1 actual %d expected %d", lua_gettop(L), base ); } */ nret = push_reply(L, pReply); /* if (lua_gettop(L) != base + nret) { freeReplyObject(pReply); return luaL_error( L, "lhrstackerror2 actual %d expected %d base %d", lua_gettop(L), base + nret, base ); } */ /* * TODO: Not entirely safe: if above code throws error, reply object is leaked. */ freeReplyObject(pReply); pReply = NULL; return nret; }
static int push_reply(lua_State *L, redisReply *redisReply) { switch(redisReply->type) { case REDIS_REPLY_ERROR: luv_push_async_error_raw(L, NULL, redisReply->str, "push_reply", NULL); break; case REDIS_REPLY_STATUS: lua_pushlstring(L, redisReply->str, redisReply->len); break; case REDIS_REPLY_INTEGER: lua_pushinteger(L, redisReply->integer); break; case REDIS_REPLY_NIL: lua_pushnil(L); break; case REDIS_REPLY_STRING: lua_pushlstring(L, redisReply->str, redisReply->len); break; case REDIS_REPLY_ARRAY: { unsigned int i; lua_createtable(L, redisReply->elements, 0); for (i = 0; i < redisReply->elements; ++i) { push_reply(L, redisReply->element[i]); lua_rawseti(L, -2, i + 1); /* Store sub-reply */ } break; } default: return luaL_error(L, "Unknown reply type: %d", redisReply->type); } return 1; }
bool parse_redis_protocol(struct request *req) { int ret; void *reply; redisReader *reader; if(strncmp(req->buf, "$-1", 3) == 0) { lua_pushboolean(req->vm, false); return true; } else if(strncmp(req->buf, "+OK", 3) == 0) { lua_pushboolean(req->vm, true); return true; } reader = redisReaderCreate(); DEBUG_PRINT("req->buf=%s\r\n", req->buf); redisReaderFeed(reader, req->buf, sdslen(req->buf)); ret = redisReaderGetReply(reader,&reply); if (ret == REDIS_ERR) { freeReplyObject(reply); redisReaderFree(reader); return false; } push_reply(req->vm, (redisReply*)reply); //printf("%s\r\n", ((redisReply*)reply)->str); freeReplyObject(reply); redisReaderFree(reader); return true; }
static int push_reply(lua_State * L, redisReply * pReply) { switch (pReply->type) { case REDIS_REPLY_STATUS: luaL_checkstack(L, 2, "not enough stack to push reply"); lua_pushvalue(L, lua_upvalueindex(1)); /* M (module table) */ lua_getfield(L, -1, "status"); /* status = M.status */ lua_remove(L, -2); /* Remove module table from stack */ lua_pushlstring(L, pReply->str, pReply->len); /* name */ lua_gettable(L, -2); /* status[name] */ lua_remove(L, -2); /* Remove status table from stack */ break; case REDIS_REPLY_ERROR: /* Not caching errors, they are (hopefully) not that common */ push_new_const(L, pReply->str, pReply->len, REDIS_REPLY_ERROR); break; case REDIS_REPLY_INTEGER: luaL_checkstack(L, 1, "not enough stack to push reply"); lua_pushinteger(L, pReply->integer); break; case REDIS_REPLY_NIL: luaL_checkstack(L, 2, "not enough stack to push reply"); lua_pushvalue(L, lua_upvalueindex(1)); /* module table */ lua_getfield(L, -1, LUAHIREDIS_KEY_NIL); lua_remove(L, -2); /* module table */ break; case REDIS_REPLY_STRING: luaL_checkstack(L, 1, "not enough stack to push reply"); lua_pushlstring(L, pReply->str, pReply->len); break; case REDIS_REPLY_ARRAY: { unsigned int i = 0; luaL_checkstack(L, 2, "not enough stack to push reply"); lua_createtable(L, pReply->elements, 0); for (i = 0; i < pReply->elements; ++i) { /* * Not controlling recursion depth: * if we parsed the reply somehow, * we hope to be able to push it. */ push_reply(L, pReply->element[i]); lua_rawseti(L, -2, i + 1); /* Store sub-reply */ } break; } default: /* should not happen */ return luaL_error(L, "command: unknown reply type: %d", pReply->type); } /* * Always returning a single value. * If changed, change REDIS_REPLY_ARRAY above. */ return 1; }
static int push_reply(lua_State * L, redisReply * pReply) { /* int base = lua_gettop(L); */ switch(pReply->type) { case REDIS_REPLY_STATUS: lua_pushvalue(L, lua_upvalueindex(1)); /* M (module table) */ lua_pushlstring(L, pReply->str, pReply->len); /* status */ lua_gettable(L, -2); /* M[status] */ if (lua_isnil(L, -1)) /* Not bothering with metatables */ { /* * TODO: Following code is likely to be broken due to early binding * (imagine that RETURN is a command that returns given string * as a status): * * assert(conn:command("RETURN", "FOO") == hiredis.FOO) * * Here hiredis.FOO would be nil before conn:command() is called. * * Note that this is not relevant to the current Redis implementation * (that is 2.2 and before), since it seems that it wouldn't * return any status code except OK, QUEUED or PONG, * all of which are alread covered. */ lua_pushlstring(L, pReply->str, pReply->len); /* status */ push_new_const( L, pReply->str, pReply->len, REDIS_REPLY_STATUS /* const */ ); lua_settable(L, -3); /* M[status] = const */ lua_pushlstring(L, pReply->str, pReply->len); /* status */ lua_gettable(L, -2); /* return M[status] */ } lua_remove(L, -2); /* Remove module table */ break; case REDIS_REPLY_ERROR: /* Not caching errors, they are (hopefully) not that common */ push_new_const(L, pReply->str, pReply->len, REDIS_REPLY_ERROR); break; case REDIS_REPLY_INTEGER: lua_pushinteger(L, pReply->integer); break; case REDIS_REPLY_NIL: lua_pushvalue(L, lua_upvalueindex(1)); /* module table */ lua_getfield(L, -1, LUAHIREDIS_KEY_NIL); lua_remove(L, -2); /* module table */ break; case REDIS_REPLY_STRING: lua_pushlstring(L, pReply->str, pReply->len); break; case REDIS_REPLY_ARRAY: { unsigned int i = 0; lua_createtable(L, pReply->elements, 0); for (i = 0; i < pReply->elements; ++i) { /* * Not controlling recursion depth: * if we parsed the reply somehow, * we hope to be able to push it. */ push_reply(L, pReply->element[i]); lua_rawseti(L, -2, i + 1); /* Store sub-reply */ } break; } default: /* should not happen */ return luaL_error(L, "command: unknown reply type: %d", pReply->type); } /* if (lua_gettop(L) != base + 1) { return luaL_error(L, "pushreplystackerror: actual %d expected %d base %d type %d", lua_gettop(L), base + 1, base, pReply->type); } */ /* * Always returning a single value. * If changed, change REDIS_REPLY_ARRAY above. */ return 1; }