source: nscp/modules/LUAScript/script_wrapper.hpp @ 47b843a

0.4.00.4.10.4.2stable
Last change on this file since 47b843a was 47b843a, checked in by Michael Medin <michael@…>, 6 years ago

2007-12-16 MickeM

+ A lot of new features in the LUA module only "arguments" missing (as well as exposing more of the API)

  • Changed some exceptions that were thrown wrong
  • Property mode set to 100644
File size: 9.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
48
49
50
51        class Account {
52                lua_Number m_balance;
53        public:
54                static const char className[];
55                static Luna<Account>::RegType methods[];
56
57                Account(lua_State *L)      { m_balance = luaL_checknumber(L, 1); }
58                int inject(lua_State *L) {
59                        m_balance += luaL_checknumber(L, 1); return 0;
60                }
61                int withdraw(lua_State *L) { m_balance -= luaL_checknumber(L, 1); return 0; }
62                int balance (lua_State *L) { lua_pushnumber(L, m_balance); return 1; }
63                ~Account() { printf("deleted Account (%p)\n", this); }
64        };
65
66        const char Account::className[] = "Account";
67
68        #define method(class, name) {#name, &class::name}
69
70        Luna<Account>::RegType Account::methods[] = {
71                method(Account, inject),
72                method(Account, withdraw),
73                method(Account, balance),
74                {0,0}
75        };
76        std::wstring extract_string(lua_State *L) {
77                return strEx::string_to_wstring(lua_tostring( L, lua_gettop( L ) ));
78        }
79        std::wstring pop_string(lua_State *L) {
80                std::wstring ret = strEx::string_to_wstring(lua_tostring( L, lua_gettop( L ) ));
81                lua_pop(L, 1);
82                return ret;
83        }
84        NSCAPI::nagiosReturn extract_code(lua_State *L) {
85                std::string str;
86                switch (lua_type( L, lua_gettop( L ) )) {
87        case LUA_TNUMBER:
88                return static_cast<int>(lua_tonumber(L, lua_gettop(L)));
89        case LUA_TTABLE:
90                NSC_LOG_ERROR_STD(_T("Incorect return from script: should be error, ok, warning or unknown"));
91                return NSCAPI::returnUNKNOWN;
92        case LUA_TSTRING:
93                str = lua_tostring(L, lua_gettop(L));
94                if ((str == "critical")||(str == "crit")||(str == "error")) {
95                        return NSCAPI::returnCRIT;
96                } else if ((str == "warning")||(str == "warn")) {
97                        return NSCAPI::returnWARN;
98                } else if (str == "ok") {
99                        return NSCAPI::returnOK;
100                } else if (str == "unknown") {
101                        return NSCAPI::returnUNKNOWN;
102                } else {
103                        NSC_LOG_ERROR_STD(_T("Incorect return from script: should be ok, warning, critical or unknown not: ") + strEx::string_to_wstring(str) );
104                        return NSCAPI::returnUNKNOWN;
105                }
106        case LUA_TBOOLEAN:
107                return lua_toboolean( L, lua_gettop( L ) )?NSCAPI::returnOK:NSCAPI::returnCRIT;
108                }
109                NSC_LOG_ERROR_STD(_T("Incorect return from script: should be error, ok, warning or unknown"));
110                return NSCAPI::returnUNKNOWN;
111        }
112
113        static int inject(lua_State *L) {
114                int nargs = lua_gettop( L );
115                unsigned int argLen = nargs-1;
116                arrayBuffer::arrayBuffer arguments = arrayBuffer::createArrayBuffer(argLen);
117                for (unsigned int i=argLen;i>0;i--) {
118                        std::wstring arg = extract_string(L);
119                        arrayBuffer::set(arguments, argLen, i-1, arg);
120                        lua_pop(L, 1);
121                }
122                std::wstring command = extract_string(L);
123                lua_pop(L, 1);
124
125                std::wstring msg;
126                std::wstring perf;
127                NSCModuleHelper::InjectCommand(command.c_str(), argLen, arguments, msg, perf);
128                lua_pushstring(L, strEx::wstring_to_string(_T("ok")).c_str());
129                lua_pushstring(L, strEx::wstring_to_string(msg).c_str());
130                lua_pushstring(L, strEx::wstring_to_string(perf).c_str());
131                return 3;
132        }
133
134        class lua_script;
135        class lua_handler {
136        public:
137                virtual void register_command(lua_script* script, std::wstring command, std::wstring function) = 0;
138
139        };
140        class lua_manager {
141                typedef std::map<double,lua_handler*> handler_type;
142                typedef std::map<double,lua_script*> script_type;
143                static handler_type handlers;
144                static script_type scripts;
145                static double last_value;
146                static char handler_key[];
147                static char script_key[];
148        public:
149                static lua_handler* get_handler(lua_State *L) {
150                        handler_type::const_iterator cit = handlers.find(get_id(L, handler_key));
151                        if (cit == handlers.end())
152                                throw LUAException(_T("Could not find handler reference"));
153                        return (*cit).second;
154                }
155                static void set_handler(lua_State *L, lua_handler* handler) {
156                        double id = get_id(L, handler_key);
157                        handlers[id] = handler;
158                }
159                static lua_script* get_script(lua_State *L) {
160                        script_type::const_iterator cit = scripts.find(get_id(L, script_key));
161                        if (cit == scripts.end())
162                                throw LUAException(_T("Could not find script reference"));
163                        return (*cit).second;
164                }
165                static void set_script(lua_State *L, lua_script* script) {
166                        double id = get_id(L, script_key);
167                        scripts[id] = script;
168                }
169                static double get_id(lua_State *L, char *key) {
170                        /* retrieve a number */
171                        lua_pushstring(L, key);
172                        //lua_pushlightuserdata(L, (void*)&key);  /* push address */
173                        lua_gettable(L, LUA_REGISTRYINDEX);  /* retrieve value */
174                        double v = 0;
175                        v = lua_tonumber(L, -1);  /* convert to number */
176                        lua_pop(L,1);
177                        if (v <= 0) {
178                                v = ++last_value;
179                                lua_pushstring(L, key);
180                                //lua_pushlightuserdata(L, reinterpret_cast<void*>(&key));  /* push address */
181                                lua_pushnumber(L, v);  /* push value */
182                                /* registry[&Key] = myNumber */
183                                lua_settable(L, LUA_REGISTRYINDEX);
184                        }
185                        return v;
186
187                }
188
189        };
190        lua_manager::handler_type lua_manager::handlers;
191        lua_manager::script_type lua_manager::scripts;
192        double lua_manager::last_value = 0;
193        char lua_manager::handler_key[] = "registry.key.handler";
194        char lua_manager::script_key[] = "registry.key.sctrip";
195
196        static int register_command(lua_State *L) {
197                try {
198                        lua_handler *handler = lua_manager::get_handler(L);
199                        lua_script *script = lua_manager::get_script(L);
200                        int nargs = lua_gettop( L );
201                        if (nargs < 2) {
202                                return luaL_error(L, "Missing argument for register_command!");
203                        }
204                        if (nargs > 2) {
205                                return luaL_error(L, "To many arguments for register_command!");
206                        }
207                        handler->register_command(script, pop_string(L), pop_string(L));
208                        return 0;
209                } catch (LUAException e) {
210                        return luaL_error(L, std::string("Error: " + w2s(e.getMessage())).c_str());
211                } catch (...) {
212                        return luaL_error(L, "Unknown exception in: register_command");
213                }
214        }
215        class lua_script {
216                Lua_State L;
217                std::wstring script_;
218        public:
219                lua_script(const std::wstring file) : script_(file) {
220                        load();
221                }
222                void load() {
223                        luaL_openlibs(L);
224
225                        //Luna<Account>::Register(L);
226                        lua_register(L, "inject", inject);
227                        lua_register(L, "register_command", register_command);
228
229
230                        if (luaL_loadfile(L, strEx::wstring_to_string(script_).c_str()) != 0) {
231                                throw LUAException(_T("Failed to load script: ") + script_ + _T(": ") + s2w(lua_tostring(L, -1)));
232                        }
233
234                }
235                std::wstring get_script() const {
236                        return script_;
237                }
238                void unload() {}
239                void reload(lua_handler *handler) {
240                        unload();
241                        load();
242                        pre_load(handler);
243                }
244                void pre_load(lua_handler *handler) {
245                        lua_manager::set_handler(L, handler);
246                        lua_manager::set_script(L, this);
247                        if (lua_pcall(L, 0, 0, 0) != 0) {
248                                throw LUAException(_T("Failed to parse script: ") + script_ + _T(": ") + s2w(lua_tostring(L, -1)));
249                        }
250                }
251
252
253                NSCAPI::nagiosReturn extract_return(Lua_State &L, int arg_count,  std::wstring &message, std::wstring &perf) {
254                        // code, message, performance data
255                        if (arg_count > 3) {
256                                NSC_LOG_ERROR_STD(_T("Too many arguments return from script (only using last 3)"));
257                                lua_pop(L, arg_count-3);
258                        }
259                        if (arg_count > 2) {
260                                perf = extract_string(L);
261                                lua_pop( L, 1 );
262                        }
263                        if (arg_count > 1) {
264                                message = extract_string(L);
265                                lua_pop( L, 1 );
266                        }
267                        if (arg_count > 0) {
268                                int ret = extract_code(L);
269                                lua_pop( L, 1 );
270                                return ret;
271                        }
272                        NSC_LOG_ERROR_STD(_T("No arguments returned from script."));
273                        return NSCAPI::returnUNKNOWN;
274                }
275
276                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) {
277                        lua_manager::set_handler(L, handler);
278                        lua_manager::set_script(L, this);
279                        int nargs = lua_gettop( L );
280                        lua_getglobal(L, w2s(function).c_str());
281                        if (!lua_isfunction(L, -1)) {
282                                lua_pop(L, 1); // remove function from LUA stack
283                                throw LUAException(_T("Failed to run script: ") + script_ + _T(": Function not found: handle"));
284                        }
285                        std::wstring cmd = command.c_str();
286                        lua_pushstring(L, w2s(cmd).c_str());
287
288                        if (lua_pcall(L, 1, LUA_MULTRET, 0) != 0) {
289                                std::wstring err = strEx::string_to_wstring(lua_tostring(L, -1));
290                                NSC_LOG_ERROR_STD(_T("Failed to call main function in script: ") + script_ + _T(": ") + err);
291                                lua_pop(L, 1); // remove error message
292                                return NSCAPI::returnUNKNOWN;
293                        }
294                        return extract_return(L, lua_gettop( L )-nargs, msg, perf);
295                }
296        };
297
298
299
300
301
302}
Note: See TracBrowser for help on using the repository browser.