diff options
Diffstat (limited to 'Controler-afb/ctl-lua.c')
-rw-r--r-- | Controler-afb/ctl-lua.c | 325 |
1 files changed, 193 insertions, 132 deletions
diff --git a/Controler-afb/ctl-lua.c b/Controler-afb/ctl-lua.c index 71ef8b0..c1bc5f3 100644 --- a/Controler-afb/ctl-lua.c +++ b/Controler-afb/ctl-lua.c @@ -17,12 +17,12 @@ * http://www.troubleshooters.com/codecorn/lua/lua_c_calls_lua.htm#_Anatomy_of_a_Lua_Call * http://acamara.es/blog/2012/08/passing-variables-from-lua-5-2-to-c-and-vice-versa/ * https://john.nachtimwald.com/2014/07/12/wrapping-a-c-library-in-lua/ + * https://gist.github.com/SONIC3D/10388137 */ #define _GNU_SOURCE #include <stdio.h> #include <string.h> -#include <dirent.h> #include "lua.h" #include "lauxlib.h" @@ -31,24 +31,30 @@ #include "ctl-binding.h" #include "wrap-json.h" -#define LUA_FIRST_ARG 2 // when using luaL_newlib calllback receive libtable as 1st arg +#define LUA_FIST_ARG 2 // when using luaL_newlib calllback receive libtable as 1st arg #define LUA_MSG_MAX_LENGTH 255 static lua_State* luaState; - #define CTX_MAGIC 123456789 #define CTX_TOKEN "AFB_ctx" typedef struct { + char *name; + int count; + afb_event event; +} LuaAfbEvent; +static LuaAfbEvent *luaDefaultEvt; + +typedef struct { int ctxMagic; afb_req request; char *info; } LuaAfbContextT; typedef struct { - const char *callback; - const char *handle; + const char *callback; + json_object *context; } LuaCallServiceT; typedef enum { @@ -65,67 +71,6 @@ typedef enum { * https://stackoverflow.com/questions/45596493/lua-using-lua-newuserdata-from-lua-pcall */ -// List Avaliable Configuration Files -PUBLIC json_object* ScanForConfig (char* searchPath, CtlScanDirModeT mode, char *pre, char *ext) { - json_object *responseJ; - char *dirPath; - char* dirList= strdup(searchPath); - size_t extLen=0; - - void ScanDir (char *searchPath) { - DIR *dirHandle; - struct dirent *dirEnt; - dirHandle = opendir (searchPath); - if (!dirHandle) { - AFB_NOTICE ("CONFIG-SCANNING dir=%s not readable", searchPath); - return; - } - - //AFB_NOTICE ("CONFIG-SCANNING:ctl_listconfig scanning: %s", searchPath); - while ((dirEnt = readdir(dirHandle)) != NULL) { - - // recursively search embedded directories ignoring any directory starting by '.' or '_' - if (dirEnt->d_type == DT_DIR && mode == CTL_SCAN_RECURSIVE) { - char newpath[CONTROL_MAXPATH_LEN]; - if (dirEnt->d_name[0]=='.' || dirEnt->d_name[0]=='_') continue; - - strncpy(newpath, searchPath, sizeof(newpath)); - strncat(newpath, "/", sizeof(newpath)); - strncat(newpath, dirEnt->d_name, sizeof(newpath)); - ScanDir(newpath); - continue; - } - - // Unknown type is accepted to support dump filesystems - if (dirEnt->d_type == DT_REG || dirEnt->d_type == DT_UNKNOWN) { - - // check prefix and extention - size_t extIdx=strlen(dirEnt->d_name)-extLen; - if (extIdx <= 0) continue; - if (pre && !strcasestr (dirEnt->d_name, pre)) continue; - if (ext && strcasecmp (ext, &dirEnt->d_name[extIdx])) continue; - - struct json_object *pathJ = json_object_new_object(); - json_object_object_add(pathJ, "fullpath", json_object_new_string(searchPath)); - json_object_object_add(pathJ, "filename", json_object_new_string(dirEnt->d_name)); - json_object_array_add(responseJ, pathJ); - } - } - closedir(dirHandle); - } - - if (ext) extLen=strlen(ext); - responseJ = json_object_new_array(); - - // loop recursively on dir - for (dirPath= strtok(dirList, ":"); dirPath && *dirPath; dirPath=strtok(NULL,":")) { - ScanDir (dirPath); - } - - free (dirList); - return (responseJ); -} - STATIC LuaAfbContextT *LuaCtxCheck (lua_State *luaState, int index) { LuaAfbContextT *afbContext; //luaL_checktype(luaState, index, LUA_TUSERDATA); @@ -159,37 +104,80 @@ STATIC void LuaCtxFree (LuaAfbContextT *afbContext) { free (afbContext->info); } -STATIC int LuaPushArgument (json_object *arg) { - - switch (json_object_get_type(arg)) { - case json_type_object: + +STATIC void LuaDumpArgs(lua_State* luaState, int start) { + int count = lua_gettop(luaState); + + for (int idx=start; idx <= count; idx++) { + int luaType = lua_type(luaState, idx); + switch(luaType) { + case LUA_TNUMBER: + AFB_NOTICE ("idx=%d type=%s value=%d", idx, lua_typename(luaState, luaType), (int)lua_tonumber(luaState, idx)); + break; + case LUA_TBOOLEAN: + AFB_NOTICE ("idx=%d type=%s value=%d", idx, lua_typename(luaState, luaType), lua_toboolean(luaState, idx)); + break; + case LUA_TSTRING: + AFB_NOTICE ("idx=%d type=%s value=%s", idx, lua_typename(luaState, luaType), lua_tostring(luaState, idx)); + break; + case LUA_TTABLE: { + AFB_NOTICE ("-++-- START luatable idx=%d ", idx); + (void)LuaDumpArgs(luaState, idx+1); + AFB_NOTICE ("-++-- END luatable idx=%d ", idx); + break; + } + default: + AFB_NOTICE ("PopOneArg: script returned Unknown/Unsupported idx=%d type:%d/%s", idx, luaType, lua_typename(luaState, luaType)); + } + } +} + +// Push a json structure on the stack as a LUA table +STATIC int LuaPushArgument (json_object *argsJ) { + + json_type jtype= json_object_get_type(argsJ); + switch (jtype) { + case json_type_object: { lua_newtable (luaState); - json_object_object_foreach (arg, key, val) { + json_object_object_foreach (argsJ, key, val) { int done = LuaPushArgument (val); if (done) { - lua_pushstring(luaState, key); // table.key = val - lua_settable(luaState, -3); + lua_setfield(luaState,-2, key); } } - break; + } + case json_type_array: { + int length= json_object_array_length(argsJ); + lua_newtable (luaState); + for (int idx=0; idx < length; idx ++) { + json_object *val=json_object_array_get_idx(argsJ, idx); + LuaPushArgument (val); + lua_seti (luaState,-2, idx); + } + break; + } case json_type_int: - lua_pushinteger(luaState, json_object_get_int(arg)); + lua_pushinteger(luaState, json_object_get_int(argsJ)); break; case json_type_string: - lua_pushstring(luaState, json_object_get_string(arg)); + lua_pushstring(luaState, json_object_get_string(argsJ)); break; case json_type_boolean: - lua_pushboolean(luaState, json_object_get_boolean(arg)); + lua_pushboolean(luaState, json_object_get_boolean(argsJ)); break; case json_type_double: - lua_pushnumber(luaState, json_object_get_double(arg)); + lua_pushnumber(luaState, json_object_get_double(argsJ)); break; + case json_type_null: + AFB_WARNING("LuaPushArgument: NULL object type %s", json_object_get_string(argsJ)); + return 0; + break; + default: - AFB_ERROR("LuaPushArgument: unsupported Json object type %s", json_object_get_string(arg)); + AFB_ERROR("LuaPushArgument: unsupported Json object type %s", json_object_get_string(argsJ)); return 0; - } - + } return 1; } @@ -251,7 +239,7 @@ static json_object *LuaPopArgs (lua_State* luaState, int start) { json_object *responseJ; int stop = lua_gettop(luaState); - if(stop-start <=0) return NULL; + if(stop-start <0) return NULL; // start at 2 because we are using a function array lib if (start == stop) { @@ -267,15 +255,16 @@ static json_object *LuaPopArgs (lua_State* luaState, int start) { return responseJ; } - STATIC void LuaFormatMessage(lua_State* luaState, LuaAfbMessageT action) { char *message; - json_object *responseJ= LuaPopArgs(luaState, LUA_FIRST_ARG); + json_object *responseJ= LuaPopArgs(luaState, LUA_FIST_ARG); if (!responseJ) { - message="--"; + message="-- Empty Message ???"; goto PrintMessage; - } + } + + AFB_NOTICE ("**** responseJ=%s", json_object_get_string(responseJ)); // if we have only on argument just return the value. if (json_object_get_type(responseJ)!=json_type_array || json_object_array_length(responseJ) <2) { @@ -297,15 +286,18 @@ STATIC void LuaFormatMessage(lua_State* luaState, LuaAfbMessageT action) { switch (format[++idx]) { case 'd': - targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"%d", json_object_get_int(slotJ)); + 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"); break; case 'f': - targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"%f", json_object_get_double(slotJ)); + 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"); break; case 's': default: - targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"%s", json_object_get_string(slotJ)); + 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"); } } else { @@ -359,11 +351,11 @@ STATIC int LuaPrintDebug(lua_State* luaState) { } STATIC int LuaAfbSuccess(lua_State* luaState) { - LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIRST_ARG); + LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG); if (!afbContext) goto OnErrorExit; // ignore context argument - json_object *responseJ= LuaPopArgs(luaState, LUA_FIRST_ARG+1); + json_object *responseJ= LuaPopArgs(luaState, LUA_FIST_ARG+1); afb_req_success(afbContext->request, responseJ, NULL); @@ -376,10 +368,10 @@ STATIC int LuaAfbSuccess(lua_State* luaState) { } STATIC int LuaAfbFail(lua_State* luaState) { - LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIRST_ARG); + LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG); if (!afbContext) goto OnErrorExit; - json_object *responseJ= LuaPopArgs(luaState, LUA_FIRST_ARG+1); + json_object *responseJ= LuaPopArgs(luaState, LUA_FIST_ARG+1); afb_req_fail(afbContext->request, afbContext->info, json_object_get_string(responseJ)); @@ -393,51 +385,43 @@ STATIC int LuaAfbFail(lua_State* luaState) { STATIC void LuaAfbServiceCB(void *handle, int iserror, struct json_object *responseJ) { LuaCallServiceT *contextCB= (LuaCallServiceT*)handle; + int count=1; - // load function (should exist in CONTROL_PATH_LUA lua_getglobal(luaState, contextCB->callback); - + // push error status & response lua_pushboolean(luaState, iserror); - (void)LuaPushArgument(responseJ); + count+= LuaPushArgument(responseJ); + count+= LuaPushArgument(contextCB->context); + + AFB_NOTICE ("*** context=%s", json_object_get_string(contextCB->context)); - int err=lua_pcall(luaState, 2, LUA_MULTRET, 0); + + int err=lua_pcall(luaState, count, LUA_MULTRET, 0); if (err) { AFB_ERROR ("LUA-SERICE-CB:FAIL response=%s err=%s", json_object_get_string(responseJ), lua_tostring(luaState,-1) ); } } + STATIC int LuaAfbService(lua_State* luaState) { int count = lua_gettop(luaState); - // retrieve userdate context - LuaAfbContextT *afbContext= luaL_checkudata(luaState, 1, "CTX_TOKEN"); - if (!afbContext) { - lua_pushliteral (luaState, "LuaAfbServiceCall-Hoops no CTX_TOKEN"); - goto OnErrorExit; - } - + // note: argument start at 2 because of AFB: table if (count <5 || !lua_isstring(luaState, 2) || !lua_isstring(luaState, 3) || !lua_istable(luaState, 4) || !lua_isstring(luaState, 5)) { - lua_pushliteral (luaState, "LuaAfbServiceCall-Syntax is AFB_service_call (api, verb, query, callback, handle"); + lua_pushliteral (luaState, "LuaAfbServiceCall-Syntax is AFB:service_call (api, verb, query, callback, handle ...."); goto OnErrorExit; } + // get api/verb+query + const char *api = lua_tostring(luaState,2); + const char *verb= lua_tostring(luaState,3); + json_object *queryJ= LuaTableToJson(luaState, 4); + LuaCallServiceT *contextCB = calloc (1, sizeof(LuaCallServiceT)); + contextCB->callback= lua_tostring(luaState, 5); + contextCB->context = LuaPopArgs(luaState, 6); - // get api/verb+query - const char *api = lua_tostring(luaState,1); - const char *verb= lua_tostring(luaState,2); - json_object *queryJ= LuaTableToJson(luaState, 3); - if (!queryJ) goto OnErrorExit; - - if (count >= 6) { - if (!lua_istable(luaState, 6)) { - lua_pushliteral (luaState, "LuaAfbServiceCall-Syntax optional handle should be a table"); - goto OnErrorExit; - } - contextCB->handle= lua_tostring(luaState, 5); - } - afb_service_call(api, verb, queryJ, LuaAfbServiceCB, contextCB); return 0; // no value return @@ -445,26 +429,84 @@ STATIC int LuaAfbService(lua_State* luaState) { OnErrorExit: lua_error(luaState); return 1; +} +STATIC int LuaAfbMakeEvent(lua_State* luaState) { + int count = lua_gettop(luaState); + LuaAfbEvent *afbevt=calloc(1,sizeof(LuaAfbEvent)); + + if (count != 1 || !lua_isstring(luaState, 1)) { + lua_pushliteral (luaState, "LuaAfbMakeEvent-Syntax is evtHandle= AFB:event ('myEventName')"); + goto OnErrorExit; + } + + // event name should be the only argument + afbevt->name= strdup (lua_tostring(luaState,1)); + + // create a new binder event + afbevt->event = afb_daemon_make_event(afbevt->name); + if (!afb_event_is_valid(afbevt->event)) { + lua_pushliteral (luaState, "LuaAfbMakeEvent-Fail to Create Binder event"); + goto OnErrorExit; + } + + // push event handler as a LUA opaque handle + lua_pushlightuserdata(luaState, afbevt); + return 1; + + OnErrorExit: + lua_error(luaState); + return 1; +} + +STATIC int LuaAfbPushEvent(lua_State* luaState) { + LuaAfbEvent *afbevt; + int index; + + // if no private event handle then use default binding event + if (lua_islightuserdata(luaState, 1)) { + afbevt = (LuaAfbEvent*) lua_touserdata(luaState, 1); + index=1; + } else { + index=2; + afbevt=luaDefaultEvt; + } + + if (!lua_isstring(luaState, index)) { + lua_pushliteral (luaState, "LuaAfbPushEvent-Syntax is AFB:signal ([evtHandle], 'myEventName', 'data-1', ... 'data-n')"); + goto OnErrorExit; + } + + // use every other arguments as event parameters + index++; + json_object *ctlEventJ= LuaTableToJson(luaState, index); + + int done = afb_event_push(afbevt->event, ctlEventJ); + if (!done) { + lua_pushliteral (luaState, "LuaAfbPushEvent-Fail to Push Binder event"); + AFB_ERROR ("LuaAfbPushEvent-Fail to Push Binder event=%s count=%d", afbevt->name, afbevt->count); + goto OnErrorExit; + } + afbevt->count++; + return 0; + + OnErrorExit: + lua_error(luaState); + return 1; } // Generated some fake event based on watchdog/counter -PUBLIC int LuaCallFunc (afb_req request, DispatchActionT *action) { +PUBLIC int LuaCallFunc (DispatchActionT *action, json_object *queryJ) { int err, count=0; - json_object* queryJ = afb_req_json(request); json_object* argsJ = action->argsJ; const char* func = action->call; // load function (should exist in CONTROL_PATH_LUA lua_getglobal(luaState, func); - // Push AFB client context on the stack - LuaAfbContextT *afbContext= LuaCtxPush(luaState, request, func); - if (!afbContext) goto OnErrorExit; - // push argsJ on the stack if (json_object_get_type(argsJ) != json_type_array) { count+= LuaPushArgument (argsJ); @@ -473,7 +515,7 @@ PUBLIC int LuaCallFunc (afb_req request, DispatchActionT *action) { count += LuaPushArgument (json_object_array_get_idx(argsJ, idx)); } } - + // push queryJ on the stack if (json_object_get_type(queryJ) != json_type_array) { count+= LuaPushArgument (queryJ); @@ -483,8 +525,8 @@ PUBLIC int LuaCallFunc (afb_req request, DispatchActionT *action) { } } - // effectively exec LUA code (afb_reply/fail done later from callback) - err=lua_pcall(luaState, count+1, 1, 0); + // effectively exec LUA script code + err=lua_pcall(luaState, count, 1, 0); if (err) { AFB_ERROR("LuaCallFunc Fail calling %s error=%s", func, lua_tostring(luaState,-1)); goto OnErrorExit; @@ -498,7 +540,8 @@ PUBLIC int LuaCallFunc (afb_req request, DispatchActionT *action) { return -1; } -// Generated some fake event based on watchdog/counter + +// Execute LUA code from recieved API request STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { int err, count=0; @@ -551,7 +594,7 @@ STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { break; } - case LUA_DOSCRIPT: { + case LUA_DOSCRIPT: { // Fulup need to fix argument passing const char *script; json_object *args; int index; @@ -655,15 +698,24 @@ static const luaL_Reg afbFunction[] = { {"service", LuaAfbService}, {"success", LuaAfbSuccess}, {"fail" , LuaAfbFail}, + {"event" , LuaAfbMakeEvent}, + {"signal" , LuaAfbPushEvent}, + {NULL, NULL} /* sentinel */ }; // Create Binding Event at Init PUBLIC int LuaLibInit () { int err, index; - + // search for default policy config file - json_object *luaScriptPathJ = ScanForConfig(CONTROL_LUA_PATH , CTL_SCAN_RECURSIVE, "onload", "lua"); + char fullprefix[CONTROL_MAXPATH_LEN]; + strncpy (fullprefix, CONTROL_CONFIG_PRE, sizeof(fullprefix)); + strncat (fullprefix, "-", sizeof(fullprefix)); + strncat (fullprefix, GetBinderName(), sizeof(fullprefix)); + strncat (fullprefix, "-", sizeof(fullprefix)); + + json_object *luaScriptPathJ = ScanForConfig(CONTROL_LUA_PATH , CTL_SCAN_RECURSIVE, fullprefix, "lua"); // open a new LUA interpretor luaState = luaL_newstate(); @@ -679,6 +731,15 @@ PUBLIC int LuaLibInit () { luaL_newlib(luaState, afbFunction); lua_setglobal(luaState, "AFB"); + // create default lua event to send test pause/resume + luaDefaultEvt=calloc(1,sizeof(LuaAfbEvent)); + luaDefaultEvt->name=CONTROL_LUA_EVENT; + luaDefaultEvt->event = afb_daemon_make_event(CONTROL_LUA_EVENT); + if (!afb_event_is_valid(luaDefaultEvt->event)) { + AFB_ERROR ("POLCTL_INIT: Cannot register lua-events=%s ", CONTROL_LUA_EVENT); + goto OnErrorExit;; + } + // load+exec any file found in LUA search path for (index=0; index < json_object_array_length(luaScriptPathJ); index++) { json_object *entryJ=json_object_array_get_idx(luaScriptPathJ, index); |