]> git.saurik.com Git - redis.git/commitdiff
Lua call of Redis command work in progress: sorry I have to go to the cinema to watch...
authorantirez <antirez@gmail.com>
Sat, 30 Apr 2011 20:29:21 +0000 (22:29 +0200)
committerantirez <antirez@gmail.com>
Wed, 25 May 2011 10:32:44 +0000 (12:32 +0200)
src/networking.c
src/redis.h
src/scripting.c

index 4a6a8afd8c3cc6cd1c4abc7d58c88dd0abb1773c..b26c20595decfad39d3f88938d74ebcee3b32b85 100644 (file)
@@ -14,14 +14,20 @@ redisClient *createClient(int fd) {
     redisClient *c = zmalloc(sizeof(redisClient));
     c->bufpos = 0;
 
-    anetNonBlock(NULL,fd);
-    anetTcpNoDelay(NULL,fd);
-    if (aeCreateFileEvent(server.el,fd,AE_READABLE,
-        readQueryFromClient, c) == AE_ERR)
-    {
-        close(fd);
-        zfree(c);
-        return NULL;
+    /* passing -1 as fd it is possible to create a non connected client.
+     * This is useful since all the Redis commands needs to be executed
+     * in the context of a client. When commands are executed in other
+     * contexts (for instance a Lua script) we need a non connected client. */
+    if (fd != -1) {
+        anetNonBlock(NULL,fd);
+        anetTcpNoDelay(NULL,fd);
+        if (aeCreateFileEvent(server.el,fd,AE_READABLE,
+            readQueryFromClient, c) == AE_ERR)
+        {
+            close(fd);
+            zfree(c);
+            return NULL;
+        }
     }
 
     selectDb(c,0);
index 4848de95bde0be466489f1c292c7051bd0060823..0071c0aa406852353fee5982278079d0cab95a61 100644 (file)
@@ -657,6 +657,7 @@ struct redisServer {
     clusterState cluster;
     /* Scripting */
     lua_State *lua;
+    redisClient *lua_client;
 };
 
 typedef struct pubsubPattern {
index 42ba3bf95c48c58c38422cd6bd35e91e25b374f5..9b957c92df3e4c6c60f4bd38c33c84fc9e5d8caa 100644 (file)
@@ -5,9 +5,67 @@
 #include <lauxlib.h>
 #include <lualib.h>
 
+int luaRedisCommand(lua_State *lua) {
+    int j, argc = lua_gettop(lua);
+    struct redisCommand *cmd;
+    robj **argv;
+    redisClient *c = server.lua_client;
+    sds reply;
+
+    argv = zmalloc(sizeof(robj*)*argc);
+    for (j = 0; j < argc; j++)
+        argv[j] = createStringObject(lua_tostring(lua,j+1),lua_strlen(lua,j+1));
+
+    /* Command lookup */
+    cmd = lookupCommand(argv[0]->ptr);
+    if (!cmd) {
+        zfree(argv);
+        lua_pushnil(lua);
+        lua_pushstring(lua,"Unknown Redis command called from Lua script");
+        return 2;
+    }
+    /* Run the command in the context of a fake client */
+    c->argv = argv;
+    c->argc = argc;
+    cmd->proc(c);
+
+    /* Convert the result of the Redis command into a suitable Lua type.
+     * The first thing we need is to create a single string from the client
+     * output buffers. */
+    reply = sdsempty();
+    if (c->bufpos) {
+        reply = sdscatlen(reply,c->bufpos,c->buf);
+        c->bufpos = 0;
+    }
+    while(listLength(c->reply)) {
+        robj *o = listNodeValue(listFirst(c->reply));
+
+        sdscatlen(reply,o->ptr,sdslen(o->ptr));
+        listDelNode(c->reply,listFirst(c->reply));
+    }
+    lua_pushnumber(lua,1);
+
+    /* Clean up. Command code may have changed argv/argc so we use the
+     * argv/argc of the client instead of the local variables. */
+    for (j = 0; j < c->argc; j++)
+        decrRefCount(c->argv[j]);
+    zfree(c->argv);
+
+    return 1;
+}
+
 void scriptingInit(void) {
     lua_State *lua = lua_open();
     luaL_openlibs(lua);
+
+    /* Register the 'r' command */
+    lua_pushcfunction(lua,luaRedisCommand);
+    lua_setglobal(lua,"r");
+
+    /* Create the (non connected) client that we use to execute Redis commands
+     * inside the Lua interpreter */
+    server.lua_client = createClient(-1);
+
     server.lua = lua;
 }