diff options
Diffstat (limited to 'Controler-afb')
-rw-r--r-- | Controler-afb/CMakeLists.txt | 3 | ||||
-rw-r--r-- | Controler-afb/README.md | 234 | ||||
-rw-r--r-- | Controler-afb/ctl-apidef.h | 71 | ||||
-rw-r--r-- | Controler-afb/ctl-apidef.json | 48 | ||||
-rw-r--r-- | Controler-afb/ctl-binding.h | 12 | ||||
-rw-r--r-- | Controler-afb/ctl-dispatch.c | 1 | ||||
-rw-r--r-- | Controler-afb/ctl-events.c | 2 | ||||
-rw-r--r-- | Controler-afb/ctl-lua.c | 117 | ||||
-rw-r--r-- | Controler-afb/ctl-misc.c | 122 |
9 files changed, 342 insertions, 268 deletions
diff --git a/Controler-afb/CMakeLists.txt b/Controler-afb/CMakeLists.txt index 4fb97b2..78e66c8 100644 --- a/Controler-afb/CMakeLists.txt +++ b/Controler-afb/CMakeLists.txt @@ -33,7 +33,7 @@ endmacro(SET_TARGET_GENSKEL) PROJECT_TARGET_ADD(control-afb) # Define project Targets - ADD_LIBRARY(${TARGET_NAME} MODULE ctl-binding.c ctl-events.c ctl-dispatch.c ctl-lua.c ctl-misc.c) + ADD_LIBRARY(${TARGET_NAME} MODULE ctl-binding.c ctl-events.c ctl-dispatch.c ctl-lua.c) # Generate API-v2 hat from OpenAPI json definition SET_TARGET_GENSKEL(${TARGET_NAME} ctl-apidef) @@ -70,6 +70,7 @@ PROJECT_TARGET_ADD(audio-plugin-sample) # Library dependencies (include updates automatically) TARGET_LINK_LIBRARIES(${TARGET_NAME} + audio-common ${link_libraries} ) diff --git a/Controler-afb/README.md b/Controler-afb/README.md new file mode 100644 index 0000000..3274ede --- /dev/null +++ b/Controler-afb/README.md @@ -0,0 +1,234 @@ +Controler AAAA(AGL Advance Audio Controler) and more. +------------------------------------------------------------ + + * Object: Generic Controler to handle Policy,Small Business Logic, Glue in between components, ... + * Status: Release Candidate + * Author: Fulup Ar Foll fulup@iot.bzh + * Date : August-2017 + +## Functionalities: + - Create an application dedicate controller from a JSON config file + - Each controls (eg: navigation, multimedia, ...) is a suite of actions. When all actions succeed control is granted, if one fail control acces is denied. + - Actions can either be: + + Invocation to an other binding API, either internal or external (eg: a policy service, Alsa UCM, ...) + + C routines from a user provider plugin (eg: policy routine, proprietary code, ...) + + LUA script function. LUA provides access to every AGL appfw functionalities and can be extended from C user provided plugins. + +## Installation + - Controler is a native part of AGL Advance Audio Framework but may be used independently with any other service or application binder. + - Dependencies: the only dependencies are audio-common for JSON-WRAP and Filescan-utils capabilities. + - Controler relies on LUA-5.3, when not needed LUA might be removed at compilation time. + +## Config + +Configuration is loaded dynamically during startup time. The controller scans CONTROL_CONFIG_PATH for a file corresponding to pattern +"onload-bindername-xxxxx.json". When controller runs within AAAA binder it searches for "onload-audio-xxxx.json". First file found in the path the loaded +any other files corresponding to the same pather are ignored and only generate a warning. + +Each bloc in the configuration file are defined with + * label: must be provided is used either for debugging or as input for the action (eg: signal name, control name, ...) + * info: optional used for documentation purpose only + +### Config is organised in 4 sections: + + * metadata + * onload defines the set of action to be executed at startup time + * control defines the set of controls with corresponding actions + * event define the set of actions to be executed when receiving a given signal + +### Metadata + +As today matadata is only used for documentation purpose. + * label + version mandatory + * info optional + +### OnLoad section + +Defines startup time configuration. Onload may provide multiple initialisation profiles, each with a different label. + * label is mandatory. Label is used to select onload profile at initialisation through DispatchOneOnLoad("onload-label") API; + * info is optional + * plugin provides optional unique plugin name. Plugin should follow "onload-bindername-xxxxx.ctlso" patern + and are search into CONTROL_PLUGIN_PATH. When defined controller will execute user provided function context=CTLP_ONLOAD(label,version,info). + The context returned by this routine is provided back to any C routines call later by the controller. + * lua2c list of LUA commands shipped with provided plugin. + * require list of binding that should be initialised before the controller starts. Note that some listed requirer binding might be absent, + nevertheless any present binding from this list will be started before controller binding, missing ones generate a warning. + * action the list of action to execute during loadtime. Any failure in action will prevent controller binding from starting. + +### Control section + +Defines a list of controls that are accessible through (api="control", verb="request", control="control-label"). + + * label mandatory + * info optional + * privileges needed privileges to request this control + * action the list of actions + +### Event section + +Defines a list of actions to be executed on event reception. Even can do anything a controller can (change state, +send back signal, ...) eg: if a controller subscribes to vehicule speed, then speed-event may ajust master-volume to speed. + + * label mandatory + * info optional + * action the list of actions + +### Actions Categories + +Controler support tree categories of actions. Each action return a status status where 0=success and 1=failure. + * AppFw API, Provides a generic model to request other bindings. Requested binding can be local (eg: ALSA/UCM) or + external (eg: vehicle signalling). + * api provides requested binding API name + * verb provides verb to requested binding + * args optionally provides a jsonc object for targeted binding API. Note that 'args' are statically defined + in JSON configuration file. Controler client may also provided its own arguments from the query list. Targeted + binding receives both arguments defined in the config file and the argument provided by controller client. + * C-API, when defined in the onload section, the plugin may provided C native API with CTLP-CAPI(apiname, label, args, query, context). + Plugin may also create LUA command with CTLP-LUA2C(LuaFuncName, label, args, query, context). Where args+query are JSONC object + and context the value return from CTLP_ONLOAD function. Any missing value is set to NULL. + * LUA-API, when compiled with LUA option, the controller support action defined directly in LUA script. During "onload" phase the + controller search in CONTROL_LUA_PATH file with pattern "onload-bindername-xxxx.lua". Any file corresponding to this pattern + is automatically loaded. Any function defined in those LUA script can be called through a controller action. LUA functions receive + three parameters (label, args, query). + +## Config Sample + +Here after a simple configuration sample. + +``` +{ + "$schema": "ToBeDone", + "metadata": { + "label": "sample-audio-control", + "info": "Provide Default Audio Policy for Multimedia, Navigation and Emergency", + "version": "1.0" + }, + "onload": [{ + "label": "onload-default", + "info": "onload initialisation config", + "plugin": "ctl-audio-plugin-sample.ctlso", + "require": ["intel-hda", "jabra-usb", "scarlett-usb"], + "actions": [ + { + "label": "onload-sample-cb", + "info": "Call control sharelib install entrypoint", + "callback": "SamplePolicyInit", + "args": { + "arg1": "first_arg", + "nextarg": "second arg value" + } + }, { + "label": "onload-sample-api", + "info": "Assert AlsaCore Presence", + "api": "alsacore", + "verb": "ping", + "args": "test" + }, { + "label": "onload-hal-lua", + "info": "Load avaliable HALs", + "lua": "Audio_Init_Hal" + } + ] + }], + "controls": + [ + { + "label": "multimedia", + "actions": { + "label": "multimedia-control-lua", + "info": "Call Lua Script function Test_Lua_Engin", + "lua": "Audio_Set_Multimedia" + } + }, { + "label": "navigation", + "actions": { + "label": "navigation-control-lua", + "info": "Call Lua Script to set Navigation", + "lua": "Audio_Set_Navigation" + } + }, { + "label": "emergency", + "actions": { + "label": "emergency-control-ucm", + "lua": "Audio_Set_Emergency" + } + }, { + "label": "multi-step-sample", + "info" : "all actions must succeed for control to be accepted", + "actions": [{ + "label": "multimedia-control-cb", + "info": "Call Sharelib Sample Callback", + "callback": "sampleControlNavigation", + "args": { + "arg1": "snoopy", + "arg2": "toto" + } + }, { + "label": "navigation-control-ucm", + "api": "alsacore", + "verb": "ping", + "args": { + "test": "navigation" + } + }, { + "label": "navigation-control-lua", + "info": "Call Lua Script to set Navigation", + "lua": "Audio_Set_Navigation" + }] + } + ], + "events": + [ + { + "label": "Vehicle-Speed", + "info": "Action when Vehicule speed change", + "actions": [ + { + "label": "speed-action-1", + "callback": "Blink-when-over-130", + "args": { + "speed": 130 + "blink-speed": 1000 + } + }, { + "label": "Adjust-Volume", + "lua": "Adjust_Volume_To_Speed", + } + ] + }, + { + "label": "Reverse-Engage", + "info": "When Reverse Gear is Engage", + "actions": [ + { + "label": "Display-Rear-Camera", + "callback": "Display-Rear-Camera", + }, { + "label": "Prevent-Phone-Call", + "api" : "phone", + "verb" : "status", + "args": { + "call-accepted": false + } + } + ] + }, + { + "label": "Neutral-Engage", + "info": "When Reverse Neutral is Engage", + "actions": [ + { + "label": "Authorize-Video", + "api" : "video", + "verb" : "status", + "args": { + "tv-accepted": true + } + } + ] + } + ] +} + +``` + diff --git a/Controler-afb/ctl-apidef.h b/Controler-afb/ctl-apidef.h index 1bd80f9..83b3308 100644 --- a/Controler-afb/ctl-apidef.h +++ b/Controler-afb/ctl-apidef.h @@ -37,35 +37,26 @@ static const char _afb_description_v2_control[] = "name\":\"delay\",\"required\":false,\"schema\":{\"type\":\"interger\"}}," "{\"in\":\"query\",\"name\":\"count\",\"required\":false,\"schema\":{\"ty" "pe\":\"interger\"}}],\"responses\":{\"200\":{\"$ref\":\"#/components/res" - "ponses/200\"}}}},\"/navigation\":{\"description\":\"Request Access to Na" - "vigation Audio Channel.\",\"get\":{\"x-permissions\":{\"$ref\":\"#/compo" - "nents/x-permissions/navigation\"},\"parameters\":[{\"in\":\"query\",\"na" - "me\":\"zone\",\"required\":false,\"schema\":{\"type\":\"string\"}}],\"re" - "sponses\":{\"200\":{\"$ref\":\"#/components/responses/200\"}}}},\"/multi" - "media\":{\"description\":\"Request Access to Navigation Audio Channel.\"" - ",\"get\":{\"x-permissions\":{\"$ref\":\"#/components/x-permissions/navig" - "ation\"},\"parameters\":[{\"in\":\"query\",\"name\":\"zone\",\"required\"" - ":false,\"schema\":{\"type\":\"string\"}}],\"responses\":{\"200\":{\"$ref" - "\":\"#/components/responses/200\"}}}},\"/emergency\":{\"description\":\"" - "Request Access to Navigation Audio Channel.\",\"get\":{\"x-permissions\"" - ":{\"$ref\":\"#/components/x-permissions/navigation\"},\"parameters\":[{\"" - "in\":\"query\",\"name\":\"zone\",\"required\":false,\"schema\":{\"type\"" - ":\"string\"}}],\"responses\":{\"200\":{\"$ref\":\"#/components/responses" - "/200\"}}}},\"/lua_docall\":{\"description\":\"Execute LUA string script." - "\",\"get\":{\"x-permissions\":{\"$ref\":\"#/components/x-permissions/nav" - "igation\"},\"parameters\":[{\"in\":\"query\",\"name\":\"func\",\"require" - "d\":true,\"schema\":{\"type\":\"string\"}},{\"in\":\"query\",\"name\":\"" - "args\",\"required\":false,\"schema\":{\"type\":\"array\"}}],\"responses\"" - ":{\"200\":{\"$ref\":\"#/components/responses/200\"}}}},\"/lua_dostring\"" - ":{\"description\":\"Execute LUA string script.\",\"get\":{\"x-permission" - "s\":{\"$ref\":\"#/components/x-permissions/navigation\"},\"parameters\":" - "[{\"in\":\"query\",\"required\":true,\"schema\":{\"type\":\"string\"}}]," - "\"responses\":{\"200\":{\"$ref\":\"#/components/responses/200\"}}}},\"/l" - "ua_doscript\":{\"description\":\"Execute LUA string script.\",\"get\":{\"" - "x-permissions\":{\"$ref\":\"#/components/x-permissions/navigation\"},\"p" - "arameters\":[{\"in\":\"query\",\"name\":\"filename\",\"required\":true,\"" - "schema\":{\"type\":\"string\"}}],\"responses\":{\"200\":{\"$ref\":\"#/co" - "mponents/responses/200\"}}}}}}" + "ponses/200\"}}}},\"/select\":{\"description\":\"Request Access to Naviga" + "tion Audio Channel.\",\"get\":{\"x-permissions\":{\"$ref\":\"#/component" + "s/x-permissions/navigation\"},\"parameters\":[{\"in\":\"query\",\"name\"" + ":\"zone\",\"required\":false,\"schema\":{\"type\":\"string\"}}],\"respon" + "ses\":{\"200\":{\"$ref\":\"#/components/responses/200\"}}}},\"/lua_docal" + "l\":{\"description\":\"Execute LUA string script.\",\"get\":{\"x-permiss" + "ions\":{\"$ref\":\"#/components/x-permissions/navigation\"},\"parameters" + "\":[{\"in\":\"query\",\"name\":\"func\",\"required\":true,\"schema\":{\"" + "type\":\"string\"}},{\"in\":\"query\",\"name\":\"args\",\"required\":fal" + "se,\"schema\":{\"type\":\"array\"}}],\"responses\":{\"200\":{\"$ref\":\"" + "#/components/responses/200\"}}}},\"/lua_dostring\":{\"description\":\"Ex" + "ecute LUA string script.\",\"get\":{\"x-permissions\":{\"$ref\":\"#/comp" + "onents/x-permissions/navigation\"},\"parameters\":[{\"in\":\"query\",\"r" + "equired\":true,\"schema\":{\"type\":\"string\"}}],\"responses\":{\"200\"" + ":{\"$ref\":\"#/components/responses/200\"}}}},\"/lua_doscript\":{\"descr" + "iption\":\"Execute LUA string script.\",\"get\":{\"x-permissions\":{\"$r" + "ef\":\"#/components/x-permissions/navigation\"},\"parameters\":[{\"in\":" + "\"query\",\"name\":\"filename\",\"required\":true,\"schema\":{\"type\":\"" + "string\"}}],\"responses\":{\"200\":{\"$ref\":\"#/components/responses/20" + "0\"}}}}}}" ; static const struct afb_auth _afb_auths_v2_control[] = { @@ -74,9 +65,7 @@ static const struct afb_auth _afb_auths_v2_control[] = { void ctlapi_monitor(struct afb_req req); void ctlapi_event_test(struct afb_req req); - void ctlapi_navigation(struct afb_req req); - void ctlapi_multimedia(struct afb_req req); - void ctlapi_emergency(struct afb_req req); + void ctlapi_select(struct afb_req req); void ctlapi_lua_docall(struct afb_req req); void ctlapi_lua_dostring(struct afb_req req); void ctlapi_lua_doscript(struct afb_req req); @@ -97,22 +86,8 @@ static const struct afb_verb_v2 _afb_verbs_v2_control[] = { .session = AFB_SESSION_NONE_V2 }, { - .verb = "navigation", - .callback = ctlapi_navigation, - .auth = &_afb_auths_v2_control[0], - .info = NULL, - .session = AFB_SESSION_NONE_V2 - }, - { - .verb = "multimedia", - .callback = ctlapi_multimedia, - .auth = &_afb_auths_v2_control[0], - .info = NULL, - .session = AFB_SESSION_NONE_V2 - }, - { - .verb = "emergency", - .callback = ctlapi_emergency, + .verb = "select", + .callback = ctlapi_select, .auth = &_afb_auths_v2_control[0], .info = NULL, .session = AFB_SESSION_NONE_V2 diff --git a/Controler-afb/ctl-apidef.json b/Controler-afb/ctl-apidef.json index 28b8581..818dd80 100644 --- a/Controler-afb/ctl-apidef.json +++ b/Controler-afb/ctl-apidef.json @@ -178,53 +178,7 @@ } } }, - "/navigation": { - "description": "Request Access to Navigation Audio Channel.", - "get": { - "x-permissions": { - "$ref": "#/components/x-permissions/navigation" - }, - "parameters": [ - { - "in": "query", - "name": "zone", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/200" - } - } - } - }, - "/multimedia": { - "description": "Request Access to Navigation Audio Channel.", - "get": { - "x-permissions": { - "$ref": "#/components/x-permissions/navigation" - }, - "parameters": [ - { - "in": "query", - "name": "zone", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "$ref": "#/components/responses/200" - } - } - } - }, - "/emergency": { + "/select": { "description": "Request Access to Navigation Audio Channel.", "get": { "x-permissions": { diff --git a/Controler-afb/ctl-binding.h b/Controler-afb/ctl-binding.h index 70ad0c3..a2cedbf 100644 --- a/Controler-afb/ctl-binding.h +++ b/Controler-afb/ctl-binding.h @@ -22,6 +22,8 @@ #define AFB_BINDING_VERSION 2 #include <afb/afb-binding.h> #include <json-c/json.h> +#include <filescan-utils.h> +#include <wrap-json.h> #ifndef PUBLIC #define PUBLIC @@ -41,16 +43,6 @@ typedef struct { #define CTL_PLUGIN_REGISTER(pluglabel) CtlPluginMagicT CtlPluginMagic={.magic=CTL_PLUGIN_MAGIC,.label=pluglabel}; struct afb_binding_data_v2; -// ctl-misc.c -typedef enum { - CTL_SCAN_FLAT=0, - CTL_SCAN_RECURSIVE=1, -} CtlScanDirModeT; - -PUBLIC const char *GetMidleName(const char*name); -PUBLIC const char *GetBinderName(); -PUBLIC json_object* ScanForConfig (char* searchPath, CtlScanDirModeT mode, char *pre, char *ext); - // polctl-binding.c PUBLIC int CtlBindingInit (); diff --git a/Controler-afb/ctl-dispatch.c b/Controler-afb/ctl-dispatch.c index 3318c8d..0594952 100644 --- a/Controler-afb/ctl-dispatch.c +++ b/Controler-afb/ctl-dispatch.c @@ -23,7 +23,6 @@ #include <string.h> #include <dlfcn.h> -#include "wrap-json.h" #include "ctl-binding.h" typedef void*(*DispatchPluginInstallCbT)(const char* label, const char*version, const char*info); diff --git a/Controler-afb/ctl-events.c b/Controler-afb/ctl-events.c index f76feca..18aac53 100644 --- a/Controler-afb/ctl-events.c +++ b/Controler-afb/ctl-events.c @@ -75,7 +75,7 @@ STATIC int DoSendEvent (void *context) { else ctx->value =1; ctlEventJ = json_object_new_object(); - json_object_object_add(ctlEventJ,"action", json_object_new_string(ctx->label)); + json_object_object_add(ctlEventJ,"signal", json_object_new_string(ctx->label)); json_object_object_add(ctlEventJ,"value" , json_object_new_int(ctx->value)); int done = afb_event_push(afbevt, ctlEventJ); diff --git a/Controler-afb/ctl-lua.c b/Controler-afb/ctl-lua.c index 919230d..bf02a31 100644 --- a/Controler-afb/ctl-lua.c +++ b/Controler-afb/ctl-lua.c @@ -33,6 +33,7 @@ #define LUA_FIST_ARG 2 // when using luaL_newlib calllback receive libtable as 1st arg #define LUA_MSG_MAX_LENGTH 255 +#define JSON_ERROR (json_object*)-1 static lua_State* luaState; @@ -107,7 +108,7 @@ STATIC void LuaCtxFree (LuaAfbContextT *afbContext) { // Push a json structure on the stack as a LUA table STATIC int LuaPushArgument (json_object *argsJ) { - AFB_NOTICE("LuaPushArgument argsJ=%s", json_object_get_string(argsJ)); + //AFB_NOTICE("LuaPushArgument argsJ=%s", json_object_get_string(argsJ)); json_type jtype= json_object_get_type(argsJ); switch (jtype) { @@ -156,6 +157,7 @@ STATIC int LuaPushArgument (json_object *argsJ) { } STATIC json_object *PopOneArg (lua_State* luaState, int idx); + STATIC json_object *LuaTableToJson (lua_State* luaState, int index) { int idx; @@ -171,8 +173,8 @@ STATIC json_object *LuaTableToJson (lua_State* luaState, int index) { snprintf(number, sizeof(number),"%d", idx); key=number; } - - json_object_object_add(tableJ, key, PopOneArg(luaState, -1)); + json_object *argJ= PopOneArg(luaState, -1); + json_object_object_add(tableJ, key, argJ); lua_pop(luaState, 1); // removes 'value'; keeps 'key' for next iteration } @@ -189,9 +191,16 @@ STATIC json_object *PopOneArg (lua_State* luaState, int idx) { int luaType = lua_type(luaState, idx); switch(luaType) { - case LUA_TNUMBER: - value= json_object_new_double(lua_tonumber(luaState, idx)); + case LUA_TNUMBER: { + lua_Number number= lua_tonumber(luaState, idx);; + int nombre = (int)number; // evil trick to determine wether n fits in an integer. (stolen from ltcl.c) + if (number == nombre) { + value= json_object_new_int((int)number); + } else { + value= json_object_new_double(number); + } break; + } case LUA_TBOOLEAN: value= json_object_new_boolean(lua_toboolean(luaState, idx)); break; @@ -199,15 +208,23 @@ STATIC json_object *PopOneArg (lua_State* luaState, int idx) { value= json_object_new_string(lua_tostring(luaState, idx)); break; case LUA_TTABLE: { - value= LuaTableToJson(luaState, idx); + if (idx > 0) { + value= LuaTableToJson(luaState, idx); + } else { + value= json_object_new_string("UNSUPPORTED_Lua_Nested_Table"); + } break; } + case LUA_TNIL: + value=json_object_new_string("nil") ; + break; + default: AFB_NOTICE ("PopOneArg: script returned Unknown/Unsupported idx=%d type:%d/%s", idx, luaType, lua_typename(luaState, luaType)); value=NULL; } - return value; + return value; } static json_object *LuaPopArgs (lua_State* luaState, int start) { @@ -223,24 +240,28 @@ static json_object *LuaPopArgs (lua_State* luaState, int start) { // loop on remaining return arguments responseJ= json_object_new_array(); for (int idx=start; idx <= stop; idx++) { - json_object_array_add(responseJ, PopOneArg (luaState, idx)); + json_object *argJ=PopOneArg (luaState, idx); + if (!argJ) goto OnErrorExit; + json_object_array_add(responseJ, argJ); } } return responseJ; -} + + OnErrorExit: + return NULL; +} -STATIC void LuaFormatMessage(lua_State* luaState, LuaAfbMessageT action) { + +STATIC int LuaFormatMessage(lua_State* luaState, LuaAfbMessageT action) { char *message; json_object *responseJ= LuaPopArgs(luaState, LUA_FIST_ARG); + if (!responseJ) { - message="-- Empty Message ???"; - goto PrintMessage; + luaL_error(luaState,"LuaFormatMessage empty message"); + goto OnErrorExit; } - - //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) { @@ -290,6 +311,7 @@ STATIC void LuaFormatMessage(lua_State* luaState, LuaAfbMessageT action) { message[targetIdx++] = format[idx]; } } + message[targetIdx]='\0'; PrintMessage: switch (action) { @@ -309,31 +331,35 @@ PrintMessage: default: AFB_ERROR (message); } + return 0; // nothing return to lua + + OnErrorExit: // on argument to return (the error message) + return 1; } STATIC int LuaPrintInfo(lua_State* luaState) { - LuaFormatMessage (luaState, AFB_MSG_INFO); - return 0; // no value return + int err=LuaFormatMessage (luaState, AFB_MSG_INFO); + return err; } STATIC int LuaPrintError(lua_State* luaState) { - LuaFormatMessage (luaState, AFB_MSG_ERROR); - return 0; // no value return + int err=LuaFormatMessage (luaState, AFB_MSG_ERROR); + return err; // no value return } STATIC int LuaPrintWarning(lua_State* luaState) { - LuaFormatMessage (luaState, AFB_MSG_WARNING); - return 0; // no value return + int err=LuaFormatMessage (luaState, AFB_MSG_WARNING); + return err; } STATIC int LuaPrintNotice(lua_State* luaState) { - LuaFormatMessage (luaState, AFB_MSG_NOTICE); - return 0; // no value return + int err=LuaFormatMessage (luaState, AFB_MSG_NOTICE); + return err; } STATIC int LuaPrintDebug(lua_State* luaState) { - LuaFormatMessage (luaState, AFB_MSG_DEBUG); - return 0; // no value return + int err=LuaFormatMessage (luaState, AFB_MSG_DEBUG); + return err; } STATIC int LuaAfbSuccess(lua_State* luaState) { @@ -342,6 +368,7 @@ STATIC int LuaAfbSuccess(lua_State* luaState) { // ignore context argument json_object *responseJ= LuaPopArgs(luaState, LUA_FIST_ARG+1); + if (responseJ == JSON_ERROR) return 1; afb_req_success(afbContext->request, responseJ, NULL); @@ -358,6 +385,7 @@ STATIC int LuaAfbFail(lua_State* luaState) { if (!afbContext) goto OnErrorExit; json_object *responseJ= LuaPopArgs(luaState, LUA_FIST_ARG+1); + if (responseJ == JSON_ERROR) return 1; afb_req_fail(afbContext->request, afbContext->info, json_object_get_string(responseJ)); @@ -400,6 +428,7 @@ STATIC int LuaAfbService(lua_State* luaState) { const char *api = lua_tostring(luaState,2); const char *verb= lua_tostring(luaState,3); json_object *queryJ= LuaTableToJson(luaState, 4); + if (queryJ == JSON_ERROR) return 1; LuaCallServiceT *contextCB = calloc (1, sizeof(LuaCallServiceT)); contextCB->callback= lua_tostring(luaState, 5); @@ -597,7 +626,6 @@ STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { lua_pushnil(luaState); count++; } else { - AFB_NOTICE("***** args=%s", json_object_get_string(argsJ)); count+= LuaPushArgument (argsJ); } @@ -606,15 +634,17 @@ STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { case LUA_DOSCRIPT: { // Fulup need to fix argument passing const char *script; + char*func; + char *filename; char*fullpath; char luaScriptPath[CONTROL_MAXPATH_LEN]; - json_object *args; + json_object *argsJ; int index; // scan luascript search path once static json_object *luaScriptPathJ =NULL; if (!luaScriptPathJ) luaScriptPathJ= ScanForConfig(CONTROL_LUA_PATH , CTL_SCAN_RECURSIVE, CONTROL_DOSCRIPT_PRE, "lua"); - err= wrap_json_unpack (queryJ, "{s:s, s?o s?o !}", "script", &script,"args", &args, "arg", &args); + err= wrap_json_unpack (queryJ, "{s:s, s?s s?o s?o !}", "script", &script,"func", &func, "arg", &argsJ); if (err) { AFB_ERROR ("LUA-DOSCRIPT-SYNTAX:missing script|(args,arg) query=%s", json_object_get_string(queryJ)); goto OnErrorExit; @@ -623,7 +653,6 @@ STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { // search for filename=script in CONTROL_LUA_PATH for (index=0; index < json_object_array_length(luaScriptPathJ); index++) { json_object *entryJ=json_object_array_get_idx(luaScriptPathJ, index); - char *filename; char*fullpath; err= wrap_json_unpack (entryJ, "{s:s, s:s !}", "fullpath", &fullpath,"filename", &filename); if (err) { @@ -649,15 +678,27 @@ STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { goto OnErrorExit; } - // push query on the stack - if (json_object_get_type(args) != json_type_array) { - count= LuaPushArgument (args); - } else { - for (int idx=0; idx<json_object_array_length(args); idx++) { - count += LuaPushArgument (json_object_array_get_idx(args, idx)); - if (err) break; - } - } + // if no func name given try to deduct from filename + if (!func) func= (char*)GetMidleName(filename); + if (!func) { + AFB_ERROR ("LUA-DOSCRIPT:FAIL to deduct funcname from %s", filename); + goto OnErrorExit; + } + + // 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 function arguments + if (!argsJ) { + lua_pushnil(luaState); + count++; + } else { + count+= LuaPushArgument (argsJ); + } break; } diff --git a/Controler-afb/ctl-misc.c b/Controler-afb/ctl-misc.c deleted file mode 100644 index 773e8f9..0000000 --- a/Controler-afb/ctl-misc.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2016 "IoT.bzh" - * Author Fulup Ar Foll <fulup@iot.bzh> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _GNU_SOURCE -#include <stdio.h> -#include <string.h> -#include <time.h> -#include <sys/prctl.h> -#include <dirent.h> - -#include "audio-common.h" -#include "ctl-binding.h" - - - -// 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_DEBUG ("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); -} - -PUBLIC const char *GetMidleName(const char*name) { - char *fullname = strdup(name); - - for (int idx = 0; fullname[idx] != '\0'; idx++) { - int start; - if (fullname[idx] == '-') { - start = idx + 1; - for (int jdx = start; fullname[jdx] != '\0'; jdx++) { - if (fullname[jdx] == '-') { - fullname[jdx] = '\0'; - return &fullname[start]; - break; - } - } - break; - } - } - return ""; -} - -PUBLIC const char *GetBinderName() { - char psName[17]; - static char *binderName=NULL; - - if (binderName) return binderName; - - // retrieve binder name from process name afb-name-trailer - prctl(PR_GET_NAME, psName,NULL,NULL,NULL); - binderName=GetMidleName(psName); - - return binderName; -}
\ No newline at end of file |