Mercurial > hg > orthanc
annotate Core/Lua/LuaContext.cpp @ 1051:92f4bf2c5d73
HTTP GET in Lua
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 23 Jul 2014 12:59:28 +0200 |
parents | b067017a8a5b |
children | cc4ff680e2a0 |
rev | line source |
---|---|
386 | 1 /** |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
689 | 3 * Copyright (C) 2012-2014 Medical Physics Department, CHU of Liege, |
386 | 4 * Belgium |
5 * | |
6 * This program is free software: you can redistribute it and/or | |
7 * modify it under the terms of the GNU General Public License as | |
8 * published by the Free Software Foundation, either version 3 of the | |
9 * License, or (at your option) any later version. | |
10 * | |
11 * In addition, as a special exception, the copyright holders of this | |
12 * program give permission to link the code of its release with the | |
13 * OpenSSL project's "OpenSSL" library (or with modified versions of it | |
14 * that use the same license as the "OpenSSL" library), and distribute | |
15 * the linked executables. You must obey the GNU General Public License | |
16 * in all respects for all of the code used other than "OpenSSL". If you | |
17 * modify file(s) with this exception, you may extend this exception to | |
18 * your version of the file(s), but you are not obligated to do so. If | |
19 * you do not wish to do so, delete this exception statement from your | |
20 * version. If you delete this exception statement from all source files | |
21 * in the program, then also delete it here. | |
22 * | |
23 * This program is distributed in the hope that it will be useful, but | |
24 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
26 * General Public License for more details. | |
27 * | |
28 * You should have received a copy of the GNU General Public License | |
29 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
30 **/ | |
31 | |
32 | |
824
a811bdf8b8eb
precompiled headers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
689
diff
changeset
|
33 #include "../PrecompiledHeaders.h" |
386 | 34 #include "LuaContext.h" |
35 | |
36 #include <glog/logging.h> | |
996
cf52f3bcb2b3
clarification of Lua classes wrt multithreading
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
824
diff
changeset
|
37 #include <cassert> |
386 | 38 |
39 extern "C" | |
40 { | |
41 #include <lualib.h> | |
42 #include <lauxlib.h> | |
43 } | |
44 | |
45 namespace Orthanc | |
46 { | |
1051 | 47 LuaContext& LuaContext::GetLuaContext(lua_State *state) |
386 | 48 { |
418
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
49 // Get the pointer to the "LuaContext" underlying object |
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
50 lua_getglobal(state, "_LuaContext"); |
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
51 assert(lua_type(state, -1) == LUA_TLIGHTUSERDATA); |
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
52 LuaContext* that = const_cast<LuaContext*>(reinterpret_cast<const LuaContext*>(lua_topointer(state, -1))); |
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
53 assert(that != NULL); |
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
54 lua_pop(state, 1); |
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
55 |
1051 | 56 return *that; |
57 } | |
58 | |
59 int LuaContext::PrintToLog(lua_State *state) | |
60 { | |
61 LuaContext& that = GetLuaContext(state); | |
62 | |
386 | 63 // http://medek.wordpress.com/2009/02/03/wrapping-lua-errors-and-print-function/ |
418
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
64 int nArgs = lua_gettop(state); |
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
65 lua_getglobal(state, "tostring"); |
386 | 66 |
67 // Make sure you start at 1 *NOT* 0 for arrays in Lua. | |
68 std::string result; | |
69 | |
70 for (int i = 1; i <= nArgs; i++) | |
71 { | |
72 const char *s; | |
418
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
73 lua_pushvalue(state, -1); |
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
74 lua_pushvalue(state, i); |
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
75 lua_call(state, 1, 1); |
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
76 s = lua_tostring(state, -1); |
386 | 77 |
78 if (result.size() > 0) | |
79 result.append(", "); | |
80 | |
81 if (s == NULL) | |
82 result.append("<No conversion to string>"); | |
83 else | |
84 result.append(s); | |
85 | |
418
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
86 lua_pop(state, 1); |
386 | 87 } |
88 | |
1002
b067017a8a5b
anonymization refactoring
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
996
diff
changeset
|
89 LOG(WARNING) << "Lua says: " << result; |
1051 | 90 that.log_.append(result); |
91 that.log_.append("\n"); | |
386 | 92 |
93 return 0; | |
94 } | |
95 | |
1051 | 96 |
97 int LuaContext::CallHttpGet(lua_State *state) | |
98 { | |
99 LuaContext& that = GetLuaContext(state); | |
100 | |
101 // Check that there is 1 string argument | |
102 int nArgs = lua_gettop(state); | |
103 if ((nArgs != 1 && nArgs != 2) || | |
104 !lua_isstring(state, 1) || | |
105 (nArgs == 2 && !lua_isboolean(state, 2))) | |
106 { | |
107 LOG(ERROR) << "Lua: Bad URL in HttpGet"; | |
108 | |
109 lua_pushstring(state, "ERROR"); | |
110 return 1; | |
111 } | |
112 | |
113 // Configure the HTTP client class | |
114 const char* url = lua_tostring(state, 1); | |
115 bool isJson = (nArgs == 2 && lua_toboolean(state, 2)); | |
116 that.httpClient_.SetMethod(HttpMethod_Get); | |
117 that.httpClient_.SetUrl(url); | |
118 | |
119 // Do the HTTP GET request | |
120 std::string str; | |
121 Json::Value json; | |
122 | |
123 try | |
124 { | |
125 if (isJson) | |
126 { | |
127 that.httpClient_.Apply(json); | |
128 } | |
129 else | |
130 { | |
131 that.httpClient_.Apply(str); | |
132 } | |
133 } | |
134 catch (OrthancException& e) | |
135 { | |
136 LOG(ERROR) << "Lua: Error in HttpGet for URL " << url << ": " << e.What(); | |
137 | |
138 lua_pushstring(state, "ERROR"); | |
139 return 1; | |
140 } | |
141 | |
142 // Return the result of the HTTP GET | |
143 if (isJson) | |
144 { | |
145 that.PushJson(json); | |
146 } | |
147 else | |
148 { | |
149 lua_pushstring(state, str.c_str()); | |
150 } | |
151 | |
152 return 1; | |
153 } | |
154 | |
155 | |
156 void LuaContext::PushJson(const Json::Value& value) | |
157 { | |
158 if (value.isString()) | |
159 { | |
160 lua_pushstring(lua_, value.asCString()); | |
161 } | |
162 else if (value.isDouble()) | |
163 { | |
164 lua_pushnumber(lua_, value.asDouble()); | |
165 } | |
166 else if (value.isInt()) | |
167 { | |
168 lua_pushinteger(lua_, value.asInt()); | |
169 } | |
170 else if (value.isUInt()) | |
171 { | |
172 lua_pushinteger(lua_, value.asUInt()); | |
173 } | |
174 else if (value.isBool()) | |
175 { | |
176 lua_pushboolean(lua_, value.asBool()); | |
177 } | |
178 else if (value.isNull()) | |
179 { | |
180 lua_pushnil(lua_); | |
181 } | |
182 else if (value.isArray()) | |
183 { | |
184 lua_newtable(lua_); | |
185 | |
186 // http://lua-users.org/wiki/SimpleLuaApiExample | |
187 for (Json::Value::ArrayIndex i = 0; i < value.size(); i++) | |
188 { | |
189 // Push the table index (note the "+1" because of Lua conventions) | |
190 lua_pushnumber(lua_, i + 1); | |
191 | |
192 // Push the value of the cell | |
193 PushJson(value[i]); | |
194 | |
195 // Stores the pair in the table | |
196 lua_rawset(lua_, -3); | |
197 } | |
198 } | |
199 else if (value.isObject()) | |
200 { | |
201 lua_newtable(lua_); | |
202 | |
203 Json::Value::Members members = value.getMemberNames(); | |
204 | |
205 for (Json::Value::Members::const_iterator | |
206 it = members.begin(); it != members.end(); ++it) | |
207 { | |
208 // Push the index of the cell | |
209 lua_pushstring(lua_, it->c_str()); | |
210 | |
211 // Push the value of the cell | |
212 PushJson(value[*it]); | |
213 | |
214 // Stores the pair in the table | |
215 lua_rawset(lua_, -3); | |
216 } | |
217 } | |
218 else | |
219 { | |
220 throw LuaException("Unsupported JSON conversion"); | |
221 } | |
222 } | |
223 | |
386 | 224 |
225 LuaContext::LuaContext() | |
226 { | |
227 lua_ = luaL_newstate(); | |
228 if (!lua_) | |
229 { | |
230 throw LuaException("Unable to create the Lua context"); | |
231 } | |
232 | |
233 luaL_openlibs(lua_); | |
234 lua_register(lua_, "print", PrintToLog); | |
1051 | 235 lua_register(lua_, "HttpGet", CallHttpGet); |
418
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
236 |
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
237 lua_pushlightuserdata(lua_, this); |
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
238 lua_setglobal(lua_, "_LuaContext"); |
386 | 239 } |
240 | |
241 | |
242 LuaContext::~LuaContext() | |
243 { | |
244 lua_close(lua_); | |
245 } | |
246 | |
247 | |
418
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
248 void LuaContext::Execute(std::string* output, |
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
249 const std::string& command) |
386 | 250 { |
418
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
251 log_.clear(); |
386 | 252 int error = (luaL_loadbuffer(lua_, command.c_str(), command.size(), "line") || |
253 lua_pcall(lua_, 0, 0, 0)); | |
254 | |
255 if (error) | |
256 { | |
257 assert(lua_gettop(lua_) >= 1); | |
258 | |
259 std::string description(lua_tostring(lua_, -1)); | |
260 lua_pop(lua_, 1); /* pop error message from the stack */ | |
261 throw LuaException(description); | |
262 } | |
418
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
263 |
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
264 if (output != NULL) |
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
265 { |
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
266 *output = log_; |
b79bf2f4ab2e
execution of lua through REST
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
397
diff
changeset
|
267 } |
386 | 268 } |
269 | |
270 | |
271 void LuaContext::Execute(EmbeddedResources::FileResourceId resource) | |
272 { | |
273 std::string command; | |
274 EmbeddedResources::GetFileResource(command, resource); | |
275 Execute(command); | |
276 } | |
397
941ea46e9e26
lua filter of new instances
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
386
diff
changeset
|
277 |
941ea46e9e26
lua filter of new instances
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
386
diff
changeset
|
278 |
941ea46e9e26
lua filter of new instances
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
386
diff
changeset
|
279 bool LuaContext::IsExistingFunction(const char* name) |
941ea46e9e26
lua filter of new instances
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
386
diff
changeset
|
280 { |
941ea46e9e26
lua filter of new instances
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
386
diff
changeset
|
281 lua_settop(lua_, 0); |
941ea46e9e26
lua filter of new instances
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
386
diff
changeset
|
282 lua_getglobal(lua_, name); |
941ea46e9e26
lua filter of new instances
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
386
diff
changeset
|
283 return lua_type(lua_, -1) == LUA_TFUNCTION; |
941ea46e9e26
lua filter of new instances
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
386
diff
changeset
|
284 } |
386 | 285 } |