]> source.dussan.org Git - rspamd.git/commitdiff
Implement synchronous redis call
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 25 Jan 2016 16:36:36 +0000 (16:36 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 25 Jan 2016 16:36:36 +0000 (16:36 +0000)
src/lua/lua_redis.c

index d3a82a9e7d534cfade81dc384d2f6a1b68e9a310..80ef9e361414dcfdf6364230cad747a352633581 100644 (file)
@@ -56,9 +56,11 @@ end
  */
 
 LUA_FUNCTION_DEF (redis, make_request);
+LUA_FUNCTION_DEF (redis, make_request_sync);
 
 static const struct luaL_reg redislib_m[] = {
        LUA_INTERFACE_DEF (redis, make_request),
+       LUA_INTERFACE_DEF (redis, make_request_sync),
        {"__tostring", rspamd_lua_class_tostring},
        {NULL, NULL}
 };
@@ -82,16 +84,16 @@ struct lua_redis_userdata {
 };
 
 static void
-lua_redis_free_args (struct lua_redis_userdata *ud)
+lua_redis_free_args (char **args, guint nargs)
 {
        guint i;
 
-       if (ud->args) {
-               for (i = 0; i < ud->nargs; i ++) {
-                       g_free (ud->args[i]);
+       if (args) {
+               for (i = 0; i < nargs; i ++) {
+                       g_free (args[i]);
                }
 
-               g_free (ud->args);
+               g_free (args);
        }
 }
 
@@ -103,7 +105,7 @@ lua_redis_fin (void *arg)
        if (ud->ctx) {
                ud->terminated = 1;
                redisAsyncFree (ud->ctx);
-               lua_redis_free_args (ud);
+               lua_redis_free_args (ud->args, ud->nargs);
                event_del (&ud->timeout);
                luaL_unref (ud->L, LUA_REGISTRYINDEX, ud->cbref);
        }
@@ -250,7 +252,7 @@ lua_redis_timeout (int fd, short what, gpointer u)
 
 static void
 lua_redis_parse_args (lua_State *L, gint idx, const gchar *cmd,
-               struct lua_redis_userdata *ud)
+               gchar ***pargs, guint *nargs)
 {
        gchar **args = NULL;
        gint top;
@@ -287,8 +289,8 @@ lua_redis_parse_args (lua_State *L, gint idx, const gchar *cmd,
                top = 1;
        }
 
-       ud->nargs = top;
-       ud->args = args;
+       *pargs = args;
+       *nargs = top;
 }
 
 static void
@@ -374,7 +376,7 @@ lua_redis_make_request (lua_State *L)
                        ud->L = L;
                        ud->cbref = cbref;
                        lua_pushstring (L, "args");
-                       lua_redis_parse_args (L, -1, cmd, ud);
+                       lua_redis_parse_args (L, -1, cmd, &ud->args, &ud->nargs);
                        ret = TRUE;
                }
                else {
@@ -404,10 +406,10 @@ lua_redis_make_request (lua_State *L)
 
                        cmd = luaL_checkstring (L, 4);
                        if (top > 4) {
-                               lua_redis_parse_args (L, 5, cmd, ud);
+                               lua_redis_parse_args (L, 5, cmd, &ud->args, &ud->nargs);
                        }
                        else {
-                               lua_redis_parse_args (L, 0, cmd, ud);
+                               lua_redis_parse_args (L, 0, cmd, &ud->args, &ud->nargs);
                        }
 
                        ret = TRUE;
@@ -426,7 +428,7 @@ lua_redis_make_request (lua_State *L)
                if (ud->ctx == NULL || ud->ctx->err) {
                        ud->terminated = 1;
                        redisAsyncFree (ud->ctx);
-                       lua_redis_free_args (ud);
+                       lua_redis_free_args (ud->args, ud->nargs);
                        luaL_unref (ud->L, LUA_REGISTRYINDEX, ud->cbref);
                        lua_pushboolean (L, FALSE);
 
@@ -453,7 +455,7 @@ lua_redis_make_request (lua_State *L)
                else {
                        msg_info ("call to redis failed: %s", ud->ctx->errstr);
                        ud->terminated = 1;
-                       lua_redis_free_args (ud);
+                       lua_redis_free_args (ud->args, ud->nargs);
                        redisAsyncFree (ud->ctx);
                        luaL_unref (ud->L, LUA_REGISTRYINDEX, ud->cbref);
                }
@@ -463,6 +465,90 @@ lua_redis_make_request (lua_State *L)
 
        return 1;
 }
+
+/***
+ * @function rspamd_redis.make_request_sync({params})
+ * Make blocking request to redis server, params is a table of key=value arguments in any order
+ * @param {task} task worker task object
+ * @param {ip} host server address
+ * @param {string} cmd command to be sent to redis
+ * @param {table} args numeric array of strings used as redis arguments
+ * @param {number} timeout timeout in seconds for request (1.0 by default)
+ * @return {boolean + result} `true` and a result if a request has been successful
+ */
+static int
+lua_redis_make_request_sync (lua_State *L)
+{
+       struct rspamd_lua_ip *addr = NULL;
+       const gchar *cmd = NULL;
+       struct timeval tv;
+       gboolean ret = FALSE;
+       gdouble timeout = REDIS_DEFAULT_TIMEOUT;
+       gchar **args = NULL;
+       guint nargs = 0;
+       redisContext *ctx;
+       redisReply *r;
+
+       if (lua_istable (L, 1)) {
+
+               lua_pushstring (L, "cmd");
+               lua_gettable (L, -2);
+               cmd = lua_tostring (L, -1);
+               lua_pop (L, 1);
+
+               lua_pushstring (L, "host");
+               lua_gettable (L, -2);
+               if (lua_type (L, -1) == LUA_TUSERDATA) {
+                       addr = lua_check_ip (L, -1);
+               }
+               lua_pop (L, 1);
+
+               lua_pushstring (L, "timeout");
+               lua_gettable (L, -2);
+               timeout = lua_tonumber (L, -1);
+               lua_pop (L, 1);
+
+               lua_pushstring (L, "args");
+               lua_redis_parse_args (L, -1, cmd, &args, &nargs);
+               ret = TRUE;
+       }
+
+       if (ret) {
+               msec_to_tv (timeout, &tv);
+               ctx = redisConnectWithTimeout (rspamd_inet_address_to_string (addr->addr),
+                               rspamd_inet_address_get_port (addr->addr), tv);
+
+               if (ctx == NULL || ctx->err) {
+                       redisFree (ctx);
+                       lua_redis_free_args (args, nargs);
+                       lua_pushboolean (L, FALSE);
+
+                       return 1;
+               }
+
+               r = redisCommandArgv (ctx,
+                                       nargs,
+                                       (const gchar **)args,
+                                       NULL);
+
+               if (r != NULL) {
+                       lua_pushboolean (L, TRUE);
+                       lua_redis_push_reply (L, r);
+                       freeReplyObject (r);
+                       redisFree (ctx);
+
+                       return 2;
+               }
+               else {
+                       msg_info ("call to redis failed: %s", ctx->errstr);
+                       redisFree (ctx);
+                       lua_redis_free_args (args, nargs);
+                       lua_pushboolean (L, FALSE);
+               }
+       }
+
+       return 1;
+}
 #else
 static int
 lua_redis_make_request (lua_State *L)
@@ -473,6 +559,15 @@ lua_redis_make_request (lua_State *L)
 
        return 1;
 }
+static int
+lua_redis_make_request_sync (lua_State *L)
+{
+       msg_warn ("rspamd is compiled with no redis support");
+
+       lua_pushboolean (L, FALSE);
+
+       return 1;
+}
 #endif
 
 static gint