diff options
author | Romain Forlot <romain.forlot@iot.bzh> | 2018-05-06 14:24:42 +0200 |
---|---|---|
committer | Romain Forlot <romain.forlot@iot.bzh> | 2018-12-13 15:02:54 +0100 |
commit | 6fed20d35d556afa95537a2be0b0efc8a2dd24c7 (patch) | |
tree | ab073906b708cfb2fd7811de5e440e27515087da /ctl-lib/ctl-lua.c | |
parent | fc2e5bc18026460bddcfd84c74e880193079a5c9 (diff) |
Upgrade config schema
Change the way to load LUA scripts. They are now considerate
as Plugin and loads with them.
This imply rework of how to search and find plugins as
well as the way to load LUA.
Also load an harcoded LUA scripts providing LUA helpers
and managing global variables lock unlock mechanism
Change-Id: I64e38aa27278d0cfdca787155db2d0c89953f905
Signed-off-by: Romain Forlot <romain.forlot@iot.bzh>
Diffstat (limited to 'ctl-lib/ctl-lua.c')
-rw-r--r-- | ctl-lib/ctl-lua.c | 319 |
1 files changed, 183 insertions, 136 deletions
diff --git a/ctl-lib/ctl-lua.c b/ctl-lib/ctl-lua.c index 757956e..d5c2975 100644 --- a/ctl-lib/ctl-lua.c +++ b/ctl-lib/ctl-lua.c @@ -36,6 +36,7 @@ #define JSON_ERROR (json_object*)-1 +extern CtlLua2cFuncT *ctlLua2cFunc; static lua_State* luaState; #ifndef CTX_MAGIC @@ -299,7 +300,7 @@ STATIC int LuaFormatMessage(lua_State* luaState, int verbosity, int level) { const char *format = json_object_get_string(json_object_array_get_idx(responseJ, 0)); int arrayIdx=1; - int targetIdx=0; + int uidIdx=0; for (int idx=0; format[idx] !='\0'; idx++) { @@ -310,43 +311,43 @@ STATIC int LuaFormatMessage(lua_State* luaState, int verbosity, int level) { switch (format[++idx]) { case 'd': - if (slotJ) targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"%d", json_object_get_int(slotJ)); - else targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"nil"); + if (slotJ) uidIdx += snprintf (&message[uidIdx], LUA_MSG_MAX_LENGTH-uidIdx,"%d", json_object_get_int(slotJ)); + else uidIdx += snprintf (&message[uidIdx], LUA_MSG_MAX_LENGTH-uidIdx,"nil"); arrayIdx++; break; case 'f': - if (slotJ) targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"%f", json_object_get_double(slotJ)); - else targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"nil"); + if (slotJ) uidIdx += snprintf (&message[uidIdx], LUA_MSG_MAX_LENGTH-uidIdx,"%f", json_object_get_double(slotJ)); + else uidIdx += snprintf (&message[uidIdx], LUA_MSG_MAX_LENGTH-uidIdx,"nil"); arrayIdx++; break; case'%': - message[targetIdx]='%'; - targetIdx++; + message[uidIdx]='%'; + uidIdx++; break; case 'A': - targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"level: %s", source->uid); + uidIdx += snprintf (&message[uidIdx], LUA_MSG_MAX_LENGTH-uidIdx,"level: %s", source->uid); break; case 's': default: - if (slotJ) targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"%s", json_object_get_string(slotJ)); - else targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"nil"); + if (slotJ) uidIdx += snprintf (&message[uidIdx], LUA_MSG_MAX_LENGTH-uidIdx,"%s", json_object_get_string(slotJ)); + else uidIdx += snprintf (&message[uidIdx], LUA_MSG_MAX_LENGTH-uidIdx,"nil"); arrayIdx++; } } else { - if (targetIdx >= LUA_MSG_MAX_LENGTH) { + if (uidIdx >= LUA_MSG_MAX_LENGTH) { AFB_ApiWarning (source->api, "LuaFormatMessage: message[%s] owerverflow LUA_MSG_MAX_LENGTH=%d", format, LUA_MSG_MAX_LENGTH); - targetIdx --; // move backward for EOL + uidIdx --; // move backward for EOL break; } else { - message[targetIdx++] = format[idx]; + message[uidIdx++] = format[idx]; } } } - message[targetIdx]='\0'; + message[uidIdx]='\0'; PrintMessage: // TBD: __file__ and __line__ should match LUA source code @@ -695,10 +696,10 @@ PUBLIC int LuaCallFunc (CtlSourceT *source, CtlActionT *action, json_object *que int err, count; - json_object* argsJ = action->argsJ; - const char* func = action->exec.lua.funcname; + json_object* argsJ = action->argsJ; + const char* func = action->exec.lua.funcname; - // load function (should exist in CONTROL_PATH_LUA + // load function (should exist in CONTROL_PATH_LUA) lua_getglobal(luaState, func); // push source on the stack @@ -737,145 +738,178 @@ PUBLIC int LuaCallFunc (CtlSourceT *source, CtlActionT *action, json_object *que return -1; } +PUBLIC int luaLoadScript(const char *luaScriptPath) +{ + int err = luaL_loadfile(luaState, luaScriptPath); + if (err) { + AFB_ApiError(source->api, "LUA-DOSCRIPT HOOPs Error in LUA loading scripts=%s err=%s", luaScriptPath, lua_tostring(luaState,-1)); + return err; + } -// Execute LUA code from received API request -STATIC void LuaDoAction (LuaDoActionT action, AFB_ReqT request) { + // Script was loaded we need to parse to make it executable + err = lua_pcall(luaState, 0, 0, 0); + if (err) { + AFB_ApiError(source->api, "LUA-DOSCRIPT:FAIL to load %s", luaScriptPath); + return err; + } - int err, count=0; - CtlSourceT *source = alloca(sizeof(CtlSourceT)); - source->request = request; + return err; +} - json_object* queryJ = AFB_ReqJson(request); +STATIC int LuaDoScript(json_object *queryJ, CtlSourceT *source) +{ + const char *uid = NULL, *func = NULL; + char luaScriptPath[CONTROL_MAXPATH_LEN]; + char *filename, *fullpath; + int index, err = 0; + json_object *argsJ=NULL; + static json_object *luaScriptPathJ = NULL; + if (!queryJ) { + return -1; + } - switch (action) { + err= wrap_json_unpack (queryJ, "{s:s,s?s,s?s,s?o !}", + "uid", &uid, + "spath",&luaScriptPathJ, + "function",&func, + "args",&argsJ); - case LUA_DOSTRING: { - const char *script = json_object_get_string(queryJ); - err=luaL_loadstring(luaState, script); - if (err) { - AFB_ApiError(source->api, "LUA-DO-COMPILE:FAIL String=%s err=%s", script, lua_tostring(luaState,-1) ); - goto OnErrorExit; - } - // Push AFB client context on the stack - LuaAfbSourceT *afbSource= LuaSourcePush(luaState, source); - if (!afbSource) goto OnErrorExit; + if (err) { + return -1; + } - break; + // search for filename=script in CONTROL_LUA_PATH + if (!luaScriptPathJ) { + strncpy(luaScriptPath,CONTROL_DOSCRIPT_PRE, strlen(CONTROL_DOSCRIPT_PRE)+1); + strncat(luaScriptPath,"-", strlen("-")); + strncat(luaScriptPath,uid, strlen(uid)); + luaScriptPathJ= ScanForConfig(luaScriptPath , CTL_SCAN_RECURSIVE, luaScriptPath, ".lua"); + } + + for (index=0; index < json_object_array_length(luaScriptPathJ); index++) { + json_object *entryJ=json_object_array_get_idx(luaScriptPathJ, index); + + err= wrap_json_unpack (entryJ, "{s:s, s:s !}", "fullpath", &fullpath,"filename", &filename); + if (err) { + AFB_ApiError(source->api, "LUA-DOSCRIPT-SCAN:HOOPs invalid config file path = %s", json_object_get_string(entryJ)); + return -2; } - case LUA_DOCALL: { - const char *func; - json_object *argsJ=NULL; + // Ignoring other found script. Only take the first one. + if (!index) { + strncpy (luaScriptPath, fullpath, strlen(fullpath)+1); + strncat (luaScriptPath, "/", strlen("/")); + strncat (luaScriptPath, filename, strlen(filename)); + } + } - err= wrap_json_unpack (queryJ, "{s:s, s?o !}", "target", &func, "args", &argsJ); - if (err) { - AFB_ApiError(source->api, "LUA-DOCALL-SYNTAX missing target|args query=%s", json_object_get_string(queryJ)); - goto OnErrorExit; - } + err = luaLoadScript(luaScriptPath); + if(err) + return err; - // load function (should exist in CONTROL_PATH_LUA - lua_getglobal(luaState, func); + // if no func name given try to deduct from filename + if (!func && (func=(char*)GetMidleName(filename))!=NULL) { + strncpy(luaScriptPath,"_", strlen("_")+1); + strncat(luaScriptPath,func, strlen(func)); + func=luaScriptPath; + } + if (!func) { + AFB_ApiError(source->api, "LUA-DOSCRIPT:FAIL to deduct funcname from %s", filename); + return -5; + } - // Push AFB client context on the stack - LuaAfbSourceT *afbSource= LuaSourcePush(luaState, source); - if (!afbSource) goto OnErrorExit; + // load function (should exist in CONTROL_PATH_LUA + lua_getglobal(luaState, func); - // push query on the stack - if (!argsJ) { - lua_pushnil(luaState); - count++; - } else { - count+= LuaPushArgument (source, argsJ); - } + // Push AFB client context on the stack + LuaAfbSourceT *afbSource = LuaSourcePush(luaState, source); + if (!afbSource) + return -6; - break; - } + return 0; +} - case LUA_DOSCRIPT: { // Fulup need to fix argument passing - char *filename; char*fullpath; - char luaScriptPath[CONTROL_MAXPATH_LEN]; - int index; - - // scan luascript search path once - static json_object *luaScriptPathJ =NULL; - - // extract value from query - const char *target=NULL,*func=NULL; - json_object *argsJ=NULL; - err= wrap_json_unpack (queryJ, "{s:s,s?s,s?s,s?o !}", - "target", &target, - "path",&luaScriptPathJ, - "function",&func, - "args",&argsJ); - if (err) { - AFB_ApiError(source->api, "LUA-DOSCRIPT-SYNTAX:missing target|[path]|[function]|[args] query=%s", json_object_get_string(queryJ)); - goto OnErrorExit; - } +STATIC int LuaDoCall(json_object *queryJ, CtlSourceT *source) +{ + int err = 0; + int count = 0; + const char *func; + json_object *argsJ = NULL; - // search for filename=script in CONTROL_LUA_PATH - if (!luaScriptPathJ) { - strncpy(luaScriptPath,CONTROL_DOSCRIPT_PRE, strlen(CONTROL_DOSCRIPT_PRE)+1); - strncat(luaScriptPath,"-", strlen("-")); - strncat(luaScriptPath,target, strlen(target)); - luaScriptPathJ= ScanForConfig(CONTROL_LUA_PATH , CTL_SCAN_RECURSIVE,luaScriptPath,".lua"); - } - for (index=0; index < json_object_array_length(luaScriptPathJ); index++) { - json_object *entryJ=json_object_array_get_idx(luaScriptPathJ, index); + if(!queryJ) + return -1; - err= wrap_json_unpack (entryJ, "{s:s, s:s !}", "fullpath", &fullpath,"filename", &filename); - if (err) { - AFB_ApiError(source->api, "LUA-DOSCRIPT-SCAN:HOOPs invalid config file path = %s", json_object_get_string(entryJ)); - goto OnErrorExit; - } + err = wrap_json_unpack(queryJ, "{s:s, s?o !}", "uid", &func, "args", &argsJ); + if (err) + return -2; - if (index > 0) AFB_ApiWarning(source->api, "LUA-DOSCRIPT-SCAN:Ignore second script=%s path=%s", filename, fullpath); - else { - strncpy (luaScriptPath, fullpath, strlen(fullpath)+1); - strncat (luaScriptPath, "/", strlen("/")); - strncat (luaScriptPath, filename, strlen(filename)); - } - } + // load function (should exist in CONTROL_PATH_LUA + lua_getglobal(luaState, func); - err= luaL_loadfile(luaState, luaScriptPath); - if (err) { - AFB_ApiError(source->api, "LUA-DOSCRIPT HOOPs Error in LUA loading scripts=%s err=%s", luaScriptPath, lua_tostring(luaState,-1)); - goto OnErrorExit; - } + // Push AFB client context on the stack + LuaAfbSourceT *afbSource= LuaSourcePush(luaState, source); + if (!afbSource) + return -3; - // script was loaded we need to parse to make it executable - err=lua_pcall(luaState, 0, 0, 0); - if (err) { - AFB_ApiError(source->api, "LUA-DOSCRIPT:FAIL to load %s", luaScriptPath); - goto OnErrorExit; - } + // push query on the stack + if (!argsJ) { + lua_pushnil(luaState); + count++; + } else { + count+= LuaPushArgument (source, argsJ); + } - // if no func name given try to deduct from filename - if (!func && (func=(char*)GetMidleName(filename))!=NULL) { - strncpy(luaScriptPath,"_", strlen("_")+1); - strncat(luaScriptPath,func, strlen(func)); - func=luaScriptPath; - } - if (!func) { - AFB_ApiError(source->api, "LUA-DOSCRIPT:FAIL to deduct funcname from %s", filename); - goto OnErrorExit; - } + return count; +} - // load function (should exist in CONTROL_PATH_LUA - lua_getglobal(luaState, func); +STATIC int LuaDoString(const char *script, CtlSourceT *source) +{ + int err = 0; - // Push AFB client context on the stack - LuaAfbSourceT *afbSource= LuaSourcePush(luaState, source); - if (!afbSource) goto OnErrorExit; + err = luaL_loadstring(luaState, script); + if (err) + return -1; - // push function arguments - if (!argsJ) { - lua_pushnil(luaState); - count++; - } else { - count+= LuaPushArgument(source, argsJ); - } + // Push AFB client context on the stack + if(source) { + LuaAfbSourceT *afbSource= LuaSourcePush(luaState, source); + if (!afbSource) + return -2; + } + return 0; +} + +// Execute LUA code from received API request +STATIC void LuaDoAction (LuaDoActionT action, AFB_ReqT request) { + int err, count=0; + CtlSourceT *source = alloca(sizeof(CtlSourceT)); + source->request = request; + + json_object* queryJ = AFB_ReqJson(request); + + switch (action) { + + case LUA_DOSTRING: { + const char *script = json_object_get_string(queryJ); + count = LuaDoString(script, source); + if(count) + AFB_ApiError(source->api, "DOSTRING goes wrong err=%d, String=%s ", count, script); + break; + } + + case LUA_DOCALL: { + count = LuaDoCall(queryJ, source); + if(count) + AFB_ApiError(source->api, "DOCALL goes wrong, error = %d, query=%s", count, json_object_get_string(queryJ)); + break; + } + + case LUA_DOSCRIPT: { // Fulup need to fix argument passing + count = LuaDoScript(queryJ, source); + if(count) + AFB_ApiError(source->api, "DOSCRIPT goes wrong error=%d query=%s", count, json_object_get_string(queryJ)); break; } @@ -884,8 +918,8 @@ STATIC void LuaDoAction (LuaDoActionT action, AFB_ReqT request) { goto OnErrorExit; } - // effectively exec LUA code (afb_reply/fail done later from callback) - err=lua_pcall(luaState, count+1, 0, 0); + if(count >= 0) + err=lua_pcall(luaState, count+1, 0, 0); if (err) { AFB_ApiError(source->api, "LUA-DO-EXEC:FAIL query=%s err=%s", json_object_get_string(queryJ), lua_tostring(luaState,-1)); goto OnErrorExit; @@ -1214,7 +1248,7 @@ PUBLIC void LuaL2cNewLib(luaL_Reg *l2cFunc, int count) { luaL_checkversion(luaState); lua_createtable(luaState, 0, count+1); luaL_setfuncs(luaState,l2cFunc,0); - lua_setglobal(luaState, "_lua2c"); + lua_setglobal(luaState, "L2C"); } static const luaL_Reg afbFunction[] = { @@ -1242,7 +1276,8 @@ static const luaL_Reg afbFunction[] = { // Load Lua Interpreter PUBLIC int LuaConfigLoad (AFB_ApiT apiHandle) { - static int luaLoaded=0; + static int luaLoaded=0, err = 0; + //int err = 0; // Lua loads only once if (luaLoaded) return 0; @@ -1271,6 +1306,13 @@ PUBLIC int LuaConfigLoad (AFB_ApiT apiHandle) { TIMER_MAGIC=CtlConfigMagicNew(); #endif + // Load LUA utils functions. + err = LuaDoString(lua_utils, NULL); + if(err) { + AFB_ApiError(apiHandle, "Error loading lua_utils default functions.%s, %d", lua_utils, err); + return -1; + } + return 0; OnErrorExit: @@ -1283,6 +1325,11 @@ PUBLIC int LuaConfigExec (AFB_ApiT apiHandle, const char* prefix) { int err, index; + // create L2C mapping before any LUA script is loaded + if (ctlLua2cFunc && ctlLua2cFunc->l2cCount) { + LuaL2cNewLib (ctlLua2cFunc->l2cFunc, ctlLua2cFunc->l2cCount); + } + // search for default policy config files char fullprefix[CONTROL_MAXPATH_LEN] = ""; if(prefix) @@ -1293,7 +1340,7 @@ PUBLIC int LuaConfigExec (AFB_ApiT apiHandle, const char* prefix) { strncat (fullprefix, "-", strlen("-")); const char *dirList= getenv("CONTROL_LUA_PATH"); - if (!dirList) dirList=CONTROL_LUA_PATH; + //if (!dirList) dirList=CONTROL_LUA_PATH; // special case for no lua even when avaliable if (!strcasecmp ("/dev/null", dirList)) { |