comparison Core/Lua/LuaContext.cpp @ 1447:5ba7471780ae

refactoring: HttpToolbox, DumpJson in Lua
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 01 Jul 2015 17:42:06 +0200
parents af112b7d9cba
children 3f7722179467
comparison
equal deleted inserted replaced
1446:8dc80ba768aa 1447:5ba7471780ae
31 31
32 32
33 #include "../PrecompiledHeaders.h" 33 #include "../PrecompiledHeaders.h"
34 #include "LuaContext.h" 34 #include "LuaContext.h"
35 35
36 #include <set>
36 #include <glog/logging.h> 37 #include <glog/logging.h>
37 #include <cassert> 38 #include <cassert>
39 #include <boost/lexical_cast.hpp>
38 40
39 extern "C" 41 extern "C"
40 { 42 {
41 #include <lualib.h> 43 #include <lualib.h>
42 #include <lauxlib.h> 44 #include <lauxlib.h>
88 90
89 return 0; 91 return 0;
90 } 92 }
91 93
92 94
93 int LuaContext::ParseJsonString(lua_State *state) 95 int LuaContext::ParseJson(lua_State *state)
94 { 96 {
95 LuaContext& that = GetLuaContext(state); 97 LuaContext& that = GetLuaContext(state);
96 98
97 int nArgs = lua_gettop(state); 99 int nArgs = lua_gettop(state);
98 if (nArgs != 1 || 100 if (nArgs != 1 ||
110 { 112 {
111 that.PushJson(value); 113 that.PushJson(value);
112 } 114 }
113 else 115 else
114 { 116 {
117 lua_pushnil(state);
118 }
119
120 return 1;
121 }
122
123
124 int LuaContext::DumpJson(lua_State *state)
125 {
126 int nArgs = lua_gettop(state);
127 if (nArgs != 1)
128 {
129 lua_pushnil(state);
130 return 1;
131 }
132
133 Json::Value json;
134 if (GetJson(json, state, 1))
135 {
136 Json::FastWriter writer;
137 std::string s = writer.write(json);
138 lua_pushstring(state, s.c_str());
139 }
140 else
141 {
142 LOG(ERROR) << "Lua: Unable to convert a JSON variable to a string";
115 lua_pushnil(state); 143 lua_pushnil(state);
116 } 144 }
117 145
118 return 1; 146 return 1;
119 } 147 }
346 throw LuaException("Unsupported JSON conversion"); 374 throw LuaException("Unsupported JSON conversion");
347 } 375 }
348 } 376 }
349 377
350 378
379 static bool CompactObjectToArray(Json::Value& result,
380 const Json::Value& source)
381 {
382 Json::Value::Members members = source.getMemberNames();
383
384 std::set<size_t> keys;
385 for (Json::Value::ArrayIndex i = 0; i < members.size(); i++)
386 {
387 try
388 {
389 size_t key = boost::lexical_cast<size_t>(members[i]);
390 keys.insert(key);
391 }
392 catch (boost::bad_lexical_cast&)
393 {
394 return false;
395 }
396 }
397
398 if (keys.size() != members.size())
399 {
400 return false;
401 }
402
403 for (size_t i = 1; i <= members.size(); i++)
404 {
405 if (keys.find(i) == keys.end())
406 {
407 return false;
408 }
409 }
410
411 result = Json::arrayValue;
412 result.resize(members.size());
413 for (size_t i = 0; i < members.size(); i++)
414 {
415 Json::Value::ArrayIndex key = boost::lexical_cast<Json::Value::ArrayIndex>(members[i]);
416 assert(key > 0);
417 result[key - 1] = source[members[i]];
418 }
419
420 return true;
421 }
422
423
424 bool LuaContext::GetJson(Json::Value& result,
425 lua_State *state,
426 int i)
427 {
428 // Caution: The order of the calls below is important, otherwise
429 // Lua considers everything as a string.
430
431 if (lua_isnil(state, i))
432 {
433 result = Json::nullValue;
434 return true;
435 }
436
437 if (lua_isboolean(state, i))
438 {
439 result = lua_toboolean(state, i) ? true : false;
440 return true;
441 }
442
443 if (lua_isnumber(state, i))
444 {
445 result = lua_tonumber(state, i);
446 return true;
447 }
448
449 if (lua_isstring(state, i))
450 {
451 result = lua_tostring(state, i);
452 return true;
453 }
454
455 if (lua_istable(state, i))
456 {
457 result = Json::objectValue;
458
459 // http://stackoverflow.com/a/6142700/881731
460 // Push another reference to the table on top of the stack (so we know
461 // where it is, and this function can work for negative, positive and
462 // pseudo indices
463 lua_pushvalue(state, i);
464 // stack now contains: -1 => table
465 lua_pushnil(state);
466 // stack now contains: -1 => nil; -2 => table
467 while (lua_next(state, -2))
468 {
469 // stack now contains: -1 => value; -2 => key; -3 => table
470 // copy the key so that lua_tostring does not modify the original
471 lua_pushvalue(state, -2);
472 // stack now contains: -1 => key; -2 => value; -3 => key; -4 => table
473 const char *key = lua_tostring(state, -1);
474
475 Json::Value item;
476 if (!GetJson(item, state, -2))
477 {
478 lua_pop(state, 3); // TODO IS THIS CORRECT?
479 return false;
480 }
481
482 result[key] = item;
483
484 // pop value + copy of key, leaving original key
485 lua_pop(state, 2);
486 // stack now contains: -1 => key; -2 => table
487 }
488 // stack now contains: -1 => table (when lua_next returns 0 it pops the key
489 // but does not push anything.)
490 // Pop table
491 lua_pop(state, 1);
492
493 // Stack is now the same as it was on entry to this function
494
495 Json::Value array;
496 if (CompactObjectToArray(array, result))
497 {
498 result = array;
499 }
500
501 return true;
502 }
503
504 return false;
505 }
506
507
351 LuaContext::LuaContext() 508 LuaContext::LuaContext()
352 { 509 {
353 lua_ = luaL_newstate(); 510 lua_ = luaL_newstate();
354 if (!lua_) 511 if (!lua_)
355 { 512 {
356 throw LuaException("Unable to create the Lua context"); 513 throw LuaException("Unable to create the Lua context");
357 } 514 }
358 515
359 luaL_openlibs(lua_); 516 luaL_openlibs(lua_);
360 lua_register(lua_, "print", PrintToLog); 517 lua_register(lua_, "print", PrintToLog);
361 lua_register(lua_, "ParseJson", ParseJsonString); 518 lua_register(lua_, "ParseJson", ParseJson);
519 lua_register(lua_, "DumpJson", DumpJson);
362 lua_register(lua_, "HttpGet", CallHttpGet); 520 lua_register(lua_, "HttpGet", CallHttpGet);
363 lua_register(lua_, "HttpPost", CallHttpPost); 521 lua_register(lua_, "HttpPost", CallHttpPost);
364 lua_register(lua_, "HttpPut", CallHttpPut); 522 lua_register(lua_, "HttpPut", CallHttpPut);
365 lua_register(lua_, "HttpDelete", CallHttpDelete); 523 lua_register(lua_, "HttpDelete", CallHttpDelete);
366 lua_register(lua_, "SetHttpCredentials", SetHttpCredentials); 524 lua_register(lua_, "SetHttpCredentials", SetHttpCredentials);