]> git.saurik.com Git - redis.git/blob - src/scripting.c
Lua function creation on EVAL, basic Lua return type to Redis protocol convertion...
[redis.git] / src / scripting.c
1 #include "redis.h"
2 #include "sha1.h"
3
4 #include <lua.h>
5 #include <lauxlib.h>
6 #include <lualib.h>
7
8 void scriptingInit(void) {
9 lua_State *lua = lua_open();
10 luaL_openlibs(lua);
11 server.lua = lua;
12 }
13
14 /* Hash the scripit into a SHA1 digest. We use this as Lua function name.
15 * Digest should point to a 41 bytes buffer: 40 for SHA1 converted into an
16 * hexadecimal number, plus 1 byte for null term. */
17 void hashScript(char *digest, char *script, size_t len) {
18 SHA1_CTX ctx;
19 unsigned char hash[20];
20 char *cset = "0123456789abcdef";
21 int j;
22
23 SHA1Init(&ctx);
24 SHA1Update(&ctx,(unsigned char*)script,len);
25 SHA1Final(hash,&ctx);
26
27 for (j = 0; j < 20; j++) {
28 digest[j*2] = cset[((hash[j]&0xF0)>>4)];
29 digest[j*2+1] = cset[(hash[j]&0xF)];
30 }
31 digest[40] = '\0';
32 }
33
34 void luaReplyToRedisReply(redisClient *c, lua_State *lua) {
35 int t = lua_type(lua,1);
36
37 switch(t) {
38 case LUA_TSTRING:
39 addReplyBulkCBuffer(c,(char*)lua_tostring(lua,1),lua_strlen(lua,1));
40 break;
41 case LUA_TBOOLEAN:
42 addReply(c,lua_toboolean(lua,1) ? shared.cone : shared.czero);
43 break;
44 case LUA_TNUMBER:
45 addReplyLongLong(c,(long long)lua_tonumber(lua,1));
46 break;
47 default:
48 addReply(c,shared.nullbulk);
49 }
50 lua_pop(lua,1);
51 }
52
53 void evalCommand(redisClient *c) {
54 lua_State *lua = server.lua;
55 char funcname[43];
56
57 /* We obtain the script SHA1, then check if this function is already
58 * defined into the Lua state */
59 funcname[0] = 'f';
60 funcname[1] = '_';
61 hashScript(funcname+2,c->argv[1]->ptr,sdslen(c->argv[1]->ptr));
62 lua_getglobal(lua, funcname);
63 if (lua_isnil(lua,1)) {
64 /* Function not defined... let's define it. */
65 sds funcdef = sdsempty();
66
67 lua_pop(lua,1); /* remove the nil from the stack */
68 funcdef = sdscat(funcdef,"function ");
69 funcdef = sdscatlen(funcdef,funcname,42);
70 funcdef = sdscatlen(funcdef," ()\n",4);
71 funcdef = sdscatlen(funcdef,c->argv[1]->ptr,sdslen(c->argv[1]->ptr));
72 funcdef = sdscatlen(funcdef,"\nend\n",5);
73 printf("Defining:\n%s\n",funcdef);
74
75 if (luaL_loadbuffer(lua,funcdef,sdslen(funcdef),"func definition")) {
76 addReplyErrorFormat(c,"Error compiling script (new function): %s\n",
77 lua_tostring(lua,-1));
78 lua_pop(lua,1);
79 return;
80 }
81 if (lua_pcall(lua,0,0,0)) {
82 addReplyErrorFormat(c,"Error running script (new function): %s\n",
83 lua_tostring(lua,-1));
84 lua_pop(lua,1);
85 return;
86 }
87 lua_getglobal(lua, funcname);
88 }
89
90 /* At this point whatever this script was never seen before or if it was
91 * already defined, we can call it. We have zero arguments and expect
92 * a single return value. */
93 if (lua_pcall(lua,0,1,0)) {
94 addReplyErrorFormat(c,"Error running script (call to %s): %s\n",
95 funcname, lua_tostring(lua,-1));
96 lua_pop(lua,1);
97 return;
98 }
99 luaReplyToRedisReply(c,lua);
100 }