]> source.dussan.org Git - rspamd.git/commitdiff
[Feature] Add periodic events support for lua_config
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Tue, 18 Oct 2016 12:46:10 +0000 (13:46 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Tue, 18 Oct 2016 12:47:52 +0000 (13:47 +0100)
src/lua/lua_common.c
src/lua/lua_config.c

index efe4f45cfc4aa07a1dc304bb20a37cd8d5f9dcf0..3f36306e2134c944b6b83aafe62c09ebe063dd69 100644 (file)
@@ -271,6 +271,12 @@ rspamd_lua_init ()
        luaopen_cryptobox (L);
        luaopen_lpeg (L);
 
+       luaL_newmetatable (L, "rspamd{ev_base}");
+       lua_pushstring (L, "class");
+       lua_pushstring (L, "rspamd{ev_base}");
+       lua_rawset (L, -3);
+       lua_pop (L, 1);
+
        rspamd_lua_add_preload (L, "ucl", luaopen_ucl);
 
        if (luaL_dostring (L, rspamadm_script_global_functions) != 0) {
index 617dac1373523ea743d03f3bbb0f94e167778d28..863bbd3d84d4bb3f1166afeef6c23863631ad832 100644 (file)
@@ -416,12 +416,38 @@ LUA_FUNCTION_DEF (config, replace_regexp);
 LUA_FUNCTION_DEF (config, register_worker_script);
 
 /***
- * @method rspamd_config:add_on_load(function(cfg) ... end)
+ * @method rspamd_config:add_on_load(function(cfg, ev_base) ... end)
  * Registers the following script to be executed when configuration is completely loaded
  * @param {function} script function to be executed
+ * @example
+rspamd_config:add_on_load(function(cfg, ev_base)
+       rspamd_config:add_periodic(ev_base, 1.0, function(cfg, ev_base)
+               local logger = require "rspamd_logger"
+               logger.infox(cfg, "periodic function")
+               return true
+       end)
+end)
  */
 LUA_FUNCTION_DEF (config, add_on_load);
 
+/***
+ * @method rspamd_config:add_periodic(event_base, timeout, function(cfg, ev_base) ... end, [jitter = false])
+ * Registers function to be periodically executed by Rspamd
+ * @param {ev_base} event_base event base that is needed for async events
+ * @param {number} timeout time in seconds (could be fractional)
+ * @param {function} script function to be executed
+ * @param {boolean} jitter `true` if timeout jittering is needed
+ * @example
+rspamd_config:add_on_load(function(cfg, ev_base)
+       rspamd_config:add_periodic(ev_base, 1.0, function(cfg, ev_base)
+               local logger = require "rspamd_logger"
+               logger.infox(cfg, "periodic function")
+               return true -- if return false, then the periodic event is removed
+       end)
+end)
+ */
+LUA_FUNCTION_DEF (config, add_periodic);
+
 /***
  * @method rspamd_config:get_symbols_count()
  * Returns number of symbols registered in rspamd configuration
@@ -509,6 +535,7 @@ static const struct luaL_reg configlib_m[] = {
        LUA_INTERFACE_DEF (config, replace_regexp),
        LUA_INTERFACE_DEF (config, register_worker_script),
        LUA_INTERFACE_DEF (config, add_on_load),
+       LUA_INTERFACE_DEF (config, add_periodic),
        LUA_INTERFACE_DEF (config, get_symbols_count),
        LUA_INTERFACE_DEF (config, get_symbol_callback),
        LUA_INTERFACE_DEF (config, set_symbol_callback),
@@ -1836,6 +1863,101 @@ lua_config_add_on_load (lua_State *L)
        return 0;
 }
 
+struct rspamd_lua_periodic {
+       struct event_base *ev_base;
+       struct rspamd_config *cfg;
+       lua_State *L;
+       gdouble timeout;
+       struct event ev;
+       gint cbref;
+       gboolean need_jitter;
+};
+
+static void
+lua_periodic_callback (gint unused_fd, short what, gpointer ud)
+{
+       gdouble timeout;
+       struct timeval tv;
+       struct rspamd_lua_periodic *periodic = ud;
+       struct rspamd_config **pcfg;
+       struct ev_base **pev_base;
+       lua_State *L;
+       gboolean plan_more = FALSE;
+
+       L = periodic->L;
+       lua_rawgeti (L, LUA_REGISTRYINDEX, periodic->cbref);
+       pcfg = lua_newuserdata (L, sizeof (*pcfg));
+       rspamd_lua_setclass (L, "rspamd{config}", -1);
+       *pcfg = periodic->cfg;
+       pev_base = lua_newuserdata (L, sizeof (*pev_base));
+       rspamd_lua_setclass (L, "rspamd{ev_base}", -1);
+
+       if (lua_pcall (L, 2, 1, 0) != 0) {
+               msg_info ("call to periodic failed: %s", lua_tostring (L, -1));
+               lua_pop (L, 1);
+       }
+       else {
+               plan_more = lua_toboolean (L, -1);
+               lua_pop (L, 1);
+       }
+
+       event_del (&periodic->ev);
+
+       if (plan_more) {
+               timeout = periodic->timeout;
+
+               if (periodic->need_jitter) {
+                       timeout = rspamd_time_jitter (timeout, 0.0);
+               }
+
+               double_to_tv (timeout, &tv);
+               event_add (&periodic->ev, &tv);
+       }
+       else {
+               luaL_unref (L, LUA_REGISTRYINDEX, periodic->cbref);
+               g_slice_free1 (sizeof (*periodic), periodic);
+       }
+}
+
+static gint
+lua_config_add_periodic (lua_State *L)
+{
+       struct rspamd_config *cfg = lua_check_config (L, 1);
+       struct event_base *ev_base = lua_check_ev_base (L, 2);
+       gdouble timeout = lua_tonumber (L, 3);
+       struct timeval tv;
+       struct rspamd_lua_periodic *periodic;
+       gboolean need_jitter = FALSE;
+
+       if (cfg == NULL || timeout <= 0 || lua_type (L, 4) != LUA_TFUNCTION) {
+               return luaL_error (L, "invalid arguments");
+       }
+
+       if (lua_type (L, 5) == LUA_TBOOLEAN) {
+               need_jitter = lua_toboolean (L, 5);
+       }
+
+       periodic = g_slice_alloc0 (sizeof (*periodic));
+       periodic->timeout = timeout;
+       periodic->L = L;
+       periodic->cfg = cfg;
+       periodic->ev_base = ev_base;
+       periodic->need_jitter = need_jitter;
+       lua_pushvalue (L, 4);
+       periodic->cbref = luaL_ref (L, LUA_REGISTRYINDEX);
+       event_set (&periodic->ev, -1, EV_TIMEOUT, lua_periodic_callback, periodic);
+       event_base_set (ev_base, &periodic->ev);
+
+       if (need_jitter) {
+               timeout = rspamd_time_jitter (timeout, 0.0);
+       }
+
+       double_to_tv (timeout, &tv);
+       event_add (&periodic->ev, &tv);
+
+       return 0;
+}
+
 static gint
 lua_config_get_symbols_count (lua_State *L)
 {