source: nscp/modules/LUAScript/script_wrapper.hpp @ d66ccee

0.4.00.4.10.4.2
Last change on this file since d66ccee was d66ccee, checked in by Michael Medin <michael@…>, 2 years ago

Tweaks to make building faster

  • Property mode set to 100644
File size: 11.9 KB
Line 
1#pragma once
2
3#include <map>
4
5extern "C" {
6#include <lua.h>
7#include "lauxlib.h"
8#include "lualib.h"
9}
10#include "luna.h"
11
12
13namespace script_wrapper {
14
15        class Lua_State {
16                lua_State *L;
17        public:
18                Lua_State() : L(lua_open()) { }
19
20                ~Lua_State() {
21                        lua_close(L);
22                }
23
24                // implicitly act as a lua_State pointer
25                inline operator lua_State*() {
26                        return L;
27                }
28        };
29
30        class LUAException {
31                std::wstring error_;
32        public:
33                LUAException(std::wstring error) : error_(error) {}
34
35                std::wstring getMessage() const {
36                        return error_;
37                }
38
39        };
40
41        inline std::string w2s(std::wstring s) {
42                return strEx::wstring_to_string(s);
43        }
44        inline std::wstring s2w(std::string s) {
45                return strEx::string_to_wstring(s);
46        }
47        typedef std::pair<std::wstring,int> where_type;
48        where_type where(lua_State *L, int level = 1) {
49                lua_Debug ar;
50                if (lua_getstack(L, level, &ar)) {  /* check function at level */
51                        lua_getinfo(L, "Sl", &ar);  /* get info about it */
52                        if (ar.currentline > 0) {  /* is there info? */
53                                return where_type(s2w(ar.short_src), ar.currentline);
54                        }
55                }
56                return where_type(_T("unknown"),0);
57        }
58        std::wstring extract_string(lua_State *L) {
59                int top = lua_gettop(L);
60                if (lua_isstring(L, top))
61                        return strEx::string_to_wstring(lua_tostring( L, lua_gettop( L ) ));
62                return _T("<NOT_A_STRING>");
63        }
64        std::wstring pop_string(lua_State *L) {
65                std::wstring ret;
66                int top = lua_gettop(L);
67                if (lua_isstring(L, top))
68                        ret = strEx::string_to_wstring(lua_tostring( L, top));
69                else if (lua_isnil(L, top))
70                        ret = _T("<NIL>");
71                else if (lua_istable(L, top))
72                        ret = _T("<TABLE>");
73                else if (lua_isnumber(L, top))
74                        ret = _T("<NUMBER>");
75                else if (lua_iscfunction(L, top))
76                        ret = _T("<C-FUNCTION>");
77                else
78                        ret = _T("<UNKNOWN>");
79                lua_pop(L, 1);
80                return ret;
81        }
82        NSCAPI::nagiosReturn extract_code(lua_State *L) {
83                std::string str;
84                switch (lua_type( L, lua_gettop( L ) )) {
85        case LUA_TNUMBER:
86                return static_cast<int>(lua_tonumber(L, lua_gettop(L)));
87        case LUA_TTABLE:
88                NSC_LOG_ERROR_STD(_T("Incorect return from script: should be error, ok, warning or unknown"));
89                return NSCAPI::returnUNKNOWN;
90        case LUA_TSTRING:
91                str = lua_tostring(L, lua_gettop(L));
92                if ((str == "critical")||(str == "crit")||(str == "error")) {
93                        return NSCAPI::returnCRIT;
94                } else if ((str == "warning")||(str == "warn")) {
95                        return NSCAPI::returnWARN;
96                } else if (str == "ok") {
97                        return NSCAPI::returnOK;
98                } else if (str == "unknown") {
99                        return NSCAPI::returnUNKNOWN;
100                } else {
101                        NSC_LOG_ERROR_STD(_T("Incorect return from script: should be ok, warning, critical or unknown not: ") + strEx::string_to_wstring(str) );
102                        return NSCAPI::returnUNKNOWN;
103                }
104        case LUA_TBOOLEAN:
105                return lua_toboolean( L, lua_gettop( L ) )?NSCAPI::returnOK:NSCAPI::returnCRIT;
106                }
107                NSC_LOG_ERROR_STD(_T("Incorect return from script: should be error, ok, warning or unknown"));
108                return NSCAPI::returnUNKNOWN;
109        }
110        void push_code(lua_State *L, NSCAPI::nagiosReturn  code) {
111                if (code == NSCAPI::returnOK)
112                        lua_pushstring(L, strEx::wstring_to_string(_T("ok")).c_str());
113                else if (code == NSCAPI::returnWARN)
114                        lua_pushstring(L, strEx::wstring_to_string(_T("warning")).c_str());
115                else if (code == NSCAPI::returnCRIT)
116                        lua_pushstring(L, strEx::wstring_to_string(_T("critical")).c_str());
117                else
118                lua_pushstring(L, strEx::wstring_to_string(_T("unknown")).c_str());
119        }
120        void push_string(lua_State *L, std::wstring s) {
121                lua_pushstring(L, strEx::wstring_to_string(s).c_str());
122        }
123        void push_array(lua_State *L, std::list<std::wstring> &arr) {
124                lua_createtable(L, 0, arr.size());
125                int i=0;
126                for (std::list<std::wstring>::const_iterator cit=arr.begin(); cit != arr.end(); ++cit) {
127                        lua_pushnumber(L,i++);
128                        lua_pushstring(L,strEx::wstring_to_string(*cit).c_str());
129                        lua_settable(L,-3);
130                }
131        }
132
133        class lua_script;
134        class lua_handler {
135        public:
136                virtual void register_command(lua_script* script, std::wstring command, std::wstring function) = 0;
137
138        };
139        class lua_manager {
140                typedef std::map<double,lua_handler*> handler_type;
141                typedef std::map<double,lua_script*> script_type;
142                static handler_type handlers;
143                static script_type scripts;
144                static double last_value;
145                static char handler_key[];
146                static char script_key[];
147        public:
148                static lua_handler* get_handler(lua_State *L) {
149                        handler_type::const_iterator cit = handlers.find(get_id(L, handler_key));
150                        if (cit == handlers.end())
151                                throw LUAException(_T("Could not find handler reference"));
152                        return (*cit).second;
153                }
154                static void set_handler(lua_State *L, lua_handler* handler) {
155                        double id = get_id(L, handler_key);
156                        handlers[id] = handler;
157                }
158                static lua_script* get_script(lua_State *L) {
159                        script_type::const_iterator cit = scripts.find(get_id(L, script_key));
160                        if (cit == scripts.end())
161                                throw LUAException(_T("Could not find script reference"));
162                        return (*cit).second;
163                }
164                static void set_script(lua_State *L, lua_script* script) {
165                        double id = get_id(L, script_key);
166                        scripts[id] = script;
167                }
168                static double get_id(lua_State *L, char *key) {
169                        /* retrieve a number */
170                        lua_pushstring(L, key);
171                        //lua_pushlightuserdata(L, (void*)&key);  /* push address */
172                        lua_gettable(L, LUA_REGISTRYINDEX);  /* retrieve value */
173                        double v = 0;
174                        v = lua_tonumber(L, -1);  /* convert to number */
175                        lua_pop(L,1);
176                        if (v <= 0) {
177                                v = ++last_value;
178                                lua_pushstring(L, key);
179                                //lua_pushlightuserdata(L, reinterpret_cast<void*>(&key));  /* push address */
180                                lua_pushnumber(L, v);  /* push value */
181                                /* registry[&Key] = myNumber */
182                                lua_settable(L, LUA_REGISTRYINDEX);
183                        }
184                        return v;
185
186                }
187
188        };
189        class nsclient_wrapper {
190        public:
191
192                static int execute (lua_State *L) {
193                        try {
194                                int nargs = lua_gettop( L );
195                                if (nargs == 0) {
196                                        return luaL_error(L, "nscp.execute requires at least 1 argument!");
197                                }
198                                unsigned int argLen = nargs-1;
199                                std::list<std::wstring> arguments;
200                                for (unsigned int i=argLen;i>0;i--) {
201                                        arguments.push_front(extract_string(L));
202                                        lua_pop(L, 1);
203                                }
204                                std::wstring command = extract_string(L);
205                                lua_pop(L, 1);
206                                std::wstring message;
207                                std::wstring perf;
208                                NSCAPI::nagiosReturn ret = GET_CORE()->InjectSimpleCommand(command, arguments, message, perf);
209                                push_code(L, ret);
210                                lua_pushstring(L, strEx::wstring_to_string(message).c_str());
211                                lua_pushstring(L, strEx::wstring_to_string(perf).c_str());
212                                return 3;
213                        } catch (...) {
214                                return luaL_error(L, "Unknown exception in: nscp.execute");
215                        }
216                }
217
218                static int register_command(lua_State *L) {
219                        try {
220                                lua_handler *handler = lua_manager::get_handler(L);
221                                lua_script *script = lua_manager::get_script(L);
222                                int nargs = lua_gettop( L );
223                                if (nargs != 2)
224                                        return luaL_error(L, "Incorrect syntax: nscp.register(<key>, <function>);");
225                                handler->register_command(script, pop_string(L), pop_string(L));
226                                return 0;
227                        } catch (LUAException e) {
228                                return luaL_error(L, std::string("Error in nscp.register: " + w2s(e.getMessage())).c_str());
229                        } catch (...) {
230                                return luaL_error(L, "Unknown exception in: nscp.register");
231                        }
232                }
233
234                static int getSetting (lua_State *L) {
235                        int nargs = lua_gettop( L );
236                        if (nargs < 2 || nargs > 3)
237                                return luaL_error(L, "Incorrect syntax: nscp.getSetting(<section>, <key>[, <default value>]);");
238                        std::wstring v;
239                        if (nargs > 2)
240                                v = pop_string(L);
241                        std::wstring k = pop_string(L);
242                        std::wstring s = pop_string(L);
243                        push_string(L, GET_CORE()->getSettingsString(s, k, v));
244                        return 1;
245                }
246                static int getSection (lua_State *L) {
247                        int nargs = lua_gettop( L );
248                        if (nargs > 1)
249                                return luaL_error(L, "Incorrect syntax: nscp.getSection([<section>]);");
250                        std::wstring v;
251                        if (nargs > 0)
252                                v = pop_string(L);
253                        try {
254                                std::list<std::wstring> list = GET_CORE()->getSettingsSection(v);
255                                push_array(L, list);
256                        } catch (...) {
257                                return luaL_error(L, "Unknown exception getting section");
258                        }
259                        return 1;
260                }
261                static int info (lua_State *L) {
262                        return log_any(L, NSCAPI::log);
263                }
264                static int error (lua_State *L) {
265                        return log_any(L, NSCAPI::error);
266                }
267                static int log_any(lua_State *L, int mode) {
268                        where_type w = where(L);
269                        int nargs = lua_gettop( L );
270                        std::wstring str;
271                        for (int i=0;i<nargs;i++) {
272                                str += pop_string(L);
273                        }
274                        GET_CORE()->Message(mode, utf8::cvt<std::string>(w.first), w.second, str);
275                        return 0;
276                }
277
278                static const luaL_Reg my_funcs[];
279
280                static int luaopen(lua_State *L) {
281                        luaL_register(L, "nscp", my_funcs);
282                        return 1;
283                }
284
285
286        };
287        const luaL_Reg nsclient_wrapper::my_funcs[] = {
288                {"execute", execute},
289                {"info", info},
290                {"print", info},
291                {"error", error},
292                {"register", register_command},
293                {"getSetting", getSetting},
294                {"getSection", getSection},
295                {NULL, NULL}
296        };
297
298        lua_manager::handler_type lua_manager::handlers;
299        lua_manager::script_type lua_manager::scripts;
300        double lua_manager::last_value = 0;
301        char lua_manager::handler_key[] = "registry.key.handler";
302        char lua_manager::script_key[] = "registry.key.script";
303
304        class lua_script {
305                Lua_State L;
306                std::wstring script_;
307        public:
308                lua_script(const std::wstring file) : script_(file) {
309                        load();
310                }
311                void load() {
312                        luaL_openlibs(L);
313                        nsclient_wrapper::luaopen(L);
314                        //Luna<Account>::Register(L);
315                        //lua_register(L, "register_command", register_command);
316
317                        if (luaL_loadfile(L, strEx::wstring_to_string(script_).c_str()) != 0) {
318                                throw LUAException(_T("Failed to load script: ") + script_ + _T(": ") + s2w(lua_tostring(L, -1)));
319                        }
320
321                }
322                std::wstring get_script() const {
323                        return script_;
324                }
325                void unload() {}
326                void reload(lua_handler *handler) {
327                        unload();
328                        load();
329                        pre_load(handler);
330                }
331                void pre_load(lua_handler *handler) {
332                        lua_manager::set_handler(L, handler);
333                        lua_manager::set_script(L, this);
334                        if (lua_pcall(L, 0, 0, 0) != 0) {
335                                throw LUAException(_T("Failed to parse script: ") + script_ + _T(": ") + s2w(lua_tostring(L, -1)));
336                        }
337                }
338
339
340                NSCAPI::nagiosReturn extract_return(Lua_State &L, int arg_count,  std::wstring &message, std::wstring &perf) {
341                        // code, message, performance data
342                        if (arg_count > 3) {
343                                NSC_LOG_ERROR_STD(_T("Too many arguments return from script (only using last 3)"));
344                                lua_pop(L, arg_count-3);
345                        }
346                        if (arg_count > 2) {
347                                perf = extract_string(L);
348                                lua_pop( L, 1 );
349                        }
350                        if (arg_count > 1) {
351                                message = extract_string(L);
352                                lua_pop( L, 1 );
353                        }
354                        if (arg_count > 0) {
355                                int ret = extract_code(L);
356                                lua_pop( L, 1 );
357                                return ret;
358                        }
359                        NSC_LOG_ERROR_STD(_T("No arguments returned from script."));
360                        return NSCAPI::returnUNKNOWN;
361                }
362
363                NSCAPI::nagiosReturn handleCommand(lua_handler *handler, std::wstring function, std::wstring cmd, std::list<std::wstring> arguments, std::wstring &msg, std::wstring &perf) {
364                        lua_manager::set_handler(L, handler);
365                        lua_manager::set_script(L, this);
366                        int nargs = lua_gettop( L );
367                        lua_getglobal(L, w2s(function).c_str());
368                        if (!lua_isfunction(L, -1)) {
369                                lua_pop(L, 1); // remove function from LUA stack
370                                throw LUAException(_T("Failed to run script: ") + script_ + _T(": Function not found: handle"));
371                        }
372                        lua_pushstring(L, w2s(cmd).c_str());
373
374                        lua_createtable(L, 0, arguments.size());
375                        int i=0;
376                        BOOST_FOREACH(std::wstring arg, arguments) {
377                                lua_pushnumber(L,i++);
378                                lua_pushstring(L,strEx::wstring_to_string(arg).c_str());
379                                lua_settable(L,-3);
380                        }
381
382                        if (lua_pcall(L, 2, LUA_MULTRET, 0) != 0) {
383                                std::wstring err = strEx::string_to_wstring(lua_tostring(L, -1));
384                                NSC_LOG_ERROR_STD(_T("Failed to call main function in script: ") + script_ + _T(": ") + err);
385                                lua_pop(L, 1); // remove error message
386                                return NSCAPI::returnUNKNOWN;
387                        }
388                        return extract_return(L, lua_gettop( L )-nargs, msg, perf);
389                }
390        };
391
392
393
394
395
396}
Note: See TracBrowser for help on using the repository browser.