]> source.dussan.org Git - rspamd.git/commitdiff
* Implement pre and post classify callbacks for checking specific statfiles for this...
authorVsevolod Stakhov <vsevolod@rambler-co.ru>
Wed, 16 Dec 2009 17:06:29 +0000 (20:06 +0300)
committerVsevolod Stakhov <vsevolod@rambler-co.ru>
Wed, 16 Dec 2009 17:06:29 +0000 (20:06 +0300)
TODO:
  - add properties to get all parameters of input task
  - add properties to statfile object
  - add some normalization function for calling from classify process
  - document changes

src/cfg_file.h
src/classifiers/winnow.c
src/lua/CMakeLists.txt
src/lua/lua_classifier.c [new file with mode: 0644]
src/lua/lua_common.c
src/lua/lua_common.h
src/lua/lua_config.c

index 43d424c70fae1985bb716e47d00e9458cba7381a..bb07a40c50e1f068e1bd200bda8a426ed4866927 100644 (file)
@@ -169,6 +169,8 @@ struct classifier_config {
     struct classifier *classifier;                  /**< classifier interface                               */
        struct tokenizer *tokenizer;                                    /**< tokenizer used for classifier                                              */
     GHashTable *opts;                               /**< other options                                      */
+       GList *pre_callbacks;                                                   /**< list of callbacks that are called before classification */
+       GList *post_callbacks;                                                  /**< list of callbacks that are called after classification */
 };
 
 /**
index 4b1bd5549b05323ca6e7076e450ad984408f879b..34e3dc2090574ec3cc4cf6b89511aa678b8c9f42 100644 (file)
@@ -30,6 +30,9 @@
 #include "../main.h"
 #include "../filter.h"
 #include "../cfg_file.h"
+#ifdef WITH_LUA
+#include "../lua/lua_common.h"
+#endif
 
 #define WINNOW_PROMOTION 1.23
 #define WINNOW_DEMOTION 0.83
@@ -135,8 +138,20 @@ winnow_classify (struct classifier_ctx *ctx, statfile_pool_t * pool, GTree * inp
        data.count = 0;
        data.now = time (NULL);
        data.ctx = ctx;
-
-       cur = ctx->cfg->statfiles;
+    
+    if (ctx->cfg->pre_callbacks) {
+#ifdef WITH_LUA
+        cur = call_classifier_pre_callbacks (ctx->cfg, task);
+        if (cur) {
+            memory_pool_add_destructor (task->task_pool, (pool_destruct_func)g_list_free, cur);
+        }
+#else
+           cur = ctx->cfg->statfiles;
+#endif
+    }
+    else {
+           cur = ctx->cfg->statfiles;
+    }
        while (cur) {
                st = cur->data;
                if ((data.file = statfile_pool_is_open (pool, st->path)) == NULL) {
@@ -170,7 +185,10 @@ winnow_classify (struct classifier_ctx *ctx, statfile_pool_t * pool, GTree * inp
                sumbuf = memory_pool_alloc (task->task_pool, 32);
                snprintf (sumbuf, 32, "%.2f", max);
                cur = g_list_prepend (NULL, sumbuf);
-               insert_result (task, ctx->cfg->metric, sel->symbol, 1, cur);
+#ifdef WITH_LUA
+        max = call_classifier_post_callbacks (ctx->cfg, task, max);
+#endif
+               insert_result (task, ctx->cfg->metric, sel->symbol, max, cur);
        }
 }
 
index 5ae12c49e3a9846156d2a662b0bd5ac3ae2a7f01..298b810256724d09e89f5df64c83696aaa5614f5 100644 (file)
@@ -2,7 +2,8 @@
 SET(LUASRC                       lua_common.c
                                          lua_task.c
                                          lua_message.c
-                                         lua_config.c)
+                                         lua_config.c
+                                         lua_classifier.c)
 
 ADD_LIBRARY(rspamd_lua STATIC ${LUASRC})
 TARGET_LINK_LIBRARIES(rspamd_lua ${LUALIB})
diff --git a/src/lua/lua_classifier.c b/src/lua/lua_classifier.c
new file mode 100644 (file)
index 0000000..ed6cdee
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2009, Rambler media
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Rambler media ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Rambler BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "lua_common.h"
+#include "../cfg_file.h"
+#include "../classifiers/classifiers.h"
+
+/* Classifier methods */
+LUA_FUNCTION_DEF (classifier, register_pre_callback);
+LUA_FUNCTION_DEF (classifier, register_post_callback);
+LUA_FUNCTION_DEF (classifier, get_statfiles);
+
+static const struct luaL_reg    classifierlib_m[] = {
+       LUA_INTERFACE_DEF (classifier, register_pre_callback),
+       LUA_INTERFACE_DEF (classifier, register_post_callback),
+       LUA_INTERFACE_DEF (classifier, get_statfiles),
+       {"__tostring", lua_class_tostring},
+       {NULL, NULL}
+};
+
+
+static const struct luaL_reg    statfilelib_m[] = {
+       {"__tostring", lua_class_tostring},
+       {NULL, NULL}
+};
+
+struct classifier_callback_data {
+       lua_State *L;
+       const char *name;
+};
+
+static struct statfile* lua_check_statfile (lua_State * L);
+
+/* Classifier implementation */
+
+
+static struct classifier_config      *
+lua_check_classifier (lua_State * L)
+{
+       void                           *ud = luaL_checkudata (L, 1, "rspamd{classifier}");
+       luaL_argcheck (L, ud != NULL, 1, "'classifier' expected");
+       return *((struct classifier_config **)ud);
+}
+
+/* Return list of statfiles that should be checked for this message */
+GList *
+call_classifier_pre_callbacks (struct classifier_config *ccf, struct worker_task *task)
+{
+       GList                          *res = NULL, *cur;
+       struct classifier_callback_data *cd;
+       struct classifier_config      **pccf;
+       struct worker_task            **ptask;
+       struct statfile                *st;
+       int                             i, len;
+
+       /* Go throught all callbacks and call them, appending results to list */
+       cur = g_list_first (ccf->pre_callbacks);
+       while (cur) {
+               cd = cur->data;
+               lua_getglobal (cd->L, cd->name);
+
+               pccf = lua_newuserdata (cd->L, sizeof (struct classifier_config *));
+               lua_setclass (cd->L, "rspamd{classifier}", -1);
+               *pccf = ccf;
+
+               ptask = lua_newuserdata (cd->L, sizeof (struct worker_task *));
+               lua_setclass (cd->L, "rspamd{task}", -1);
+               *ptask = task;
+
+               if (lua_pcall (cd->L, 2, 1, 0) != 0) {
+                       msg_warn ("call_classifier_pre_callbacks: error running function %s: %s", cd->name, lua_tostring (cd->L, -1));
+               }
+               else {
+                       if (lua_istable (cd->L, 1)) {
+                               len = lua_objlen (cd->L, 1);
+                               for (i = 1; i <= len; i ++) {
+                                       lua_rawgeti (cd->L, 1, i);
+                                       st = lua_check_statfile (cd->L);
+                                       if (st) {
+                                               res = g_list_prepend (res, st);
+                                       }
+                               }
+                       }
+               }
+
+               cur = g_list_next (cur);
+       }
+       
+       return res;
+}
+
+/* Return result mark for statfile */
+double
+call_classifier_post_callbacks (struct classifier_config *ccf, struct worker_task *task, double in)
+{
+       struct classifier_callback_data *cd;
+       struct classifier_config      **pccf;
+       struct worker_task            **ptask;
+       double                          out = in;
+       GList                          *cur;
+
+       /* Go throught all callbacks and call them, appending results to list */
+       cur = g_list_first (ccf->pre_callbacks);
+       while (cur) {
+               cd = cur->data;
+               lua_getglobal (cd->L, cd->name);
+
+               pccf = lua_newuserdata (cd->L, sizeof (struct classifier_config *));
+               lua_setclass (cd->L, "rspamd{classifier}", -1);
+               *pccf = ccf;
+
+               ptask = lua_newuserdata (cd->L, sizeof (struct worker_task *));
+               lua_setclass (cd->L, "rspamd{task}", -1);
+               *ptask = task;
+
+               lua_pushnumber (cd->L, out);
+
+               if (lua_pcall (cd->L, 3, 1, 0) != 0) {
+                       msg_warn ("call_classifier_pre_callbacks: error running function %s: %s", cd->name, lua_tostring (cd->L, -1));
+               }
+               else {
+                       if (lua_isnumber (cd->L, 1)) {
+                               out = lua_tonumber (cd->L, 1);
+                       }
+               }
+
+               cur = g_list_next (cur);
+       }
+
+       return out;
+
+}
+
+static int
+lua_classifier_register_pre_callback (lua_State *L)
+{
+       struct classifier_config       *ccf = lua_check_classifier (L);
+       struct classifier_callback_data *cd;
+       const char                     *name;
+
+       if (ccf) {
+               name = luaL_checkstring (L, 2);
+               if (name) {
+                       cd = g_malloc (sizeof (struct classifier_callback_data));
+                       cd->name = g_strdup (name);
+                       cd->L = L;
+                       ccf->pre_callbacks = g_list_prepend (ccf->pre_callbacks, cd);
+               }
+       }
+
+       return 0;
+
+}
+
+static int
+lua_classifier_register_post_callback (lua_State *L)
+{
+       struct classifier_config       *ccf = lua_check_classifier (L);
+       struct classifier_callback_data *cd;
+       const char                     *name;
+
+       if (ccf) {
+               name = luaL_checkstring (L, 2);
+               if (name) {
+                       cd = g_malloc (sizeof (struct classifier_callback_data));
+                       cd->name = g_strdup (name);
+                       cd->L = L;
+                       ccf->pre_callbacks = g_list_prepend (ccf->pre_callbacks, cd);
+               }
+       }
+
+       return 0;
+}
+
+/* Return table of statfiles indexed by theirs name */
+static int
+lua_classifier_get_statfiles (lua_State *L)
+{
+       struct classifier_config       *ccf = lua_check_classifier (L);
+       GList                          *cur;
+       struct statfile                *st, **pst;
+
+       if (ccf) {
+               lua_newtable (L);
+               cur = g_list_first (ccf->statfiles);
+               while (cur) {
+                       st = cur->data;
+                       /* t['statfile_name'] = statfile */
+                       lua_pushstring (L, st->symbol);
+                       pst = lua_newuserdata (L, sizeof (struct statfile *));
+                       lua_setclass (L, "rspamd{statfile}", -1);
+                       *pst = st;
+
+                       lua_settable (L, -3);
+
+                       cur = g_list_next (cur);
+               }
+       }
+       else {
+               lua_pushnil (L);
+       }
+
+       return 1;
+}
+
+/* Statfile functions */
+static struct statfile      *
+lua_check_statfile (lua_State * L)
+{
+       void                           *ud = luaL_checkudata (L, 1, "rspamd{statfile}");
+       luaL_argcheck (L, ud != NULL, 1, "'statfile' expected");
+       return *((struct statfile **)ud);
+}
+
+
+/* Open functions */
+
+int
+luaopen_classifier (lua_State * L)
+{
+       lua_newclass (L, "rspamd{classifier}", classifierlib_m);
+       luaL_openlib (L, "rspamd_classifier", null_reg, 0);
+
+       return 1;
+}
+
+int
+luaopen_statfile (lua_State * L)
+{
+       lua_newclass (L, "rspamd{statfile}", statfilelib_m);
+       luaL_openlib (L, "rspamd_statfile", null_reg, 0);
+
+       return 1;
+}
+
index 7e7caefda59ddfdeeb562e91a89771c8f8563cca..1ad61aaf0e50c44d1325a1f356d7872109138da7 100644 (file)
@@ -196,6 +196,8 @@ init_lua ()
                (void)luaopen_task (L);
                (void)luaopen_textpart (L);
                (void)luaopen_message (L);
+               (void)luaopen_classifier (L);
+               (void)luaopen_statfile (L);
        }
 }
 
index 9cd966e230ffd4cbd8038097d4fef2b550f078c5..314f903e7c97fb3e0e8fa1bb5ca90479604a283b 100644 (file)
@@ -27,6 +27,8 @@ int luaopen_metric (lua_State *L);
 int luaopen_radix (lua_State *L);
 int luaopen_hash_table (lua_State *L);
 int luaopen_textpart (lua_State *L);
+int luaopen_classifier (lua_State *L);
+int luaopen_statfile (lua_State * L);
 void init_lua_filters (struct config_file *cfg);
 
 int lua_call_filter (const char *function, struct worker_task *task);
@@ -34,5 +36,8 @@ int lua_call_chain_filter (const char *function, struct worker_task *task, int *
 double lua_consolidation_func (struct worker_task *task, const char *metric_name, const char *function_name);
 void add_luabuf (const char *line);
 
+GList *call_classifier_pre_callbacks (struct classifier_config *ccf, struct worker_task *task);
+double call_classifier_post_callbacks (struct classifier_config *ccf, struct worker_task *task, double in);
+
 #endif /* WITH_LUA */
 #endif /* RSPAMD_LUA_H */
index 377d72be5e4c6a254f9e06d920e151110e3e8374..fa23134a9b0af27d9aacbc04c8961673b864dccd 100644 (file)
@@ -27,6 +27,7 @@
 #include "../expressions.h"
 #include "../map.h"
 #include "../radix.h"
+#include "../classifiers/classifiers.h"
 
 /* Config file methods */
 LUA_FUNCTION_DEF (config, get_module_opt);
@@ -35,6 +36,7 @@ LUA_FUNCTION_DEF (config, get_all_opt);
 LUA_FUNCTION_DEF (config, register_function);
 LUA_FUNCTION_DEF (config, add_radix_map);
 LUA_FUNCTION_DEF (config, add_hash_map);
+LUA_FUNCTION_DEF (config, get_classifier);
 
 static const struct luaL_reg    configlib_m[] = {
        LUA_INTERFACE_DEF (config, get_module_opt),
@@ -43,6 +45,7 @@ static const struct luaL_reg    configlib_m[] = {
        LUA_INTERFACE_DEF (config, register_function),
        LUA_INTERFACE_DEF (config, add_radix_map),
        LUA_INTERFACE_DEF (config, add_hash_map),
+       LUA_INTERFACE_DEF (config, get_classifier),
        {"__tostring", lua_class_tostring},
        {NULL, NULL}
 };
@@ -236,6 +239,39 @@ lua_config_get_metric (lua_State * L)
 
 }
 
+static int
+lua_config_get_classifier (lua_State * L)
+{
+       struct config_file             *cfg = lua_check_config (L);
+       struct classifier_config       *clc = NULL, **pclc = NULL;
+       const char                     *name;
+       GList                          *cur;
+
+       if (cfg) {
+               name = luaL_checkstring (L, 2);
+
+               cur = g_list_first (cfg->classifiers);
+               while (cur) {
+                       clc = cur->data;
+                       if (g_ascii_strcasecmp (clc->classifier->name, name) == 0) {
+                               pclc = &clc;
+                               break;
+                       }
+                       cur = g_list_next (cur);
+               }
+               if (pclc) {
+                       pclc = lua_newuserdata (L, sizeof (struct classifier_config *));
+                       lua_setclass (L, "rspamd{classifier}", -1);
+                       *pclc = clc;
+                       return 1;
+               }
+       }
+
+       lua_pushnil (L);
+       return 1;
+
+}
+
 struct lua_callback_data {
        const char                     *name;
        lua_State                      *L;