aboutsummaryrefslogtreecommitdiffstats
path: root/Controler-afb
diff options
context:
space:
mode:
Diffstat (limited to 'Controler-afb')
-rw-r--r--Controler-afb/CMakeLists.txt9
-rw-r--r--Controler-afb/README.md31
-rw-r--r--Controler-afb/ctl-apidef.h34
-rw-r--r--Controler-afb/ctl-apidef.json2
-rw-r--r--Controler-afb/ctl-binding.c19
-rw-r--r--Controler-afb/ctl-binding.h52
-rw-r--r--Controler-afb/ctl-dispatch.c583
-rw-r--r--Controler-afb/ctl-lua.c50
-rw-r--r--Controler-afb/ctl-plugin-sample.c52
9 files changed, 513 insertions, 319 deletions
diff --git a/Controler-afb/CMakeLists.txt b/Controler-afb/CMakeLists.txt
index 78e66c8..30fcb37 100644
--- a/Controler-afb/CMakeLists.txt
+++ b/Controler-afb/CMakeLists.txt
@@ -26,14 +26,19 @@ macro(SET_TARGET_GENSKEL TARGET_NAME API_DEF_NAME)
)
add_custom_target(${API_DEF_NAME}_OPENAPI DEPENDS ${API_DEF_NAME}.h)
add_dependencies(${TARGET_NAME} ${API_DEF_NAME}_OPENAPI)
-
endmacro(SET_TARGET_GENSKEL)
+# Include LUA only when requested
+if(CONTROL_SUPPORT_LUA)
+ message(STATUS "Notice: LUA Controler Support Selected")
+ set(CTL_LUA_SOURCE ctl-lua.c)
+endif(CONTROL_SUPPORT_LUA)
+
# Add target to project dependency list
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)
+ ADD_LIBRARY(${TARGET_NAME} MODULE ctl-binding.c ctl-events.c ctl-dispatch.c ${CTL_LUA_SOURCE})
# Generate API-v2 hat from OpenAPI json definition
SET_TARGET_GENSKEL(${TARGET_NAME} ctl-apidef)
diff --git a/Controler-afb/README.md b/Controler-afb/README.md
index 3274ede..3abe762 100644
--- a/Controler-afb/README.md
+++ b/Controler-afb/README.md
@@ -12,12 +12,12 @@ Controler AAAA(AGL Advance Audio Controler) and more.
- 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.
+ + 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.
+ - Controler relies on Lua-5.3, when not needed Lua might be removed at compilation time.
## Config
@@ -49,8 +49,9 @@ Defines startup time configuration. Onload may provide multiple initialisation p
* 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.
+ The context returned by this routine is provided back to any C routines call later by the controller. Note that Lua2C function
+ are prefix in Lua script with plugin label (eg: MyPlug: in following config sample)
+ * 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.
@@ -61,7 +62,7 @@ Defines a list of controls that are accessible through (api="control", verb="req
* label mandatory
* info optional
- * privileges needed privileges to request this control
+ * permissions Cynara needed privileges to request this control (same as AppFw-V2)
* action the list of actions
### Event section
@@ -84,13 +85,16 @@ Controler support tree categories of actions. Each action return a status status
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
+ 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
+ * 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).
+Note: Lua added functions systematically prefix. AGL standard AppFw functions are prefixed with AGL: (eg: AGL:notice(), AGL_success(), ...).
+User Lua functions added though the plugin and CTLP_Lua2C are prefix with plugin label (eg: MyPlug:HelloWorld1).
+
## Config Sample
Here after a simple configuration sample.
@@ -106,7 +110,11 @@ Here after a simple configuration sample.
"onload": [{
"label": "onload-default",
"info": "onload initialisation config",
- "plugin": "ctl-audio-plugin-sample.ctlso",
+ "plugin": {
+ "label" : "MyPlug",
+ "sharelib": "ctl-audio-plugin-sample.ctlso",
+ "lua2c": ["Lua2cHelloWorld1", "Lua2cHelloWorld2"]
+ },
"require": ["intel-hda", "jabra-usb", "scarlett-usb"],
"actions": [
{
@@ -134,6 +142,7 @@ Here after a simple configuration sample.
[
{
"label": "multimedia",
+ "permissions": "urn:AGL:permission:audio:public:mutimedia",
"actions": {
"label": "multimedia-control-lua",
"info": "Call Lua Script function Test_Lua_Engin",
@@ -141,6 +150,7 @@ Here after a simple configuration sample.
}
}, {
"label": "navigation",
+ "permissions": "urn:AGL:permission:audio:public:navigation",
"actions": {
"label": "navigation-control-lua",
"info": "Call Lua Script to set Navigation",
@@ -148,6 +158,7 @@ Here after a simple configuration sample.
}
}, {
"label": "emergency",
+ "permissions": "urn:AGL:permission:audio:public:emergency",
"actions": {
"label": "emergency-control-ucm",
"lua": "Audio_Set_Emergency"
diff --git a/Controler-afb/ctl-apidef.h b/Controler-afb/ctl-apidef.h
index 83b3308..9eb271d 100644
--- a/Controler-afb/ctl-apidef.h
+++ b/Controler-afb/ctl-apidef.h
@@ -37,20 +37,20 @@ 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\"}}}},\"/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\""
+ "ponses/200\"}}}},\"/dispatch\":{\"description\":\"Request Access to Navi"
+ "gation Audio Channel.\",\"get\":{\"x-permissions\":{\"$ref\":\"#/compone"
+ "nts/x-permissions/navigation\"},\"parameters\":[{\"in\":\"query\",\"name"
+ "\":\"zone\",\"required\":false,\"schema\":{\"type\":\"string\"}}],\"resp"
+ "onses\":{\"200\":{\"$ref\":\"#/components/responses/200\"}}}},\"/lua_doc"
+ "all\":{\"description\":\"Execute LUA string script.\",\"get\":{\"x-permi"
+ "ssions\":{\"$ref\":\"#/components/x-permissions/navigation\"},\"paramete"
+ "rs\":[{\"in\":\"query\",\"name\":\"func\",\"required\":true,\"schema\":{"
+ "\"type\":\"string\"}},{\"in\":\"query\",\"name\":\"args\",\"required\":f"
+ "alse,\"schema\":{\"type\":\"array\"}}],\"responses\":{\"200\":{\"$ref\":"
+ "\"#/components/responses/200\"}}}},\"/lua_dostring\":{\"description\":\""
+ "Execute LUA string script.\",\"get\":{\"x-permissions\":{\"$ref\":\"#/co"
+ "mponents/x-permissions/navigation\"},\"parameters\":[{\"in\":\"query\",\""
+ "required\":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\":"
@@ -65,7 +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_select(struct afb_req req);
+ void ctlapi_dispatch(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);
@@ -86,8 +86,8 @@ static const struct afb_verb_v2 _afb_verbs_v2_control[] = {
.session = AFB_SESSION_NONE_V2
},
{
- .verb = "select",
- .callback = ctlapi_select,
+ .verb = "dispatch",
+ .callback = ctlapi_dispatch,
.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 818dd80..93456ab 100644
--- a/Controler-afb/ctl-apidef.json
+++ b/Controler-afb/ctl-apidef.json
@@ -178,7 +178,7 @@
}
}
},
- "/select": {
+ "/dispatch": {
"description": "Request Access to Navigation Audio Channel.",
"get": {
"x-permissions": {
diff --git a/Controler-afb/ctl-binding.c b/Controler-afb/ctl-binding.c
index 554199b..8771fc0 100644
--- a/Controler-afb/ctl-binding.c
+++ b/Controler-afb/ctl-binding.c
@@ -29,21 +29,6 @@
#include "ctl-apidef.h"
-PUBLIC void ctlapi_navigation (afb_req request) {
-
- ctlapi_dispatch ("NAVIGATION", request);
-}
-
-PUBLIC void ctlapi_multimedia (afb_req request) {
-
- ctlapi_dispatch ("MULTIMEDIA", request);
-}
-
-PUBLIC void ctlapi_emergency (afb_req request) {
-
- ctlapi_dispatch ("EMERGENCY", request);
-}
-
PUBLIC void ctlapi_monitor (afb_req request) {
// subscribe Client to event
@@ -66,11 +51,13 @@ PUBLIC int CtlBindingInit () {
errcount += TimerEvtInit();
errcount += DispatchInit();
+#ifdef CONTROL_SUPPORT_LUA
errcount += LuaLibInit();
+#endif
// now that everything is initialised execute the onload action
if (!errcount)
- errcount += DispatchOneOnLoad(CONTROL_ONLOAD_DEFAULT);
+ errcount += DispatchOnLoad(CONTROL_ONLOAD_DEFAULT);
AFB_DEBUG ("Audio Policy Control Binding Done errcount=%d", errcount);
return errcount;
diff --git a/Controler-afb/ctl-binding.h b/Controler-afb/ctl-binding.h
index a2cedbf..33a9049 100644
--- a/Controler-afb/ctl-binding.h
+++ b/Controler-afb/ctl-binding.h
@@ -25,6 +25,12 @@
#include <filescan-utils.h>
#include <wrap-json.h>
+#ifdef CONTROL_SUPPORT_LUA
+#include "lua.h"
+#include "lauxlib.h"
+#include "lualib.h"
+#endif
+
#ifndef PUBLIC
#define PUBLIC
#endif
@@ -35,15 +41,6 @@
#define UNUSED_FUNCTION(x) __attribute__((__unused__)) UNUSED_ ## x
#endif
-// sharelib ctl-plugin*
-typedef struct {
- long magic;
- char *label;
-} CtlPluginMagicT;
-
-#define CTL_PLUGIN_REGISTER(pluglabel) CtlPluginMagicT CtlPluginMagic={.magic=CTL_PLUGIN_MAGIC,.label=pluglabel}; struct afb_binding_data_v2;
-
-
// polctl-binding.c
PUBLIC int CtlBindingInit ();
@@ -71,15 +68,23 @@ typedef struct DispatchActionS{
const char* call;
json_object *argsJ;
int timeout;
- int (*actionCB)(struct DispatchActionS *action, json_object *queryJ, void *context);
+ int (*actionCB)(const char*label, json_object *argsJ, json_object *queryJ, void *context);
} DispatchActionT;
+typedef int (*Lua2cFunctionT)(char *funcname, json_object *argsJ, void*context);
PUBLIC int DispatchInit(void);
-PUBLIC int DispatchOneOnLoad(const char *onLoadLabel);
+PUBLIC int DispatchOnLoad(const char *onLoadLabel);
PUBLIC void DispatchOneEvent(const char *evtLabel, json_object *eventJ);
-PUBLIC void ctlapi_dispatch (char* control, afb_req request);
+PUBLIC int DispatchOneL2c(lua_State* luaState, char *funcname, Lua2cFunctionT callback);
+PUBLIC void ctlapi_dispatch (afb_req request);
+#ifdef CONTROL_SUPPORT_LUA
// ctl-lua.c
+typedef int (*Lua2cWrapperT) (lua_State* luaState, char *funcname, Lua2cFunctionT callback);
+
+#define CTLP_LUA2C(FuncName,label,argsJ, context) static int FuncName(char*label,json_object*argsJ, void*context);\
+ int lua2c_ ## FuncName(lua_State* luaState){return((*Lua2cWrap)(luaState, MACRO_STR_VALUE(FuncName), FuncName));};\
+ static int FuncName(char* label, json_object* argsJ, void* context)
typedef enum {
LUA_DOCALL,
@@ -88,9 +93,30 @@ typedef enum {
} LuaDoActionT;
PUBLIC int LuaLibInit ();
+PUBLIC void LuaL2cNewLib(const char *label, luaL_Reg *l2cFunc, int count);
+PUBLIC int Lua2cWrapper(lua_State* luaState, char *funcname, Lua2cFunctionT callback, void *context);
PUBLIC int LuaCallFunc (DispatchActionT *action, json_object *queryJ);
PUBLIC void ctlapi_lua_docall (afb_req request);
PUBLIC void ctlapi_lua_dostring (afb_req request);
PUBLIC void ctlapi_lua_doscript (afb_req request);
-#endif
+#else
+ typedef void* Lua2cWrapperT;
+#endif // CONTROL_SUPPORT_LUA
+
+
+// sharelib ctl-plugin*
+typedef struct {
+ long magic;
+ char *label;
+} CtlPluginMagicT;
+
+
+#define MACRO_STR_VALUE(arg) #arg
+#define CTLP_REGISTER(pluglabel) CtlPluginMagicT CtlPluginMagic={.magic=CTL_PLUGIN_MAGIC,.label=pluglabel}; struct afb_binding_data_v2; Lua2cWrapperT Lua2cWrap;
+#define CTLP_ONLOAD(label,version,info) void* CtlPluginOnload(char* label, char* version, char* info)
+#define CTLP_CAPI(funcname,label,argsJ, queryJ, context) int funcname(char* label, json_object* argsJ, json_object* queryJ, void* context)
+
+
+
+#endif // CONTROLER_BINDING_INCLUDE
diff --git a/Controler-afb/ctl-dispatch.c b/Controler-afb/ctl-dispatch.c
index 0594952..22bee27 100644
--- a/Controler-afb/ctl-dispatch.c
+++ b/Controler-afb/ctl-dispatch.c
@@ -27,7 +27,7 @@
typedef void*(*DispatchPluginInstallCbT)(const char* label, const char*version, const char*info);
-static afb_req NULL_AFBREQ={};
+static afb_req NULL_AFBREQ = {};
typedef enum {
CTL_DISPATCH_ONLOAD,
@@ -42,12 +42,20 @@ typedef struct {
} DispatchHandleT;
typedef struct {
- const char* label;
+ const char *label;
const char *info;
- const char *version;
void *context;
- char *plugin;
+ char *sharelib;
void *dlHandle;
+ luaL_Reg *l2cFunc;
+ int l2cCount;
+} DispatchPluginT;
+
+typedef struct {
+ const char* label;
+ const char *info;
+ const char *version;
+ DispatchPluginT *plugin;
DispatchHandleT **onloads;
DispatchHandleT **events;
DispatchHandleT **controls;
@@ -58,295 +66,348 @@ STATIC DispatchConfigT *configHandle = NULL;
STATIC int DispatchControlToIndex(DispatchHandleT **controls, const char* controlLabel) {
- for (int idx=0; controls[idx]; idx++) {
+ for (int idx = 0; controls[idx]; idx++) {
if (!strcasecmp(controlLabel, controls[idx]->label)) return idx;
}
return -1;
}
-STATIC int DispatchOneControl (DispatchHandleT **controls, const char* controlLabel, json_object *queryJ, afb_req request) {
+STATIC int DispatchOneControl(DispatchHandleT **controls, const char* controlLabel, json_object *queryJ, afb_req request) {
int err;
- if(!configHandle->controls) {
- AFB_ERROR ("DISPATCH-CTL-API: No Control Action in Json config label=%s version=%s", configHandle->label, configHandle->version);
+ if (!configHandle) {
+ AFB_ERROR("DISPATCH-CTL-API: (Hoops/Bug!!!) No Config Loaded");
goto OnErrorExit;
}
-
- int index=DispatchControlToIndex(controls, controlLabel);
- if (index<0 || !controls[index]->actions) {
- AFB_ERROR ("DISPATCH-CTL-API:NotFound label=%s in Json Control Config File", controlLabel);
+
+ if (!configHandle->controls) {
+ AFB_ERROR("DISPATCH-CTL-API: No Control Action in Json config label=%s version=%s", configHandle->label, configHandle->version);
goto OnErrorExit;
- }
+ }
+
+ int index = DispatchControlToIndex(controls, controlLabel);
+ if (index < 0 || !controls[index]->actions) {
+ AFB_ERROR("DISPATCH-CTL-API:NotFound/Error label=%s in Json Control Config File", controlLabel);
+ goto OnErrorExit;
+ }
+
+ // Fulup (Bug/Feature) in current version is unique to every onload profile
+ if (configHandle->plugin && configHandle->plugin->l2cCount) {
+ LuaL2cNewLib (configHandle->plugin->label, configHandle->plugin->l2cFunc, configHandle->plugin->l2cCount);
+ }
// loop on action for this control
- DispatchActionT *actions=controls[index]->actions;
- for (int idx=0; actions[idx].label; idx++) {
-
+ DispatchActionT *actions = controls[index]->actions;
+ for (int idx = 0; actions[idx].label; idx++) {
+
switch (actions[idx].mode) {
- case CTL_MODE_API: {
+ case CTL_MODE_API:
+ {
json_object *returnJ;
-
- json_object_get( actions[idx].argsJ); // make sure afb_service_call does not free the argsJ
+
+ json_object_get(actions[idx].argsJ); // make sure afb_service_call does not free the argsJ
int err = afb_service_call_sync(actions[idx].api, actions[idx].call, actions[idx].argsJ, &returnJ);
if (err) {
- static const char*format="DispatchOneControl(Api) api=%s verb=%s args=%s";
+ static const char*format = "DispatchOneControl(Api) api=%s verb=%s args=%s";
if (afb_req_is_valid(request))afb_req_fail_f(request, "DISPATCH-CTL-MODE:API", format, actions[idx].label, actions[idx].api, actions[idx].call);
- else AFB_ERROR (format, actions[idx].api, actions[idx].call, actions[idx].label);
+ else AFB_ERROR(format, actions[idx].api, actions[idx].call, actions[idx].label);
goto OnErrorExit;
}
break;
}
-
+
+#ifdef CONTROL_SUPPORT_LUA
case CTL_MODE_LUA:
- err= LuaCallFunc (&actions[idx], queryJ);
+ err = LuaCallFunc(&actions[idx], queryJ);
if (err) {
- static const char*format= "DispatchOneControl(Lua) label=%s func=%s args=%s";
+ static const char*format = "DispatchOneControl(Lua) label=%s func=%s args=%s";
if (afb_req_is_valid(request)) afb_req_fail_f(request, "DISPATCH-CTL-MODE:Lua", format, actions[idx].label, actions[idx].call, json_object_get_string(actions[idx].argsJ));
- else AFB_ERROR (format, actions[idx].label, actions[idx].call, json_object_get_string(actions[idx].argsJ));
+ else AFB_ERROR(format, actions[idx].label, actions[idx].call, json_object_get_string(actions[idx].argsJ));
goto OnErrorExit;
}
break;
-
+#endif
+
case CTL_MODE_CB:
- err= (*actions[idx].actionCB) (&actions[idx], queryJ, configHandle->context);
+ err = (*actions[idx].actionCB) (actions[idx].label, actions[idx].argsJ, queryJ, configHandle->plugin->context);
if (err) {
- static const char*format="DispatchOneControl(Callback) label%s func=%s args=%s";
- if (afb_req_is_valid(request)) afb_req_fail_f(request, "DISPATCH-CTL-MODE:Cb", format, actions[idx].label, actions[idx].call, json_object_get_string(actions[idx].argsJ));
- else AFB_ERROR (format, actions[idx].label, actions[idx].call, json_object_get_string(actions[idx].argsJ));
+ static const char*format = "DispatchOneControl(Callback) label%s func=%s args=%s";
+ if (afb_req_is_valid(request)) afb_req_fail_f(request, "DISPATCH-CTL-MODE:Cb", format, actions[idx].label, actions[idx].call, json_object_get_string(actions[idx].argsJ));
+ else AFB_ERROR(format, actions[idx].label, actions[idx].call, json_object_get_string(actions[idx].argsJ));
goto OnErrorExit;
}
break;
-
- default:{
- static const char*format="DispatchOneControl(unknown) mode control=%s action=%s";
- AFB_ERROR (format, controls[index]->label);
+
+ default:
+ {
+ static const char*format = "DispatchOneControl(unknown) mode control=%s action=%s";
+ AFB_ERROR(format, controls[index]->label);
if (afb_req_is_valid(request))afb_req_fail_f(request, "DISPATCH-CTL-MODE:Unknown", format, controls[index]->label);
- }
+ }
}
}
-
+
// everything when fine
- if(afb_req_is_valid(request))afb_req_success(request,NULL,controls[index]->label);
+ if (afb_req_is_valid(request))afb_req_success(request, NULL, controls[index]->label);
return 0;
-
- OnErrorExit:
+
+OnErrorExit:
return -1;
}
// Event name is mapped on control label and executed as a standard control
-PUBLIC void DispatchOneEvent(const char *evtLabel, json_object *eventJ){
- DispatchHandleT **events=configHandle->events;
- (void)DispatchOneControl(events, evtLabel, eventJ, NULL_AFBREQ);
+PUBLIC void DispatchOneEvent(const char *evtLabel, json_object *eventJ) {
+ DispatchHandleT **events = configHandle->events;
+
+ (void) DispatchOneControl(events, evtLabel, eventJ, NULL_AFBREQ);
}
// Event name is mapped on control label and executed as a standard control
-PUBLIC int DispatchOneOnLoad(const char *onLoadLabel){
- DispatchHandleT **onloads=configHandle->onloads;
- int err=DispatchOneControl(onloads, onLoadLabel, NULL, NULL_AFBREQ);
+PUBLIC int DispatchOnLoad(const char *onLoadLabel) {
+ DispatchHandleT **onloads = configHandle->onloads;
+
+ int err = DispatchOneControl(onloads, onLoadLabel, NULL, NULL_AFBREQ);
return err;
}
-PUBLIC void ctlapi_dispatch (char* controlLabel, afb_req request) {
- DispatchHandleT **controls=configHandle->controls;
-
- json_object* queryJ = afb_req_json(request);
- (void)DispatchOneControl(controls, controlLabel, queryJ, request);
-}
+PUBLIC void ctlapi_dispatch(afb_req request) {
+ DispatchHandleT **controls = configHandle->controls;
+ json_object *queryJ, *argsJ;
+ const char *target;
+
+ queryJ = afb_req_json(request);
+ int err = wrap_json_unpack(queryJ, "{s:s, s:o !}", "target", &target, "args", &argsJ);
+ if (err) {
+ afb_req_fail_f(request, "CTL-DISPTACH-INVALID", "missing target or args not a valid json object query=%s", json_object_get_string(queryJ));
+ goto OnErrorExit;
+ }
+
+ (void) DispatchOneControl(controls, target, argsJ, request);
+
+OnErrorExit:
+ return;
+}
+
+// Wrapper to Lua2c plugin command add context dans delegate to LuaWrapper
+PUBLIC int DispatchOneL2c(lua_State* luaState, char *funcname, Lua2cFunctionT callback) {
+#ifndef CONTROL_SUPPORT_LUA
+ AFB_ERROR("DISPATCH-ONE-L2C: LUA support not selected (cf:CONTROL_SUPPORT_LUA) in config.cmake");
+ return 1;
+#else
+ int err=Lua2cWrapper(luaState, funcname, callback, configHandle->plugin->context);
+ return err;
+#endif
+}
+
// List Avaliable Configuration Files
-PUBLIC void ctlapi_config (struct afb_req request) {
+
+PUBLIC void ctlapi_config(struct afb_req request) {
json_object*tmpJ;
char *dirList;
-
+
json_object* queryJ = afb_req_json(request);
- if (queryJ && json_object_object_get_ex (queryJ, "cfgpath" , &tmpJ)) {
- dirList = strdup (json_object_get_string(tmpJ));
- } else {
- dirList = strdup (CONTROL_CONFIG_PATH);
- AFB_NOTICE ("CONFIG-MISSING: use default CONTROL_CONFIG_PATH=%s", CONTROL_CONFIG_PATH);
+ if (queryJ && json_object_object_get_ex(queryJ, "cfgpath", &tmpJ)) {
+ dirList = strdup(json_object_get_string(tmpJ));
+ } else {
+ dirList = strdup(CONTROL_CONFIG_PATH);
+ AFB_NOTICE("CONFIG-MISSING: use default CONTROL_CONFIG_PATH=%s", CONTROL_CONFIG_PATH);
}
-
+
// get list of config file
struct json_object *responseJ = ScanForConfig(dirList, CTL_SCAN_RECURSIVE, "onload", "json");
-
+
if (json_object_array_length(responseJ) == 0) {
- afb_req_fail(request, "CONFIGPATH:EMPTY", "No Config Found in CONTROL_CONFIG_PATH");
+ afb_req_fail(request, "CONFIGPATH:EMPTY", "No Config Found in CONTROL_CONFIG_PATH");
} else {
afb_req_success(request, responseJ, NULL);
}
-
+
return;
}
// unpack individual action object
-STATIC int DispatchLoadOneAction (DispatchConfigT *controlConfig, json_object *actionJ, DispatchActionT *action) {
- char *api=NULL, *verb=NULL, *callback=NULL, *lua=NULL;
- int err, modeCount=0;
- err= wrap_json_unpack(actionJ, "{ss,s?s,s?s,s?s,s?s,s?s,s?o !}"
- , "label",&action->label, "info",&action->info, "callback",&callback, "lua", &lua, "api",&api, "verb", &verb, "args",&action->argsJ);
+STATIC int DispatchLoadOneAction(DispatchConfigT *controlConfig, json_object *actionJ, DispatchActionT *action) {
+ char *api = NULL, *verb = NULL, *callback = NULL, *lua = NULL;
+ int err, modeCount = 0;
+
+ err = wrap_json_unpack(actionJ, "{ss,s?s,s?s,s?s,s?s,s?s,s?o !}"
+ , "label", &action->label, "info", &action->info, "callback", &callback, "lua", &lua, "api", &api, "verb", &verb, "args", &action->argsJ);
if (err) {
- AFB_ERROR ("DISPATCH-LOAD-ACTION Missing something label|info|callback|lua|(api+verb)|args in %s", json_object_get_string(actionJ));
+ AFB_ERROR("DISPATCH-LOAD-ACTION Missing something label|info|callback|lua|(api+verb)|args in %s", json_object_get_string(actionJ));
goto OnErrorExit;
}
if (lua) {
action->mode = CTL_MODE_LUA;
- action->call=lua;
+ action->call = lua;
modeCount++;
}
if (api && verb) {
action->mode = CTL_MODE_API;
- action->api=api;
- action->call=verb;
+ action->api = api;
+ action->call = verb;
modeCount++;
}
- if (callback && controlConfig->dlHandle) {
+ if (callback && controlConfig->plugin) {
action->mode = CTL_MODE_CB;
- action->call=callback;
+ action->call = callback;
modeCount++;
- action->actionCB = dlsym(controlConfig->dlHandle, callback);
+ action->actionCB = dlsym(controlConfig->plugin->dlHandle, callback);
if (!action->actionCB) {
- AFB_ERROR ("DISPATCH-LOAD-ACTION fail to find calbback=%s in %s", callback, controlConfig->plugin);
+ AFB_ERROR("DISPATCH-LOAD-ACTION fail to find calbback=%s in %s", callback, controlConfig->plugin->sharelib);
goto OnErrorExit;
}
}
// make sure at least one mode is selected
if (modeCount == 0) {
- AFB_ERROR ("DISPATCH-LOAD-ACTION No Action Selected lua|callback|(api+verb) in %s", json_object_get_string(actionJ));
+ AFB_ERROR("DISPATCH-LOAD-ACTION No Action Selected lua|callback|(api+verb) in %s", json_object_get_string(actionJ));
goto OnErrorExit;
- }
+ }
if (modeCount > 1) {
- AFB_ERROR ("DISPATCH-LOAD-ACTION:ToMany arguments lua|callback|(api+verb) in %s", json_object_get_string(actionJ));
+ AFB_ERROR("DISPATCH-LOAD-ACTION:ToMany arguments lua|callback|(api+verb) in %s", json_object_get_string(actionJ));
goto OnErrorExit;
- }
- return 0;
-
+ }
+ return 0;
+
OnErrorExit:
- return -1;
+ return -1;
};
-STATIC DispatchActionT *DispatchLoadActions (DispatchConfigT *controlConfig, json_object *actionsJ) {
+STATIC DispatchActionT *DispatchLoadActions(DispatchConfigT *controlConfig, json_object *actionsJ) {
int err;
DispatchActionT *actions;
-
+
// action array is close with a nullvalue;
if (json_object_get_type(actionsJ) == json_type_array) {
int count = json_object_array_length(actionsJ);
- actions = calloc (count+1, sizeof(DispatchActionT));
-
- for (int idx=0; idx < count; idx++) {
+ actions = calloc(count + 1, sizeof (DispatchActionT));
+
+ for (int idx = 0; idx < count; idx++) {
json_object *actionJ = json_object_array_get_idx(actionsJ, idx);
- err = DispatchLoadOneAction (controlConfig, actionJ, &actions[idx]);
+ err = DispatchLoadOneAction(controlConfig, actionJ, &actions[idx]);
if (err) goto OnErrorExit;
}
-
+
} else {
- actions = calloc (2, sizeof(DispatchActionT));
- err = DispatchLoadOneAction (controlConfig, actionsJ, &actions[0]);
+ actions = calloc(2, sizeof (DispatchActionT));
+ err = DispatchLoadOneAction(controlConfig, actionsJ, &actions[0]);
if (err) goto OnErrorExit;
}
-
+
return actions;
-
- OnErrorExit:
+
+OnErrorExit:
return NULL;
-
+
}
-STATIC DispatchHandleT *DispatchLoadControl (DispatchConfigT *controlConfig, json_object *controlJ) {
- json_object *actionsJ;
+STATIC DispatchHandleT *DispatchLoadControl(DispatchConfigT *controlConfig, json_object *controlJ) {
+ json_object *actionsJ, *permissionsJ;
int err;
-
- DispatchHandleT *dispatchHandle = calloc (1, sizeof(DispatchHandleT));
- err= wrap_json_unpack(controlJ, "{ss,s?s,so !}", "label",&dispatchHandle->label, "info",&dispatchHandle->info, "actions",&actionsJ);
+
+ DispatchHandleT *dispatchHandle = calloc(1, sizeof (DispatchHandleT));
+ err = wrap_json_unpack(controlJ, "{ss,s?s,s?o, so !}", "label", &dispatchHandle->label, "info", &dispatchHandle->info
+ , "permissions", &permissionsJ, "actions", &actionsJ);
if (err) {
- AFB_ERROR ("DISPATCH-LOAD-CONFIG:CONTROL Missing something label|[info]|actions in %s", json_object_get_string(controlJ));
+ AFB_ERROR("DISPATCH-LOAD-CONFIG:CONTROL Missing something label|[info]|actions in %s", json_object_get_string(controlJ));
goto OnErrorExit;
}
- dispatchHandle->actions= DispatchLoadActions(controlConfig, actionsJ);
+ dispatchHandle->actions = DispatchLoadActions(controlConfig, actionsJ);
if (!dispatchHandle->actions) {
- AFB_ERROR ("DISPATCH-LOAD-CONFIG:CONTROL Error when parsing actions %s", dispatchHandle->label);
- goto OnErrorExit;
+ AFB_ERROR("DISPATCH-LOAD-CONFIG:CONTROL Error when parsing actions %s", dispatchHandle->label);
+ goto OnErrorExit;
}
return dispatchHandle;
-
- OnErrorExit:
- return NULL;
+
+OnErrorExit:
+ return NULL;
}
-STATIC DispatchHandleT *DispatchLoadOnload (DispatchConfigT *controlConfig, json_object *onloadJ) {
- json_object *actionsJ=NULL, *requireJ=NULL;
+STATIC DispatchHandleT *DispatchLoadOnload(DispatchConfigT *controlConfig, json_object *onloadJ) {
+ json_object *actionsJ = NULL, *requireJ = NULL, *pluginJ = NULL;
int err;
-
- DispatchHandleT *dispatchHandle = calloc (1, sizeof(DispatchHandleT));
- err= wrap_json_unpack(onloadJ, "{ss,s?s,s?s,s?o,s?o !}",
- "label",&dispatchHandle->label, "info",&dispatchHandle->info, "plugin", &controlConfig->plugin, "require", &requireJ, "actions",&actionsJ);
+
+ DispatchHandleT *dispatchHandle = calloc(1, sizeof (DispatchHandleT));
+ err = wrap_json_unpack(onloadJ, "{ss,s?s,s?o,s?o,s?o !}",
+ "label", &dispatchHandle->label, "info", &dispatchHandle->info, "plugin", &pluginJ, "require", &requireJ, "actions", &actionsJ);
if (err) {
- AFB_ERROR ("DISPATCH-LOAD-CONFIG:ONLOAD Missing something label|[info]|[plugin]|[actions] in %s", json_object_get_string(onloadJ));
+ AFB_ERROR("DISPATCH-LOAD-CONFIG:ONLOAD Missing something label|[info]|[plugin]|[actions] in %s", json_object_get_string(onloadJ));
goto OnErrorExit;
}
// best effort to initialise everything before starting
if (requireJ) {
- void DispatchRequireOneApi (json_object *bindindJ) {
+ void DispatchRequireOneApi(json_object * bindindJ) {
const char* requireBinding = json_object_get_string(bindindJ);
err = afb_daemon_require_api(requireBinding, 1);
if (err) {
- AFB_WARNING ("DISPATCH-LOAD-CONFIG:REQUIRE Fail to get=%s", requireBinding);
+ AFB_WARNING("DISPATCH-LOAD-CONFIG:REQUIRE Fail to get=%s", requireBinding);
}
}
if (json_object_get_type(requireJ) == json_type_array) {
- for (int idx=0; idx < json_object_array_length(requireJ); idx++) {
- DispatchRequireOneApi (json_object_array_get_idx(requireJ, idx));
+ for (int idx = 0; idx < json_object_array_length(requireJ); idx++) {
+ DispatchRequireOneApi(json_object_array_get_idx(requireJ, idx));
}
} else {
- DispatchRequireOneApi (requireJ);
+ DispatchRequireOneApi(requireJ);
}
}
- if (controlConfig->plugin) {
+ if (pluginJ) {
+ json_object *lua2csJ = NULL;
+ DispatchPluginT *dPlugin= calloc(1, sizeof(DispatchPluginT));
+ controlConfig->plugin = dPlugin;
+
+ err = wrap_json_unpack(pluginJ, "{ss,s?s,ss,s?o!}",
+ "label", &dPlugin->label, "info", &dPlugin->info, "sharelib", &dPlugin->sharelib, "lua2c", &lua2csJ);
+ if (err) {
+ AFB_ERROR("DISPATCH-LOAD-CONFIG:ONLOAD Plugin missing label|[info]|sharelib|[lua2c] in %s", json_object_get_string(onloadJ));
+ goto OnErrorExit;
+ }
// search for default policy config file
- json_object *pluginPathJ = ScanForConfig(CONTROL_PLUGIN_PATH , CTL_SCAN_RECURSIVE, controlConfig->plugin, NULL);
+ json_object *pluginPathJ = ScanForConfig(CONTROL_PLUGIN_PATH, CTL_SCAN_RECURSIVE, dPlugin->sharelib, NULL);
if (!pluginPathJ || json_object_array_length(pluginPathJ) == 0) {
- AFB_ERROR ("DISPATCH-LOAD-CONFIG:PLUGIN Missing plugin=%s in path=%s", controlConfig->plugin, CONTROL_PLUGIN_PATH);
- goto OnErrorExit;
+ AFB_ERROR("DISPATCH-LOAD-CONFIG:PLUGIN Missing plugin=%s in path=%s", dPlugin->sharelib, CONTROL_PLUGIN_PATH);
+ goto OnErrorExit;
}
- char *filename; char*fullpath;
- err= wrap_json_unpack (json_object_array_get_idx(pluginPathJ,0), "{s:s, s:s !}", "fullpath", &fullpath,"filename", &filename);
+ char *filename;
+ char*fullpath;
+ err = wrap_json_unpack(json_object_array_get_idx(pluginPathJ, 0), "{s:s, s:s !}", "fullpath", &fullpath, "filename", &filename);
if (err) {
- AFB_ERROR ("DISPATCH-LOAD-CONFIG:PLUGIN HOOPs invalid plugin file path = %s", json_object_get_string(pluginPathJ));
+ AFB_ERROR("DISPATCH-LOAD-CONFIG:PLUGIN HOOPs invalid plugin file path = %s", json_object_get_string(pluginPathJ));
goto OnErrorExit;
}
if (json_object_array_length(pluginPathJ) > 1) {
- AFB_WARNING ("DISPATCH-LOAD-CONFIG:PLUGIN plugin multiple instances in searchpath will use %s/%s", fullpath, filename);
+ AFB_WARNING("DISPATCH-LOAD-CONFIG:PLUGIN plugin multiple instances in searchpath will use %s/%s", fullpath, filename);
}
char pluginpath[CONTROL_MAXPATH_LEN];
- strncpy(pluginpath, fullpath, sizeof(pluginpath));
- strncat(pluginpath, "/", sizeof(pluginpath));
- strncat(pluginpath, filename, sizeof(pluginpath));
- controlConfig->dlHandle = dlopen(pluginpath, RTLD_NOW);
- if (!controlConfig->dlHandle) {
- AFB_ERROR ("DISPATCH-LOAD-CONFIG:PLUGIN Fail to load pluginpath=%s err= %s", pluginpath, dlerror());
+ strncpy(pluginpath, fullpath, sizeof (pluginpath));
+ strncat(pluginpath, "/", sizeof (pluginpath));
+ strncat(pluginpath, filename, sizeof (pluginpath));
+ dPlugin->dlHandle = dlopen(pluginpath, RTLD_NOW);
+ if (!dPlugin->dlHandle) {
+ AFB_ERROR("DISPATCH-LOAD-CONFIG:PLUGIN Fail to load pluginpath=%s err= %s", pluginpath, dlerror());
goto OnErrorExit;
}
- CtlPluginMagicT *ctlPluginMagic = (CtlPluginMagicT*)dlsym(controlConfig->dlHandle, "CtlPluginMagic");
+ CtlPluginMagicT *ctlPluginMagic = (CtlPluginMagicT*) dlsym(dPlugin->dlHandle, "CtlPluginMagic");
if (!ctlPluginMagic || ctlPluginMagic->magic != CTL_PLUGIN_MAGIC) {
AFB_ERROR("DISPATCH-LOAD-CONFIG:Plugin symbol'CtlPluginMagic' missing or != CTL_PLUGIN_MAGIC plugin=%s", pluginpath);
goto OnErrorExit;
@@ -355,173 +416,229 @@ STATIC DispatchHandleT *DispatchLoadOnload (DispatchConfigT *controlConfig, jso
}
// Jose hack to make verbosity visible from sharelib
- struct afb_binding_data_v2 *afbHidenData = dlsym(controlConfig->dlHandle, "afbBindingV2data");
- if (afbHidenData) *afbHidenData = afbBindingV2data;
+ struct afb_binding_data_v2 *afbHidenData = dlsym(dPlugin->dlHandle, "afbBindingV2data");
+ if (afbHidenData) *afbHidenData = afbBindingV2data;
+
+ // Push lua2cWrapper @ into plugin
+ Lua2cWrapperT *lua2cInPlug = dlsym(dPlugin->dlHandle, "Lua2cWrap");
+#ifndef CONTROL_SUPPORT_LUA
+ if (lua2cInPlug) *lua2cInPlug = NULL;
+#else
+ // Lua2cWrapper is part of binder and not expose to dynamic link
+ if (lua2cInPlug) *lua2cInPlug = DispatchOneL2c;
+
+ {
+ int Lua2cAddOne(luaL_Reg *l2cFunc, const char* l2cName, int index) {
+ char funcName[CONTROL_MAXPATH_LEN];
+ strncpy(funcName, "lua2c_", sizeof(funcName));
+ strncat(funcName, l2cName, sizeof(funcName));
+
+ Lua2cFunctionT l2cFunction= (Lua2cFunctionT)dlsym(dPlugin->dlHandle, funcName);
+ if (!l2cFunction) {
+ AFB_ERROR("DISPATCH-LOAD-CONFIG:Plugin symbol'%s' missing err=%s", funcName, dlerror());
+ return 1;
+ }
+ l2cFunc[index].func=(void*)l2cFunction;
+ l2cFunc[index].name=strdup(l2cName);
+
+ return 0;
+ }
- DispatchPluginInstallCbT ctlPluginOnload = dlsym(controlConfig->dlHandle, "CtlPluginOnload");
+ int errCount = 0;
+ luaL_Reg *l2cFunc=NULL;
+ int count=0;
+
+ // look on l2c command and push them to LUA
+ if (json_object_get_type(lua2csJ) == json_type_array) {
+ int length = json_object_array_length(lua2csJ);
+ l2cFunc = calloc(length + 1, sizeof (luaL_Reg));
+ for (count=0; count < length; count++) {
+ int err;
+ const char *l2cName = json_object_get_string(json_object_array_get_idx(lua2csJ, count));
+ err = Lua2cAddOne(l2cFunc, l2cName, count);
+ if (err) errCount++;
+ }
+ } else {
+ l2cFunc = calloc(2, sizeof (luaL_Reg));
+ const char *l2cName = json_object_get_string(lua2csJ);
+ errCount = Lua2cAddOne(l2cFunc, l2cName, 0);
+ count=1;
+ }
+ if (errCount) {
+ AFB_ERROR("DISPATCH-LOAD-CONFIG:Plugin %d symbols not found in plugin='%s'", errCount, pluginpath);
+ goto OnErrorExit;
+ } else {
+ dPlugin->l2cFunc= l2cFunc;
+ dPlugin->l2cCount= count;
+ }
+ }
+#endif
+ DispatchPluginInstallCbT ctlPluginOnload = dlsym(dPlugin->dlHandle, "CtlPluginOnload");
if (ctlPluginOnload) {
- controlConfig->context = (*ctlPluginOnload) (controlConfig->label, controlConfig->version, controlConfig->info);
+ dPlugin->context = (*ctlPluginOnload) (controlConfig->label, controlConfig->version, controlConfig->info);
}
}
- dispatchHandle->actions= DispatchLoadActions(controlConfig, actionsJ);
+ dispatchHandle->actions = DispatchLoadActions(controlConfig, actionsJ);
if (!dispatchHandle->actions) {
- AFB_ERROR ("DISPATCH-LOAD-CONFIG:ONLOAD Error when parsing actions %s", dispatchHandle->label);
- goto OnErrorExit;
+ AFB_ERROR("DISPATCH-LOAD-CONFIG:ONLOAD Error when parsing actions %s", dispatchHandle->label);
+ goto OnErrorExit;
}
return dispatchHandle;
-
- OnErrorExit:
- return NULL;
+
+OnErrorExit:
+ return NULL;
}
-STATIC DispatchConfigT *DispatchLoadConfig (const char* filepath) {
+STATIC DispatchConfigT *DispatchLoadConfig(const char* filepath) {
json_object *controlConfigJ, *ignoreJ;
int err;
-
+
// Load JSON file
- controlConfigJ= json_object_from_file(filepath);
+ controlConfigJ = json_object_from_file(filepath);
if (!controlConfigJ) {
- AFB_ERROR ("DISPATCH-LOAD-CONFIG:JsonLoad invalid JSON %s ", filepath);
+ AFB_ERROR("DISPATCH-LOAD-CONFIG:JsonLoad invalid JSON %s ", filepath);
goto OnErrorExit;
}
-
- AFB_INFO ("DISPATCH-LOAD-CONFIG: loading config filepath=%s", filepath);
-
- json_object *metadataJ=NULL, *onloadsJ=NULL, *controlsJ=NULL, *eventsJ=NULL;
- err= wrap_json_unpack(controlConfigJ, "{s?o,so,s?o,s?o,s?o !}", "$schema", &ignoreJ, "metadata",&metadataJ, "onload",&onloadsJ, "controls",&controlsJ, "events",&eventsJ);
+
+ AFB_INFO("DISPATCH-LOAD-CONFIG: loading config filepath=%s", filepath);
+
+ json_object *metadataJ = NULL, *onloadsJ = NULL, *controlsJ = NULL, *eventsJ = NULL;
+ err = wrap_json_unpack(controlConfigJ, "{s?o,so,s?o,s?o,s?o !}", "$schema", &ignoreJ, "metadata", &metadataJ, "onload", &onloadsJ, "controls", &controlsJ, "events", &eventsJ);
if (err) {
- AFB_ERROR ("DISPATCH-LOAD-CONFIG Missing something metadata|[onload]|[controls]|[events] in %s", json_object_get_string(controlConfigJ));
+ AFB_ERROR("DISPATCH-LOAD-CONFIG Missing something metadata|[onload]|[controls]|[events] in %s", json_object_get_string(controlConfigJ));
goto OnErrorExit;
}
-
- DispatchConfigT *controlConfig = calloc (1, sizeof(DispatchConfigT));
+
+ DispatchConfigT *controlConfig = calloc(1, sizeof (DispatchConfigT));
if (metadataJ) {
- err= wrap_json_unpack(metadataJ, "{ss,s?s,ss !}", "label", &controlConfig->label, "info",&controlConfig->info, "version",&controlConfig->version);
+ err = wrap_json_unpack(metadataJ, "{ss,s?s,ss !}", "label", &controlConfig->label, "info", &controlConfig->info, "version", &controlConfig->version);
if (err) {
- AFB_ERROR ("DISPATCH-LOAD-CONFIG:METADATA Missing something label|version|[label] in %s", json_object_get_string(metadataJ));
+ AFB_ERROR("DISPATCH-LOAD-CONFIG:METADATA Missing something label|version|[label] in %s", json_object_get_string(metadataJ));
goto OnErrorExit;
}
- }
-
+ }
+
if (onloadsJ) {
DispatchHandleT *dispatchHandle;
-
+
if (json_object_get_type(onloadsJ) != json_type_array) {
- controlConfig->onloads = (DispatchHandleT**) calloc (2, sizeof(void*));
- dispatchHandle = DispatchLoadOnload (controlConfig, onloadsJ);
- controlConfig->onloads[0]= dispatchHandle;
- } else {
- int length= json_object_array_length(onloadsJ);
- controlConfig->onloads = (DispatchHandleT**) calloc (length+1, sizeof(void*));
-
- for (int jdx=0; jdx< length; jdx++) {
- json_object *onloadJ = json_object_array_get_idx(onloadsJ,jdx);
- dispatchHandle = DispatchLoadOnload (controlConfig, onloadJ);
- controlConfig->onloads[jdx]= dispatchHandle;
+ controlConfig->onloads = (DispatchHandleT**) calloc(2, sizeof (void*));
+ dispatchHandle = DispatchLoadOnload(controlConfig, onloadsJ);
+ controlConfig->onloads[0] = dispatchHandle;
+ } else {
+ int length = json_object_array_length(onloadsJ);
+ controlConfig->onloads = (DispatchHandleT**) calloc(length + 1, sizeof (void*));
+
+ for (int jdx = 0; jdx < length; jdx++) {
+ json_object *onloadJ = json_object_array_get_idx(onloadsJ, jdx);
+ dispatchHandle = DispatchLoadOnload(controlConfig, onloadJ);
+ controlConfig->onloads[jdx] = dispatchHandle;
}
- }
+ }
}
-
+
if (controlsJ) {
DispatchHandleT *dispatchHandle;
-
+
if (json_object_get_type(controlsJ) != json_type_array) {
- controlConfig->controls = (DispatchHandleT**) calloc (2, sizeof(void*));
- dispatchHandle = DispatchLoadControl (controlConfig, controlsJ);
- controlConfig->controls[0]= dispatchHandle;
- } else {
- int length= json_object_array_length(controlsJ);
- controlConfig->controls = (DispatchHandleT**) calloc (length+1, sizeof(void*));
-
- for (int jdx=0; jdx< length; jdx++) {
- json_object *controlJ = json_object_array_get_idx(controlsJ,jdx);
- dispatchHandle = DispatchLoadControl (controlConfig, controlJ);
- controlConfig->controls[jdx]= dispatchHandle;
+ controlConfig->controls = (DispatchHandleT**) calloc(2, sizeof (void*));
+ dispatchHandle = DispatchLoadControl(controlConfig, controlsJ);
+ controlConfig->controls[0] = dispatchHandle;
+ } else {
+ int length = json_object_array_length(controlsJ);
+ controlConfig->controls = (DispatchHandleT**) calloc(length + 1, sizeof (void*));
+
+ for (int jdx = 0; jdx < length; jdx++) {
+ json_object *controlJ = json_object_array_get_idx(controlsJ, jdx);
+ dispatchHandle = DispatchLoadControl(controlConfig, controlJ);
+ controlConfig->controls[jdx] = dispatchHandle;
}
- }
+ }
}
-
+
if (eventsJ) {
DispatchHandleT *dispatchHandle;
-
+
if (json_object_get_type(eventsJ) != json_type_array) {
- controlConfig->events = (DispatchHandleT**) calloc (2, sizeof(void*));
- dispatchHandle = DispatchLoadControl (controlConfig, eventsJ);
- controlConfig->events[0]= dispatchHandle;
- } else {
- int length= json_object_array_length(eventsJ);
- controlConfig->events = (DispatchHandleT**) calloc (length+1, sizeof(void*));
-
- for (int jdx=0; jdx< length; jdx++) {
- json_object *eventJ = json_object_array_get_idx(eventsJ,jdx);
- dispatchHandle = DispatchLoadControl (controlConfig, eventJ);
- controlConfig->events[jdx]= dispatchHandle;
+ controlConfig->events = (DispatchHandleT**) calloc(2, sizeof (void*));
+ dispatchHandle = DispatchLoadControl(controlConfig, eventsJ);
+ controlConfig->events[0] = dispatchHandle;
+ } else {
+ int length = json_object_array_length(eventsJ);
+ controlConfig->events = (DispatchHandleT**) calloc(length + 1, sizeof (void*));
+
+ for (int jdx = 0; jdx < length; jdx++) {
+ json_object *eventJ = json_object_array_get_idx(eventsJ, jdx);
+ dispatchHandle = DispatchLoadControl(controlConfig, eventJ);
+ controlConfig->events[jdx] = dispatchHandle;
}
}
}
-
+
return controlConfig;
-
+
OnErrorExit:
return NULL;
}
// Load default config file at init
-PUBLIC int DispatchInit () {
- int index, err, luaLoaded=0;
+
+PUBLIC int DispatchInit() {
+ int index, err, luaLoaded = 0;
char controlFile [CONTROL_MAXPATH_LEN];
-
- strncpy (controlFile,CONTROL_CONFIG_PRE, CONTROL_MAXPATH_LEN);
- strncat (controlFile,"-", CONTROL_MAXPATH_LEN);
- strncat (controlFile,GetBinderName(), CONTROL_MAXPATH_LEN);
-
+
+ strncpy(controlFile, CONTROL_CONFIG_PRE, CONTROL_MAXPATH_LEN);
+ strncat(controlFile, "-", CONTROL_MAXPATH_LEN);
+ strncat(controlFile, GetBinderName(), CONTROL_MAXPATH_LEN);
+
// search for default dispatch config file
- json_object* responseJ = ScanForConfig(CONTROL_CONFIG_PATH, CTL_SCAN_RECURSIVE,controlFile, "json");
+ json_object* responseJ = ScanForConfig(CONTROL_CONFIG_PATH, CTL_SCAN_RECURSIVE, controlFile, "json");
// We load 1st file others are just warnings
- for (index=0; index < json_object_array_length(responseJ); index++) {
- json_object *entryJ=json_object_array_get_idx(responseJ, index);
-
- char *filename; char*fullpath;
- err= wrap_json_unpack (entryJ, "{s:s, s:s !}", "fullpath", &fullpath,"filename", &filename);
+ for (index = 0; index < json_object_array_length(responseJ); index++) {
+ json_object *entryJ = json_object_array_get_idx(responseJ, index);
+
+ char *filename;
+ char*fullpath;
+ err = wrap_json_unpack(entryJ, "{s:s, s:s !}", "fullpath", &fullpath, "filename", &filename);
if (err) {
- AFB_ERROR ("DISPATCH-INIT HOOPs invalid JSON entry= %s", json_object_get_string(entryJ));
+ AFB_ERROR("DISPATCH-INIT HOOPs invalid JSON entry= %s", json_object_get_string(entryJ));
goto OnErrorExit;
}
if (index == 0) {
if (strcasestr(filename, controlFile)) {
char filepath[CONTROL_MAXPATH_LEN];
- strncpy(filepath, fullpath, sizeof(filepath));
- strncat(filepath, "/", sizeof(filepath));
- strncat(filepath, filename, sizeof(filepath));
- configHandle = DispatchLoadConfig (filepath);
+ strncpy(filepath, fullpath, sizeof (filepath));
+ strncat(filepath, "/", sizeof (filepath));
+ strncat(filepath, filename, sizeof (filepath));
+ configHandle = DispatchLoadConfig(filepath);
if (!configHandle) {
- AFB_ERROR ("DISPATCH-INIT:ERROR Fail loading [%s]", filepath);
+ AFB_ERROR("DISPATCH-INIT:ERROR Fail loading [%s]", filepath);
goto OnErrorExit;
}
- luaLoaded=1;
+ luaLoaded = 1;
break;
}
} else {
- AFB_WARNING ("DISPATCH-INIT:WARNING Secondary Control Config Ignored %s/%s", fullpath, filename);
+ AFB_WARNING("DISPATCH-INIT:WARNING Secondary Control Config Ignored %s/%s", fullpath, filename);
}
}
-
+
// no dispatch config found remove control API from binder
- if (!luaLoaded) {
- AFB_WARNING ("DISPATCH-INIT:WARNING Not Found Control dispatch file [%s]", controlFile);
+ if (!luaLoaded) {
+ AFB_WARNING("DISPATCH-INIT:WARNING Not Found Control dispatch file [%s]", controlFile);
}
-
- AFB_NOTICE ("DISPATCH-INIT:SUCCES: Audio Control Dispatch Init");
+
+ AFB_NOTICE("DISPATCH-INIT:SUCCES: Audio Control Dispatch Init");
return 0;
-
+
OnErrorExit:
- AFB_NOTICE ("DISPATCH-INIT:ERROR: Audio Control Dispatch Init");
- return 1;
+ AFB_NOTICE("DISPATCH-INIT:ERROR: Audio Control Dispatch Init");
+ return 1;
}
-
-
+
+
diff --git a/Controler-afb/ctl-lua.c b/Controler-afb/ctl-lua.c
index bf02a31..affeb83 100644
--- a/Controler-afb/ctl-lua.c
+++ b/Controler-afb/ctl-lua.c
@@ -24,15 +24,12 @@
#include <stdio.h>
#include <string.h>
-#include "lua.h"
-#include "lauxlib.h"
-#include "lualib.h"
#include "ctl-binding.h"
#include "wrap-json.h"
#define LUA_FIST_ARG 2 // when using luaL_newlib calllback receive libtable as 1st arg
-#define LUA_MSG_MAX_LENGTH 255
+#define LUA_MSG_MAX_LENGTH 512
#define JSON_ERROR (json_object*)-1
static lua_State* luaState;
@@ -160,20 +157,23 @@ STATIC json_object *PopOneArg (lua_State* luaState, int idx);
STATIC json_object *LuaTableToJson (lua_State* luaState, int index) {
int idx;
+ #define LUA_KEY_INDEX -2
+ #define LUA_VALUE_INDEX -1
json_object *tableJ= json_object_new_object();
const char *key;
char number[3];
lua_pushnil(luaState); // 1st key
+ if (index < 0) index--; // nested table https://stackoverflow.com/questions/45699144/lua-nested-table-from-lua-to-c
for (idx=1; lua_next(luaState, index) != 0; idx++) {
// uses 'key' (at index -2) and 'value' (at index -1)
- if (lua_type(luaState,-2) == LUA_TSTRING) key= lua_tostring(luaState, -2);
+ if (lua_type(luaState,LUA_KEY_INDEX) == LUA_TSTRING) key= lua_tostring(luaState, LUA_KEY_INDEX);
else {
snprintf(number, sizeof(number),"%d", idx);
key=number;
}
- json_object *argJ= PopOneArg(luaState, -1);
+ json_object *argJ= PopOneArg(luaState, LUA_VALUE_INDEX);
json_object_object_add(tableJ, key, argJ);
lua_pop(luaState, 1); // removes 'value'; keeps 'key' for next iteration
}
@@ -207,14 +207,9 @@ STATIC json_object *PopOneArg (lua_State* luaState, int idx) {
case LUA_TSTRING:
value= json_object_new_string(lua_tostring(luaState, idx));
break;
- case LUA_TTABLE: {
- if (idx > 0) {
- value= LuaTableToJson(luaState, idx);
- } else {
- value= json_object_new_string("UNSUPPORTED_Lua_Nested_Table");
- }
+ case LUA_TTABLE:
+ value= LuaTableToJson(luaState, idx);
break;
- }
case LUA_TNIL:
value=json_object_new_string("nil") ;
break;
@@ -308,7 +303,13 @@ STATIC int LuaFormatMessage(lua_State* luaState, LuaAfbMessageT action) {
}
} else {
- message[targetIdx++] = format[idx];
+ if (targetIdx >= LUA_MSG_MAX_LENGTH) {
+ AFB_WARNING ("LuaFormatMessage: message[%s] owerverflow LUA_MSG_MAX_LENGTH=%d", format, LUA_MSG_MAX_LENGTH);
+ targetIdx --; // move backward for EOL
+ break;
+ } else {
+ message[targetIdx++] = format[idx];
+ }
}
}
message[targetIdx]='\0';
@@ -357,7 +358,7 @@ STATIC int LuaPrintNotice(lua_State* luaState) {
return err;
}
-STATIC int LuaPrintDebug(lua_State* luaState) {
+STATIC int LuaPrintDebug(lua_State* luaState) {
int err=LuaFormatMessage (luaState, AFB_MSG_DEBUG);
return err;
}
@@ -535,6 +536,16 @@ STATIC int LuaAfbPushEvent(lua_State* luaState) {
return 1;
}
+// Function call from LUA when lua2c plugin L2C is used
+PUBLIC int Lua2cWrapper(lua_State* luaState, char *funcname, Lua2cFunctionT callback, void *context) {
+
+ json_object *argsJ= LuaPopArgs(luaState, LUA_FIST_ARG);
+ int response = (*callback) (funcname, argsJ, context);
+
+ // push response to LUA
+ lua_pushinteger(luaState, response);
+ return 1;
+}
// Generated some fake event based on watchdog/counter
PUBLIC int LuaCallFunc (DispatchActionT *action, json_object *queryJ) {
@@ -733,6 +744,15 @@ PUBLIC void ctlapi_lua_doscript (afb_req request) {
LuaDoAction (LUA_DOSCRIPT, request);
}
+// Register a new L2c list of LUA user plugin commands
+PUBLIC void LuaL2cNewLib(const char *label, luaL_Reg *l2cFunc, int count) {
+ // luaL_newlib(luaState, l2cFunc); macro does not work with pointer :(
+ luaL_checkversion(luaState);
+ lua_createtable(luaState, 0, count+1);
+ luaL_setfuncs(luaState,l2cFunc,0);
+ lua_setglobal(luaState, label);
+}
+
static const luaL_Reg afbFunction[] = {
{"notice" , LuaPrintNotice},
{"info" , LuaPrintInfo},
diff --git a/Controler-afb/ctl-plugin-sample.c b/Controler-afb/ctl-plugin-sample.c
index 837ad9d..1d24487 100644
--- a/Controler-afb/ctl-plugin-sample.c
+++ b/Controler-afb/ctl-plugin-sample.c
@@ -31,9 +31,6 @@ typedef struct {
int count;
} MyPluginCtxT;
-// Declare this sharelib as a Controller Plugin
-CTL_PLUGIN_REGISTER("MyCtlSamplePlugin");
-
STATIC const char* jsonToString (json_object *valueJ) {
const char *value;
if (valueJ)
@@ -44,8 +41,11 @@ STATIC const char* jsonToString (json_object *valueJ) {
return value;
}
+// Declare this sharelib as a Controller Plugin
+CTLP_REGISTER("MyCtlSamplePlugin");
+
// Call at initialisation time
-PUBLIC void* CtlPluginOnload(char* label, char* version, char* info) {
+PUBLIC CTLP_ONLOAD(label, version, info) {
MyPluginCtxT *pluginCtx= (MyPluginCtxT*)calloc (1, sizeof(MyPluginCtxT));
pluginCtx->magic = MY_PLUGIN_MAGIC;
pluginCtx->count = -1;
@@ -54,7 +54,7 @@ PUBLIC void* CtlPluginOnload(char* label, char* version, char* info) {
return (void*)pluginCtx;
}
-PUBLIC int SamplePolicyInit (DispatchActionT *action, json_object *argsJ, void *context) {
+PUBLIC CTLP_CAPI (SamplePolicyInit, label, argsJ, queryJ, context) {
MyPluginCtxT *pluginCtx= (MyPluginCtxT*)context;
if (!context || pluginCtx->magic != MY_PLUGIN_MAGIC) {
AFB_ERROR("CONTROLER-PLUGIN-SAMPLE:SamplePolicyInit (Hoops) Invalid Sample Plugin Context");
@@ -62,11 +62,11 @@ PUBLIC int SamplePolicyInit (DispatchActionT *action, json_object *argsJ, void *
};
pluginCtx->count = 0;
- AFB_NOTICE ("CONTROLER-PLUGIN-SAMPLE:Init label=%s args=%s\n", action->label, jsonToString(action->argsJ));
+ AFB_NOTICE ("CONTROLER-PLUGIN-SAMPLE:Init label=%s args=%s\n", label, jsonToString(argsJ));
return 0;
}
-PUBLIC int sampleControlMultimedia (DispatchActionT *action, json_object *queryJ, void *context) {
+PUBLIC CTLP_CAPI (sampleControlMultimedia,label, argsJ,queryJ,context) {
MyPluginCtxT *pluginCtx= (MyPluginCtxT*)context;
if (!context || pluginCtx->magic != MY_PLUGIN_MAGIC) {
@@ -75,11 +75,11 @@ PUBLIC int sampleControlMultimedia (DispatchActionT *action, json_object *queryJ
};
pluginCtx->count++;
AFB_NOTICE ("CONTROLER-PLUGIN-SAMPLE:sampleControlMultimedia SamplePolicyCount action=%s args=%s query=%s count=%d"
- , action->label, jsonToString(action->argsJ), jsonToString(queryJ), pluginCtx->count);
+ , label, jsonToString(argsJ), jsonToString(queryJ), pluginCtx->count);
return 0;
}
-PUBLIC int sampleControlNavigation (DispatchActionT *action, json_object *queryJ, void *context) {
+PUBLIC CTLP_CAPI (sampleControlNavigation, label, argsJ, queryJ, context) {
MyPluginCtxT *pluginCtx= (MyPluginCtxT*)context;
if (!context || pluginCtx->magic != MY_PLUGIN_MAGIC) {
@@ -88,11 +88,11 @@ PUBLIC int sampleControlNavigation (DispatchActionT *action, json_object *queryJ
};
pluginCtx->count++;
AFB_NOTICE ("CONTROLER-PLUGIN-SAMPLE:sampleControlNavigation SamplePolicyCount action=%s args=%s query=%s count=%d"
- ,action->label, jsonToString(action->argsJ), jsonToString(queryJ), pluginCtx->count);
+ ,label, jsonToString(argsJ), jsonToString(queryJ), pluginCtx->count);
return 0;
}
-PUBLIC int SampleControlEvent (DispatchActionT *action, json_object *queryJ, void *context) {
+PUBLIC CTLP_CAPI (SampleControlEvent, label, argsJ, queryJ, context) {
MyPluginCtxT *pluginCtx= (MyPluginCtxT*)context;
if (!context || pluginCtx->magic != MY_PLUGIN_MAGIC) {
@@ -101,6 +101,34 @@ PUBLIC int SampleControlEvent (DispatchActionT *action, json_object *queryJ, voi
};
pluginCtx->count++;
AFB_NOTICE ("CONTROLER-PLUGIN-SAMPLE:sampleControlMultimedia SamplePolicyCount action=%s args=%s query=%s count=%d"
- ,action->label, jsonToString(action->argsJ), jsonToString(queryJ), pluginCtx->count);
+ ,label, jsonToString(argsJ), jsonToString(queryJ), pluginCtx->count);
+ return 0;
+}
+
+// This function is a LUA function. Lua2CHelloWorld label should be declare in the "onload" section of JSON config file
+PUBLIC CTLP_LUA2C (Lua2cHelloWorld1, label, argsJ, context) {
+ MyPluginCtxT *pluginCtx= (MyPluginCtxT*)context;
+
+ if (!context || pluginCtx->magic != MY_PLUGIN_MAGIC) {
+ AFB_ERROR("CONTROLER-PLUGIN-SAMPLE:Lua2cHelloWorld1 (Hoops) Invalid Sample Plugin Context");
+ return -1;
+ };
+ pluginCtx->count++;
+ AFB_NOTICE ("CONTROLER-PLUGIN-SAMPLE:Lua2cHelloWorld1 SamplePolicyCount action=%s args=%s count=%d"
+ ,label, jsonToString(argsJ), pluginCtx->count);
+ return 0;
+}
+
+// This function is a LUA function. Lua2CHelloWorld label should be declare in the "onload" section of JSON config file
+PUBLIC CTLP_LUA2C (Lua2cHelloWorld2, label, argsJ, context) {
+ MyPluginCtxT *pluginCtx= (MyPluginCtxT*)context;
+
+ if (!context || pluginCtx->magic != MY_PLUGIN_MAGIC) {
+ AFB_ERROR("CONTROLER-PLUGIN-SAMPLE:Lua2cHelloWorld2 (Hoops) Invalid Sample Plugin Context");
+ return -1;
+ };
+ pluginCtx->count++;
+ AFB_NOTICE ("CONTROLER-PLUGIN-SAMPLE:Lua2cHelloWorld2 SamplePolicyCount action=%s args=%s count=%d"
+ ,label, jsonToString(argsJ), pluginCtx->count);
return 0;
}