source: nscp/modules/LUAScript/script_wrapper.hpp @ 1ff950c

0.4.00.4.10.4.2stable
Last change on this file since 1ff950c was 1ff950c, checked in by Michael Medin <michael@…>, 4 years ago

Fixed build environment to work better (stand alone)

  • Property mode set to 100644
File size: 12.0 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 atleast 1 argument!");
197                                }
198                                unsigned int argLen = nargs-1;
199                                arrayBuffer::arrayBuffer arguments = arrayBuffer::createArrayBuffer(argLen);
200                                for (unsigned int i=argLen;i>0;i--) {
201                                        std::wstring arg = extract_string(L);
202                                        arrayBuffer::set(arguments, argLen, i-1, arg);
203                                        lua_pop(L, 1);
204                                }
205                                std::wstring command = extract_string(L);
206                                lua_pop(L, 1);
207                                std::wstring msg;
208                                std::wstring perf;
209                                NSCAPI::nagiosReturn ret = NSCModuleHelper::InjectCommand(command.c_str(), argLen, arguments, msg, perf);
210                                push_code(L, ret);
211                                lua_pushstring(L, strEx::wstring_to_string(msg).c_str());
212                                lua_pushstring(L, strEx::wstring_to_string(perf).c_str());
213                                return 3;
214                        } catch (...) {
215                                return luaL_error(L, "Unknown exception in: nscp.execute");
216                        }
217                }
218
219                static int register_command(lua_State *L) {
220                        try {
221                                lua_handler *handler = lua_manager::get_handler(L);
222                                lua_script *script = lua_manager::get_script(L);
223                                int nargs = lua_gettop( L );
224                                if (nargs != 2)
225                                        return luaL_error(L, "Incorrect syntax: nscp.register(<key>, <function>);");
226                                handler->register_command(script, pop_string(L), pop_string(L));
227                                return 0;
228                        } catch (LUAException e) {
229                                return luaL_error(L, std::string("Error in nscp.register: " + w2s(e.getMessage())).c_str());
230                        } catch (...) {
231                                return luaL_error(L, "Unknown exception in: nscp.register");
232                        }
233                }
234
235                static int getSetting (lua_State *L) {
236                        int nargs = lua_gettop( L );
237                        if (nargs < 2 || nargs > 3)
238                                return luaL_error(L, "Incorrect syntax: nscp.getSetting(<section>, <key>[, <default value>]);");
239                        std::wstring v;
240                        if (nargs > 2)
241                                v = pop_string(L);
242                        std::wstring k = pop_string(L);
243                        std::wstring s = pop_string(L);
244                        push_string(L, NSCModuleHelper::getSettingsString(s, k, v));
245                        return 1;
246                }
247                static int getSection (lua_State *L) {
248                        int nargs = lua_gettop( L );
249                        if (nargs > 1)
250                                return luaL_error(L, "Incorrect syntax: nscp.getSection([<section>]);");
251                        std::wstring v;
252                        if (nargs > 0)
253                                v = pop_string(L);
254                        try {
255                                std::list<std::wstring> list = NSCModuleHelper::getSettingsSection(v);
256                                push_array(L, list);
257                        } catch (...) {
258                                return luaL_error(L, "Unknown exception getting section");
259                        }
260                        return 1;
261                }
262                static int info (lua_State *L) {
263                        return log_any(L, NSCAPI::log);
264                }
265                static int error (lua_State *L) {
266                        return log_any(L, NSCAPI::error);
267                }
268                static int log_any(lua_State *L, int mode) {
269                        where_type w = where(L);
270                        int nargs = lua_gettop( L );
271                        std::wstring str;
272                        for (int i=0;i<nargs;i++) {
273                                str += pop_string(L);
274                        }
275                        NSCModuleHelper::Message(mode, w.first, w.second, str);
276                        return 0;
277                }
278
279                static const luaL_Reg my_funcs[];
280
281                static int luaopen(lua_State *L) {
282                        luaL_register(L, "nscp", my_funcs);
283                        return 1;
284                }
285
286
287        };
288        const luaL_Reg nsclient_wrapper::my_funcs[] = {
289                {"execute", execute},
290                {"info", info},
291                {"print", info},
292                {"error", error},
293                {"register", register_command},
294                {"getSetting", getSetting},
295                {"getSection", getSection},
296                {NULL, NULL}
297        };
298
299        lua_manager::handler_type lua_manager::handlers;
300        lua_manager::script_type lua_manager::scripts;
301        double lua_manager::last_value = 0;
302        char lua_manager::handler_key[] = "registry.key.handler";
303        char lua_manager::script_key[] = "registry.key.script";
304
305        class lua_script {
306                Lua_State L;
307                std::wstring script_;
308        public:
309                lua_script(const std::wstring file) : script_(file) {
310                        load();
311                }
312                void load() {
313                        luaL_openlibs(L);
314                        nsclient_wrapper::luaopen(L);
315                        //Luna<Account>::Register(L);
316                        //lua_register(L, "register_command", register_command);
317
318                        if (luaL_loadfile(L, strEx::wstring_to_string(script_).c_str()) != 0) {
319                                throw LUAException(_T("Failed to load script: ") + script_ + _T(": ") + s2w(lua_tostring(L, -1)));
320                        }
321
322                }
323                std::wstring get_script() const {
324                        return script_;
325                }
326                void unload() {}
327                void reload(lua_handler *handler) {
328                        unload();
329                        load();
330                        pre_load(handler);
331                }
332                void pre_load(lua_handler *handler) {
333                        lua_manager::set_handler(L, handler);
334                        lua_manager::set_script(L, this);
335                        if (lua_pcall(L, 0, 0, 0) != 0) {
336                                throw LUAException(_T("Failed to parse script: ") + script_ + _T(": ") + s2w(lua_tostring(L, -1)));
337                        }
338                }
339
340
341                NSCAPI::nagiosReturn extract_return(Lua_State &L, int arg_count,  std::wstring &message, std::wstring &perf) {
342                        // code, message, performance data
343                        if (arg_count > 3) {
344                                NSC_LOG_ERROR_STD(_T("Too many arguments return from script (only using last 3)"));
345                                lua_pop(L, arg_count-3);
346                        }
347                        if (arg_count > 2) {
348                                perf = extract_string(L);
349                                lua_pop( L, 1 );
350                        }
351                        if (arg_count > 1) {
352                                message = extract_string(L);
353                                lua_pop( L, 1 );
354                        }
355                        if (arg_count > 0) {
356                                int ret = extract_code(L);
357                                lua_pop( L, 1 );
358                                return ret;
359                        }
360                        NSC_LOG_ERROR_STD(_T("No arguments returned from script."));
361                        return NSCAPI::returnUNKNOWN;
362                }
363
364                NSCAPI::nagiosReturn handleCommand(lua_handler *handler, std::wstring function, strEx::blindstr command, const unsigned int argLen, TCHAR **char_args, std::wstring &msg, std::wstring &perf) {
365                        lua_manager::set_handler(L, handler);
366                        lua_manager::set_script(L, this);
367                        int nargs = lua_gettop( L );
368                        lua_getglobal(L, w2s(function).c_str());
369                        if (!lua_isfunction(L, -1)) {
370                                lua_pop(L, 1); // remove function from LUA stack
371                                throw LUAException(_T("Failed to run script: ") + script_ + _T(": Function not found: handle"));
372                        }
373                        std::wstring cmd = command.c_str();
374                        lua_pushstring(L, w2s(cmd).c_str());
375
376                        lua_createtable(L, 0, argLen);
377                        for (unsigned int i=0;i<argLen;i++) {
378                                lua_pushnumber(L,i+1);
379                                lua_pushstring(L,strEx::wstring_to_string(char_args[i]).c_str());
380                                lua_settable(L,-3);
381                        }
382
383                        if (lua_pcall(L, 2, LUA_MULTRET, 0) != 0) {
384                                std::wstring err = strEx::string_to_wstring(lua_tostring(L, -1));
385                                NSC_LOG_ERROR_STD(_T("Failed to call main function in script: ") + script_ + _T(": ") + err);
386                                lua_pop(L, 1); // remove error message
387                                return NSCAPI::returnUNKNOWN;
388                        }
389                        return extract_return(L, lua_gettop( L )-nargs, msg, perf);
390                }
391        };
392
393
394
395
396
397}
Note: See TracBrowser for help on using the repository browser.