1 #include "stdafx.h"
2 #include "Helper.h"
3 #include "Logger.h"
4 #include "RFXtrx.h"
5 #include "LuaHandler.h"
6 
7 extern "C" {
8 #include <lua.h>
9 #include <lualib.h>
10 #include <lauxlib.h>
11 }
12 
13 #include "../tinyxpath/xpath_processor.h"
14 
15 #include <json/json.h>
16 #include "SQLHelper.h"
17 #include "mainworker.h"
18 #include "../hardware/hardwaretypes.h"
19 #include <boost/thread.hpp>
20 
21 extern std::string szUserDataFolder;
22 
l_domoticz_updateDevice(lua_State * lua_state)23 int CLuaHandler::l_domoticz_updateDevice(lua_State* lua_state)
24 {
25 	int nargs = lua_gettop(lua_state);
26 	if (nargs >= 3 && nargs <= 5)
27 	{
28 		// Supported format ares :
29 		// - deviceId (integer), svalue (string), nvalue (string), [rssi(integer)], [battery(integer)]
30 		// - deviceId (integer), svalue (string), nvalue (integer), [rssi(integer)], [battery(integer)]
31 		if (lua_isnumber(lua_state, 1) && (lua_isstring(lua_state, 2) || lua_isnumber(lua_state, 2)) && lua_isstring(lua_state, 3))
32 		{
33 			// Extract the parameters from the lua 'updateDevice' function
34 			int ideviceId = (int)lua_tointeger(lua_state, 1);
35 			std::string nvalue = lua_tostring(lua_state, 2);
36 			std::string svalue = lua_tostring(lua_state, 3);
37 			if (((lua_isstring(lua_state, 3) && nvalue.empty()) && svalue.empty()))
38 			{
39 				_log.Log(LOG_ERROR, "CLuaHandler (updateDevice from LUA) : nvalue and svalue are empty ");
40 				return 0;
41 			}
42 
43 			// Parse
44 			int invalue = (!nvalue.empty()) ? atoi(nvalue.c_str()) : 0;
45 			int signallevel = 12;
46 			if (nargs >= 4 && lua_isnumber(lua_state, 4))
47 			{
48 				signallevel = (int)lua_tointeger(lua_state, 4);
49 			}
50 			int batterylevel = 255;
51 			if (nargs == 5 && lua_isnumber(lua_state, 5))
52 			{
53 				batterylevel = (int)lua_tointeger(lua_state, 5);
54 			}
55 			_log.Log(LOG_NORM, "CLuaHandler (updateDevice from LUA) : idx=%d nvalue=%s svalue=%s invalue=%d signallevel=%d batterylevel=%d", ideviceId, nvalue.c_str(), svalue.c_str(), invalue, signallevel, batterylevel);
56 
57 			m_mainworker.UpdateDevice(ideviceId, invalue, svalue, signallevel, batterylevel);
58 		}
59 		else
60 		{
61 			_log.Log(LOG_ERROR, "CLuaHandler (updateDevice from LUA) : Incorrect parameters type");
62 		}
63 	}
64 	else
65 	{
66 		_log.Log(LOG_ERROR, "CLuaHandler (updateDevice from LUA) : Not enough parameters");
67 	}
68 	return 0;
69 }
70 
l_domoticz_print(lua_State * lua_state)71 int CLuaHandler::l_domoticz_print(lua_State* lua_state)
72 {
73 	int nargs = lua_gettop(lua_state);
74 
75 	for (int i = 1; i <= nargs; i++)
76 	{
77 		if (lua_isstring(lua_state, i))
78 		{
79 			//std::string lstring=lua_tostring(lua_state, i);
80 			_log.Log(LOG_NORM, "CLuaHandler: udevices: %s", lua_tostring(lua_state, i));
81 		}
82 		else
83 		{
84 			/* non strings? */
85 		}
86 	}
87 	return 0;
88 }
89 
CLuaHandler(int hwdID)90 CLuaHandler::CLuaHandler(int hwdID)
91 {
92 	m_HwdID = hwdID;
93 }
94 
luaThread(lua_State * lua_state,const std::string & filename)95 void CLuaHandler::luaThread(lua_State *lua_state, const std::string &filename)
96 {
97 	int status;
98 
99 	status = lua_pcall(lua_state, 0, LUA_MULTRET, 0);
100 	report_errors(lua_state, status);
101 	lua_close(lua_state);
102 }
103 
luaStop(lua_State * L,lua_Debug * ar)104 void CLuaHandler::luaStop(lua_State *L, lua_Debug *ar)
105 {
106 	if (ar->event == LUA_HOOKCOUNT)
107 	{
108 		(void)ar;  /* unused arg. */
109 		lua_sethook(L, NULL, 0, 0);
110 		luaL_error(L, "LuaHandler: Lua script execution exceeds maximum number of lines");
111 		lua_close(L);
112 	}
113 }
114 
report_errors(lua_State * L,int status)115 void CLuaHandler::report_errors(lua_State *L, int status)
116 {
117 	if (status != 0) {
118 		_log.Log(LOG_ERROR, "CLuaHandler: %s", lua_tostring(L, -1));
119 		lua_pop(L, 1); // remove error message
120 	}
121 }
122 
executeLuaScript(const std::string & script,const std::string & content)123 bool CLuaHandler::executeLuaScript(const std::string &script, const std::string &content)
124 {
125 	std::vector<std::string> allParameters;
126 	return executeLuaScript(script, content, allParameters);
127 }
128 
executeLuaScript(const std::string & script,const std::string & content,std::vector<std::string> & allParameters)129 bool CLuaHandler::executeLuaScript(const std::string &script, const std::string &content, std::vector<std::string>& allParameters)
130 {
131 	std::stringstream lua_DirT;
132 #ifdef WIN32
133 	lua_DirT << szUserDataFolder << "scripts\\lua_parsers\\";
134 #else
135 	lua_DirT << szUserDataFolder << "scripts/lua_parsers/";
136 #endif
137 	std::string lua_Dir = lua_DirT.str();
138 
139 	lua_State *lua_state;
140 	lua_state = luaL_newstate();
141 
142 	luaL_openlibs(lua_state);
143 	lua_pushcfunction(lua_state, l_domoticz_print);
144 	lua_setglobal(lua_state, "print");
145 
146 	lua_pushcfunction(lua_state, l_domoticz_updateDevice);
147 	lua_setglobal(lua_state, "domoticz_updateDevice");
148 
149 	lua_pushcfunction(lua_state, l_domoticz_applyJsonPath);
150 	lua_setglobal(lua_state, "domoticz_applyJsonPath");
151 
152 	lua_pushcfunction(lua_state, l_domoticz_applyXPath);
153 	lua_setglobal(lua_state, "domoticz_applyXPath");
154 
155 	lua_pushinteger(lua_state, m_HwdID);
156 	lua_setglobal(lua_state, "hwdId");
157 
158 	lua_createtable(lua_state, 1, 0);
159 	lua_pushstring(lua_state, "content");
160 	lua_pushstring(lua_state, content.c_str());
161 	lua_rawset(lua_state, -3);
162 	lua_setglobal(lua_state, "request");
163 
164 	CEventSystem::_tEventQueue item;
165 	item.id = 0;
166 	m_mainworker.m_eventsystem.ExportDeviceStatesToLua(lua_state, item);
167 
168 	// Push all url parameters as a map indexed by the parameter name
169 	// Each entry will be uri[<param name>] = <param value>
170 	int totParameters = (int)allParameters.size();
171 	lua_createtable(lua_state, totParameters, 0);
172 	for (int i = 0; i < totParameters; i++)
173 	{
174 		std::vector<std::string> parameterCouple;
175 		StringSplit(allParameters[i], "=", parameterCouple);
176 		if (parameterCouple.size() == 2) {
177 			// Add an url parameter after 'url' decoding it
178 			lua_pushstring(lua_state, CURLEncode::URLDecode(parameterCouple[0]).c_str());
179 			lua_pushstring(lua_state, CURLEncode::URLDecode(parameterCouple[1]).c_str());
180 			lua_rawset(lua_state, -3);
181 		}
182 	}
183 	lua_setglobal(lua_state, "uri");
184 
185 	std::string fullfilename = lua_Dir + script;
186 	int status = luaL_loadfile(lua_state, fullfilename.c_str());
187 	if (status == 0)
188 	{
189 		lua_sethook(lua_state, luaStop, LUA_MASKCOUNT, 10000000);
190 		boost::thread aluaThread(boost::bind(&CLuaHandler::luaThread, this, lua_state, fullfilename));
191 		SetThreadName(aluaThread.native_handle(), "aluaThread");
192 		aluaThread.timed_join(boost::posix_time::seconds(10));
193 		return true;
194 	}
195 	else
196 	{
197 		report_errors(lua_state, status);
198 		lua_close(lua_state);
199 	}
200 	return false;
201 }
202