diff options
-rw-r--r-- | ctl-lib/CMakeLists.txt | 2 | ||||
-rw-r--r-- | ctl-lib/ctl-action.c | 119 | ||||
-rw-r--r-- | ctl-lib/ctl-config.c | 122 | ||||
-rw-r--r-- | ctl-lib/ctl-config.h | 87 | ||||
-rw-r--r-- | ctl-lib/ctl-control.c | 43 | ||||
-rw-r--r-- | ctl-lib/ctl-event.c | 94 | ||||
-rw-r--r-- | ctl-lib/ctl-lua.c | 564 | ||||
-rw-r--r-- | ctl-lib/ctl-lua.h | 15 | ||||
-rw-r--r-- | ctl-lib/ctl-onload.c | 28 | ||||
-rw-r--r-- | ctl-lib/ctl-plugin.c | 64 | ||||
-rw-r--r-- | ctl-lib/ctl-plugin.h | 176 | ||||
-rw-r--r-- | ctl-lib/ctl-timer.c | 28 | ||||
-rw-r--r-- | ctl-lib/ctl-timer.h | 8 |
13 files changed, 886 insertions, 464 deletions
diff --git a/ctl-lib/CMakeLists.txt b/ctl-lib/CMakeLists.txt index 6f765d8..2630b94 100644 --- a/ctl-lib/CMakeLists.txt +++ b/ctl-lib/CMakeLists.txt @@ -30,7 +30,7 @@ endif(CONTROL_SUPPORT_LUA) PROJECT_TARGET_ADD(ctl-utilities) # Define project Targets - ADD_LIBRARY(${TARGET_NAME} STATIC ctl-action.c ctl-config.c ctl-onload.c ctl-plugin.c ${CTL_LUA_SOURCE}) + ADD_LIBRARY(${TARGET_NAME} STATIC ctl-action.c ctl-config.c ctl-onload.c ctl-plugin.c ctl-control.c ctl-event.c ${CTL_LUA_SOURCE}) # Library dependencies (include updates automatically) TARGET_LINK_LIBRARIES(${TARGET_NAME} diff --git a/ctl-lib/ctl-action.c b/ctl-lib/ctl-action.c index b24269c..fa0fa6f 100644 --- a/ctl-lib/ctl-action.c +++ b/ctl-lib/ctl-action.c @@ -24,11 +24,18 @@ #include "ctl-config.h" +PUBLIC int ActionLabelToIndex(CtlActionT*actions, const char* actionLabel) { -PUBLIC int ActionExecOne(CtlActionT* action, json_object *queryJ) { - int err; + for (int idx = 0; actions[idx].label; idx++) { + if (!strcasecmp(actionLabel, actions[idx].label)) return idx; + } + return -1; +} +PUBLIC void ActionExecOne(CtlSourceT *source, CtlActionT* action, json_object *queryJ) { + int err; + switch (action->type) { case CTL_TYPE_API: { @@ -51,92 +58,123 @@ PUBLIC int ActionExecOne(CtlActionT* action, json_object *queryJ) { } } - json_object_object_add(queryJ, "label", json_object_new_string(action->source.label)); + json_object_object_add(queryJ, "label", json_object_new_string(source->label)); - int err = afb_service_call_sync(action->api, action->call, queryJ, &returnJ); + int err = AFB_ServiceSync(action->api, action->exec.subcall.api, action->exec.subcall.verb, queryJ, &returnJ); if (err) { - static const char*format = "ActionExecOne(Api) api=%s verb=%s args=%s"; - AFB_ERROR(format, action->api, action->call, action->source.label); - goto OnErrorExit; + AFB_ApiError(action->api, "ActionExecOne(AppFw) label=%s api=%s verb=%s args=%s", source->label, action->exec.subcall.api, action->exec.subcall.verb, json_object_get_string(action->argsJ)); } break; } #ifdef CONTROL_SUPPORT_LUA case CTL_TYPE_LUA: - err = LuaCallFunc(action, queryJ); + err = LuaCallFunc(source, action, queryJ); if (err) { - AFB_ERROR("ActionExecOne(Lua) label=%s func=%s args=%s", action->source.label, action->call, json_object_get_string(action->argsJ)); - goto OnErrorExit; + AFB_ApiError(action->api, "ActionExecOne(Lua) label=%s func=%s args=%s", source->label, action->exec.lua.funcname, json_object_get_string(action->argsJ)); } break; #endif case CTL_TYPE_CB: - err = (*action->actionCB) (&action->source, action->argsJ, queryJ); + err = (*action->exec.cb.callback) (source, action->argsJ, queryJ); if (err) { - AFB_ERROR("ActionExecOne(Callback) label%s func=%s args=%s", action->source.label, action->call, json_object_get_string(action->argsJ)); - goto OnErrorExit; + AFB_ApiError(action->api, "ActionExecOne(Callback) label%s plugin=%s function=%s args=%s", source->label, action->exec.cb.plugin->label, action->exec.cb.funcname, json_object_get_string(action->argsJ)); } break; default: { - AFB_ERROR("ActionExecOne(unknown) API type label=%s", action->source.label); - goto OnErrorExit; + AFB_ApiError(action->api, "ActionExecOne(unknown) API type label=%s", source->label); + break; } } +} - return 0; -OnErrorExit: - return -1; +// Direct Request Call in APIV3 +#ifdef AFB_BINDING_PREV3 +STATIC void ActionDynRequest (AFB_ReqT request) { + + // retrieve action handle from request and execute the request + json_object *queryJ = afb_request_json(request); + CtlActionT* action = (CtlActionT*)afb_request_get_vcbdata(request); + + CtlSourceT source; + source.label = action->label; + source.request = request; + source.api = action->api; + + // provide request and execute the action + ActionExecOne(&source, action, queryJ); } - +#endif // unpack individual action object -PUBLIC int ActionLoadOne(CtlActionT *action, json_object *actionJ) { - char *api = NULL, *verb = NULL, *lua = NULL; +PUBLIC int ActionLoadOne(AFB_ApiT apiHandle, CtlActionT *action, json_object *actionJ, int exportApi) { int err, modeCount = 0; - json_object *callbackJ=NULL; + json_object *callbackJ=NULL, *luaJ=NULL, *subcallJ=NULL; - err = wrap_json_unpack(actionJ, "{ss,s?s,s?o,s?s,s?s,s?s,s?o !}" - , "label", &action->source.label, "info", &action->source.info, "callback", &callbackJ, "lua", &lua, "api", &api, "verb", &verb, "args", &action->argsJ); + err = wrap_json_unpack(actionJ, "{ss,s?s,s?o,s?o,s?o,s?o !}" + , "label", &action->label, "info", &action->info, "callback", &callbackJ, "lua", &luaJ, "subcall", &subcallJ, "args", &action->argsJ); if (err) { - AFB_ERROR("ACTION-LOAD-ONE Missing something label|info|callback|lua|(api+verb)|args in:\n-- %s", json_object_get_string(actionJ)); + AFB_ApiError(apiHandle,"ACTION-LOAD-ONE Action missing label|[info]|[callback]|[lua]|[subcall]|[args] in:\n-- %s", json_object_get_string(actionJ)); goto OnErrorExit; } + + // save per action api handle + action->api = apiHandle; + + // in API V3 each control is optionally map to a verb +#ifdef AFB_BINDING_PREV3 + if (apiHandle && exportApi) { + err = afb_dynapi_add_verb(apiHandle, action->label, action->info, ActionDynRequest, action, NULL, 0); + if (err) { + AFB_ApiError(apiHandle,"ACTION-LOAD-ONE fail to register API verb=%s", action->label); + goto OnErrorExit; + } + action->api = apiHandle; + } +#endif - if (lua) { - action->type = CTL_TYPE_LUA; - action->call = lua; + if (luaJ) { modeCount++; + action->type = CTL_TYPE_LUA; + err = wrap_json_unpack(luaJ, "{s?s,s:s !}", "load", &action->exec.lua.load, "func", &action->exec.lua.funcname); + if (err) { + AFB_ApiError(apiHandle,"ACTION-LOAD-ONE Lua missing [load]|func in:\n-- %s", json_object_get_string(luaJ)); + goto OnErrorExit; + } } - if (api && verb) { - action->type = CTL_TYPE_API; - action->api = api; - action->call = verb; + if (subcallJ) { modeCount++; + action->type = CTL_TYPE_API; + + err = wrap_json_unpack(luaJ, "{s?s,s:s !}", "api", &action->exec.subcall.api, "verb", &action->exec.subcall.verb); + if (err) { + AFB_ApiError(apiHandle,"ACTION-LOAD-ONE Subcall missing [load]|func in:\n-- %s", json_object_get_string(luaJ)); + goto OnErrorExit; + } } if (callbackJ) { + modeCount++; action->type = CTL_TYPE_CB; modeCount++; - err = PluginGetCB (action, callbackJ); - if (err) goto OnErrorExit; - + err = PluginGetCB (apiHandle, action, callbackJ); + if (err) goto OnErrorExit; } // make sure at least one mode is selected if (modeCount == 0) { - AFB_ERROR("ACTION-LOAD-ONE No Action Selected lua|callback|(api+verb) in %s", json_object_get_string(actionJ)); + AFB_ApiError(apiHandle,"ACTION-LOAD-ONE No Action Selected lua|callback|(api+verb) in %s", json_object_get_string(actionJ)); goto OnErrorExit; } if (modeCount > 1) { - AFB_ERROR("ACTION-LOAD-ONE:ToMany arguments lua|callback|(api+verb) in %s", json_object_get_string(actionJ)); + AFB_ApiError(apiHandle,"ACTION-LOAD-ONE:ToMany arguments lua|callback|(api+verb) in %s", json_object_get_string(actionJ)); goto OnErrorExit; } return 0; @@ -145,7 +183,7 @@ OnErrorExit: return 1; }; -PUBLIC CtlActionT *ActionLoad(json_object *actionsJ) { +PUBLIC CtlActionT *ActionConfig(AFB_ApiT apiHandle, json_object *actionsJ, int exportApi) { int err; CtlActionT *actions; @@ -156,13 +194,14 @@ PUBLIC CtlActionT *ActionLoad(json_object *actionsJ) { for (int idx = 0; idx < count; idx++) { json_object *actionJ = json_object_array_get_idx(actionsJ, idx); - err = ActionLoadOne(&actions[idx], actionJ); + + err = ActionLoadOne(apiHandle, &actions[idx], actionJ, exportApi); if (err) goto OnErrorExit; } } else { actions = calloc(2, sizeof (CtlActionT)); - err = ActionLoadOne(&actions[0], actionsJ); + err = ActionLoadOne(apiHandle, &actions[0], actionsJ, exportApi); if (err) goto OnErrorExit; } diff --git a/ctl-lib/ctl-config.c b/ctl-lib/ctl-config.c index b7c0d54..2b5d345 100644 --- a/ctl-lib/ctl-config.c +++ b/ctl-lib/ctl-config.c @@ -21,6 +21,8 @@ #define _GNU_SOURCE #include <stdio.h> #include <string.h> +#include <sys/time.h> + #include "filescan-utils.h" #include "ctl-config.h" @@ -28,16 +30,36 @@ // Load control config file -PUBLIC char* CtlConfigSearch(const char *dirList) { - int index, err; - char controlFile [CONTROL_MAXPATH_LEN]; +PUBLIC int CtlConfigMagicNew() { + static int InitRandomDone=0; + + if (!InitRandomDone) { + struct timeval tv; + InitRandomDone=1; + gettimeofday(&tv,NULL); + srand ((int)tv.tv_usec); + } + + return ((long)rand()); +} - strncpy(controlFile, CONTROL_CONFIG_PRE "-", CONTROL_MAXPATH_LEN); +PUBLIC json_object* CtlConfigScan(const char *dirList, const char *prefix) { + char controlFile [CONTROL_MAXPATH_LEN]; + strncpy(controlFile, prefix, CONTROL_MAXPATH_LEN); strncat(controlFile, GetBinderName(), CONTROL_MAXPATH_LEN); // search for default dispatch config file json_object* responseJ = ScanForConfig(dirList, CTL_SCAN_RECURSIVE, controlFile, ".json"); + return responseJ; +} + +PUBLIC char* CtlConfigSearch(AFB_ApiT apiHandle, const char *dirList, const char *prefix) { + int index, err; + + // search for default dispatch config file + json_object* responseJ = CtlConfigScan (dirList, prefix); + // 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); @@ -46,18 +68,16 @@ PUBLIC char* CtlConfigSearch(const char *dirList) { char*fullpath; err = wrap_json_unpack(entryJ, "{s:s, s:s !}", "fullpath", &fullpath, "filename", &filename); if (err) { - AFB_ERROR("CTL-INIT HOOPs invalid JSON entry= %s", json_object_get_string(entryJ)); + AFB_ApiError(apiHandle, "CTL-INIT HOOPs invalid JSON entry= %s", json_object_get_string(entryJ)); return NULL; } 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)); - return (strdup(filepath)); - } + char filepath[CONTROL_MAXPATH_LEN]; + strncpy(filepath, fullpath, sizeof (filepath)); + strncat(filepath, "/", sizeof (filepath)); + strncat(filepath, filename, sizeof (filepath)); + return (strdup(filepath)); } } @@ -65,15 +85,16 @@ PUBLIC char* CtlConfigSearch(const char *dirList) { return NULL; } -PUBLIC int CtlConfigExec(CtlConfigT *ctlConfig) { +PUBLIC int CtlConfigExec(AFB_ApiT apiHandle, CtlConfigT *ctlConfig) { + // best effort to initialise everything before starting if (ctlConfig->requireJ) { void DispatchRequireOneApi(json_object * bindindJ) { const char* requireBinding = json_object_get_string(bindindJ); - int err = afb_daemon_require_api(requireBinding, 1); + int err = AFB_RequireApi(apiHandle, requireBinding, 1); if (err) { - AFB_WARNING("CTL-LOAD-CONFIG:REQUIRE Fail to get=%s", requireBinding); + AFB_ApiWarning(apiHandle, "CTL-LOAD-CONFIG:REQUIRE Fail to get=%s", requireBinding); } } @@ -87,14 +108,14 @@ PUBLIC int CtlConfigExec(CtlConfigT *ctlConfig) { } #ifdef CONTROL_SUPPORT_LUA - int err= LuaConfigExec(); + int err= LuaConfigExec(apiHandle); if (err) goto OnErrorExit; #endif // Loop on every section and process config int errcount=0; for (int idx = 0; ctlConfig->sections[idx].key != NULL; idx++) { - errcount += ctlConfig->sections[idx].loadCB(&ctlConfig->sections[idx], NULL); + errcount += ctlConfig->sections[idx].loadCB(apiHandle, &ctlConfig->sections[idx], NULL); } return errcount; @@ -102,73 +123,66 @@ OnErrorExit: return 1; } -PUBLIC CtlConfigT *CtlConfigLoad(const char* filepath, CtlSectionT *sections) { +PUBLIC CtlConfigT *CtlLoadMetaData(AFB_ApiT apiHandle, const char* filepath) { json_object *ctlConfigJ; - CtlConfigT *ctlConfig; + CtlConfigT *ctlHandle=NULL; int err; -#ifdef CONTROL_SUPPORT_LUA - err= LuaConfigLoad(); - if (err) goto OnErrorExit; -#endif - - // Search for config in filepath - filepath = CtlConfigSearch(filepath); - - if (!filepath) { - AFB_ERROR("CTL-LOAD-CONFIG No JSON Config found invalid JSON %s ", filepath); - goto OnErrorExit; - } - // Load JSON file ctlConfigJ = json_object_from_file(filepath); if (!ctlConfigJ) { - AFB_ERROR("CTL-LOAD-CONFIG Not invalid JSON %s ", filepath); + AFB_ApiError(apiHandle, "CTL-LOAD-CONFIG Not invalid JSON %s ", filepath); goto OnErrorExit; } - AFB_INFO("CTL-LOAD-CONFIG: loading config filepath=%s", filepath); + AFB_ApiInfo(apiHandle, "CTL-LOAD-CONFIG: loading config filepath=%s", filepath); json_object *metadataJ; int done = json_object_object_get_ex(ctlConfigJ, "metadata", &metadataJ); if (done) { - ctlConfig = calloc(1, sizeof (CtlConfigT)); - err = wrap_json_unpack(metadataJ, "{ss,ss,ss,s?s,s?o !}", "label", &ctlConfig->label, "version", &ctlConfig->version - , "api", &ctlConfig->api, "info", &ctlConfig->info, "require", &ctlConfig->requireJ); + ctlHandle = calloc(1, sizeof (CtlConfigT)); + err = wrap_json_unpack(metadataJ, "{ss,ss,ss,s?s,s?o !}", "label", &ctlHandle->label, "version", &ctlHandle->version + , "api", &ctlHandle->api, "info", &ctlHandle->info, "require", &ctlHandle->requireJ); if (err) { - AFB_ERROR("CTL-LOAD-CONFIG:METADATA Missing something label|api|version|[info]|[require] in:\n-- %s", json_object_get_string(metadataJ)); + AFB_ApiError(apiHandle, "CTL-LOAD-CONFIG:METADATA Missing something label|api|version|[info]|[require] in:\n-- %s", json_object_get_string(metadataJ)); goto OnErrorExit; } - - // Should replace this with API name change - if (ctlConfig->api) { - err = afb_daemon_rename_api(ctlConfig->api); - if (err) AFB_WARNING("Fail to rename api to:%s", ctlConfig->api); - } - } + + ctlHandle->configJ = ctlConfigJ; + return ctlHandle; + +OnErrorExit: + if (ctlHandle) free(ctlHandle); + return NULL; +} + +PUBLIC int CtlLoadSections(AFB_ApiT apiHandle, CtlConfigT *ctlHandle, CtlSectionT *sections) { + int err; + +#ifdef CONTROL_SUPPORT_LUA + err= LuaConfigLoad(apiHandle); + if (err) goto OnErrorExit; +#endif - //load config sections err = 0; - ctlConfig->sections = sections; + ctlHandle->sections = sections; for (int idx = 0; sections[idx].key != NULL; idx++) { json_object * sectionJ; - int done = json_object_object_get_ex(ctlConfigJ, sections[idx].key, §ionJ); + int done = json_object_object_get_ex(ctlHandle->configJ, sections[idx].key, §ionJ); if (!done) { - AFB_ERROR("CtlConfigLoad: fail to find '%s' section in config '%s'", sections[idx].key, filepath); + AFB_ApiError(apiHandle, "CtlConfigLoad: fail to find '%s' section in config '%s'", sections[idx].key, ctlHandle->label); err++; } else { - err += sections[idx].loadCB(§ions[idx], sectionJ); + err += sections[idx].loadCB(apiHandle, §ions[idx], sectionJ); } - } if (err) goto OnErrorExit; - return (ctlConfig); + return 0; OnErrorExit: - free(ctlConfig); - return NULL; + return 1; } diff --git a/ctl-lib/ctl-config.h b/ctl-lib/ctl-config.h index 2e3a16a..09c573f 100644 --- a/ctl-lib/ctl-config.h +++ b/ctl-lib/ctl-config.h @@ -22,13 +22,10 @@ #define _CTL_CONFIG_INCLUDE_ #define _GNU_SOURCE -#define AFB_BINDING_VERSION 2 -#include <afb/afb-binding.h> -#include <json-c/json.h> -#include <filescan-utils.h> -#include <wrap-json.h> #include "ctl-plugin.h" +#include <filescan-utils.h> +#include <wrap-json.h> #ifndef CONTROL_MAXPATH_LEN #define CONTROL_MAXPATH_LEN 255 @@ -42,37 +39,13 @@ #define CTL_PLUGIN_EXT ".ctlso" #endif - - -typedef enum { - CTL_TYPE_NONE=0, - CTL_TYPE_API, - CTL_TYPE_CB, - CTL_TYPE_LUA, -} CtlActionTypeT; - - -typedef struct { - CtlActionTypeT type; - const char* api; - const char* call; - json_object *argsJ; - int (*actionCB)(CtlSourceT *source, json_object *argsJ, json_object *queryJ); - CtlSourceT source; -} CtlActionT; - -typedef struct { - const char* label; - const char *info; - CtlActionT *actions; -} DispatchHandleT; - typedef struct ConfigSectionS { const char *key; const char *label; const char *info; - int (*loadCB)(struct ConfigSectionS *section, json_object *sectionJ); - void *handle; + int (*loadCB)(AFB_ApiT apihandle, struct ConfigSectionS *section, json_object *sectionJ); + void *handle; + CtlActionT *actions; } CtlSectionT; typedef struct { @@ -80,6 +53,7 @@ typedef struct { const char* label; const char *info; const char *version; + json_object *configJ; json_object *requireJ; CtlSectionT *sections; } CtlConfigT; @@ -87,27 +61,54 @@ typedef struct { #ifdef CONTROL_SUPPORT_LUA #include "ctl-lua.h" -#else - typedef void* Lua2cWrapperT; #endif + +// This should not be global as application may want to define their own sections +typedef enum { + CTL_SECTION_PLUGIN, + CTL_SECTION_ONLOAD, + CTL_SECTION_CONTROL, + CTL_SECTION_EVENT, + CTL_SECTION_HAL, + + CTL_SECTION_ENDTAG, +} SectionEnumT; // ctl-action.c -PUBLIC CtlActionT *ActionLoad(json_object *actionsJ); -PUBLIC int ActionExecOne(CtlActionT* action, json_object *queryJ); -PUBLIC int ActionLoadOne(CtlActionT *action, json_object *actionJ); +PUBLIC CtlActionT *ActionConfig(AFB_ApiT apiHandle, json_object *actionsJ, int exportApi); +PUBLIC void ActionExecOne( CtlSourceT *source, CtlActionT* action, json_object *queryJ); +PUBLIC int ActionLoadOne(AFB_ApiT apiHandle, CtlActionT *action, json_object *, int exportApi); +PUBLIC int ActionLabelToIndex(CtlActionT* actions, const char* actionLabel); + // ctl-config.c -PUBLIC CtlConfigT *CtlConfigLoad(const char* filepath, CtlSectionT *sections); -PUBLIC int CtlConfigExec(CtlConfigT *ctlConfig); +PUBLIC int CtlConfigMagicNew(); +PUBLIC json_object* CtlConfigScan(const char *dirList, const char *prefix) ; +PUBLIC char* CtlConfigSearch(AFB_ApiT apiHandle, const char *dirList, const char *prefix) ; +PUBLIC int CtlConfigExec(AFB_ApiT apiHandle, CtlConfigT *ctlConfig) ; +PUBLIC CtlConfigT *CtlLoadMetaData(AFB_ApiT apiHandle,const char* filepath) ; +PUBLIC int CtlLoadSections(AFB_ApiT apiHandle, CtlConfigT *ctlHandle, CtlSectionT *sections); -// ctl-onload.c -PUBLIC int OnloadConfig(CtlSectionT *section, json_object *actionsJ); +// ctl-event.c +PUBLIC int EventConfig(AFB_ApiT apihandle, CtlSectionT *section, json_object *actionsJ); +#ifdef AFB_BINDING_PREV3 +PUBLIC void CtrlDispatchApiEvent (AFB_ApiT apiHandle, const char *evtLabel, struct json_object *eventJ); +#else +PUBLIC void CtrlDispatchV2Event(const char *evtLabel, json_object *eventJ); +#endif + +// ctl-control.c +PUBLIC int ControlConfig(AFB_ApiT apiHandle, CtlSectionT *section, json_object *actionsJ); + +// ctl-onload.c +PUBLIC int OnloadConfig(AFB_ApiT apiHandle, CtlSectionT *section, json_object *actionsJ); + // ctl-plugin.c -PUBLIC int PluginConfig(CtlSectionT *section, json_object *pluginsJ); -PUBLIC int PluginGetCB (CtlActionT *action , json_object *callbackJ); +PUBLIC int PluginConfig(AFB_ApiT UNUSED_ARG(apiHandle), CtlSectionT *section, json_object *pluginsJ); +PUBLIC int PluginGetCB (AFB_ApiT apiHandle, CtlActionT *action , json_object *callbackJ); #endif /* _CTL_CONFIG_INCLUDE_ */
\ No newline at end of file diff --git a/ctl-lib/ctl-control.c b/ctl-lib/ctl-control.c new file mode 100644 index 0000000..117f5b5 --- /dev/null +++ b/ctl-lib/ctl-control.c @@ -0,0 +1,43 @@ +/* + * 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, something 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 "ctl-config.h" + +// onload section receive one action or an array of actions +PUBLIC int ControlConfig(AFB_ApiT apiHandle, CtlSectionT *section, json_object *actionsJ) { + + // Load time parse actions in config file + if (actionsJ != NULL) { + section->actions= ActionConfig(apiHandle, actionsJ, 1); + + if (!section->actions) { + AFB_ApiError (apiHandle, "ControlLoad config fail processing onload actions"); + goto OnErrorExit; + } + } + + return 0; + +OnErrorExit: + return 1; + +} diff --git a/ctl-lib/ctl-event.c b/ctl-lib/ctl-event.c new file mode 100644 index 0000000..b9be1c7 --- /dev/null +++ b/ctl-lib/ctl-event.c @@ -0,0 +1,94 @@ +/* + * 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, something 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 "ctl-config.h" + + +// Event dynamic API-V3 mode +#ifdef AFB_BINDING_PREV3 +PUBLIC void CtrlDispatchApiEvent (AFB_ApiT apiHandle, const char *evtLabel, struct json_object *eventJ) { + AFB_ApiNotice (apiHandle, "Received event=%s, query=%s", evtLabel, json_object_get_string(eventJ)); + + // retrieve section config from api handle + CtlConfigT *ctrlConfig = (CtlConfigT*) afb_dynapi_get_userdata(apiHandle); + + CtlActionT* actions = ctrlConfig->sections[CTL_SECTION_EVENT].actions; + + int index= ActionLabelToIndex(actions, evtLabel); + if (index < 0) { + AFB_ApiWarning(apiHandle, "CtlDispatchEvent: fail to find label=%s in action event section", evtLabel); + return; + } + + // create a dummy source for action + CtlSourceT source; + source.label = actions[index].label; + source.api = actions[index].api; + source.request = NULL; + + // Best effort ignoring error to exec corresponding action + (void) ActionExecOne (&source, &actions[index], eventJ); + +} +#else +// In API-V2 controller config is unique and static +extern CtlConfigT *ctrlConfig; + +// call action attached to even name if any +PUBLIC void CtrlDispatchV2Event(const char *evtLabel, json_object *eventJ) { + CtlActionT* actions = ctrlConfig->sections[CTL_SECTION_EVENT].actions; + + int index= ActionLabelToIndex(actions, evtLabel); + if (index < 0) { + AFB_WARNING ("CtlDispatchEvent: fail to find label=%s in action event section", evtLabel); + return; + } + + CtlSourceT source; + source.label = actions[index].label; + source.api = actions[index].api; + source.request = AFB_ReqNone; + + // Best effort ignoring error to exec corresponding action + (void) ActionExecOne (&source, &actions[index], eventJ); +} +#endif + +// onload section receive one action or an array of actions +PUBLIC int EventConfig(AFB_ApiT apiHandle, CtlSectionT *section, json_object *actionsJ) { + + // Load time parse actions in config file + if (actionsJ != NULL) { + section->actions= ActionConfig(apiHandle, actionsJ, 1); + + if (!section->actions) { + AFB_ApiError (apiHandle, "EventLoad config fail processing onload actions"); + goto OnErrorExit; + } + } + + return 0; + +OnErrorExit: + return 1; + +} diff --git a/ctl-lib/ctl-lua.c b/ctl-lib/ctl-lua.c index 7b68fe2..2aaaabb 100644 --- a/ctl-lib/ctl-lua.c +++ b/ctl-lib/ctl-lua.c @@ -27,47 +27,43 @@ #define _GNU_SOURCE #include <stdio.h> #include <string.h> +#include <sys/time.h> #include "ctl-config.h" #define LUA_FIST_ARG 2 // when using luaL_newlib calllback receive libtable as 1st arg #define LUA_MSG_MAX_LENGTH 512 #define JSON_ERROR (json_object*)-1 -static afb_req NULL_AFBREQ = {}; static lua_State* luaState; -#define CTX_MAGIC 123456789 -#define CTX_TOKEN "AFB_ctx" +#ifndef CTX_MAGIC + static int CTX_MAGIC; +#endif + +#ifndef TIMER_MAGIC + static int TIMER_MAGIC; +#endif typedef struct { char *name; int count; - afb_event event; + AFB_EventT event; } LuaAfbEvent; -static LuaAfbEvent *luaDefaultEvt; typedef struct { int ctxMagic; - afb_req request; - void *handle; - char *info; -} LuaAfbContextT; + CtlSourceT *source; +} LuaAfbSourceT; typedef struct { const char *callback; json_object *context; - void *handle; -} LuaCallServiceT; + CtlSourceT *source; +} LuaCbHandleT; + -typedef enum { - AFB_MSG_INFO, - AFB_MSG_WARNING, - AFB_MSG_NOTICE, - AFB_MSG_DEBUG, - AFB_MSG_ERROR, -} LuaAfbMessageT; /* * Note(Fulup): I fail to use luaL_setmetatable and replaced it with a simple opaque @@ -75,43 +71,32 @@ typedef enum { * https://stackoverflow.com/questions/45596493/lua-using-lua-newuserdata-from-lua-pcall */ -STATIC LuaAfbContextT *LuaCtxCheck (lua_State *luaState, int index) { - LuaAfbContextT *afbContext; - //luaL_checktype(luaState, index, LUA_TUSERDATA); - //afbContext = (LuaAfbContextT *)luaL_checkudata(luaState, index, CTX_TOKEN); +STATIC CtlSourceT *LuaSourcePop (lua_State *luaState, int index) { + LuaAfbSourceT *afbSource; luaL_checktype(luaState, index, LUA_TLIGHTUSERDATA); - afbContext = (LuaAfbContextT *) lua_touserdata(luaState, index); - if (afbContext == NULL && afbContext->ctxMagic != CTX_MAGIC) { - luaL_error(luaState, "Fail to retrieve user data context=%s", CTX_TOKEN); - AFB_ERROR ("afbContextCheck error retrieving afbContext"); + afbSource = (LuaAfbSourceT *) lua_touserdata(luaState, index); + if (afbSource == NULL || afbSource->ctxMagic != CTX_MAGIC) { + luaL_error(luaState, "(Hoops) Invalid source handle"); return NULL; } - return afbContext; + return afbSource->source; } -STATIC LuaAfbContextT *LuaCtxPush (lua_State *luaState, afb_req request, void *handle, const char* info) { - // LuaAfbContextT *afbContext = (LuaAfbContextT *)lua_newuserdata(luaState, sizeof(LuaAfbContextT)); - // luaL_setmetatable(luaState, CTX_TOKEN); - LuaAfbContextT *afbContext = (LuaAfbContextT *)calloc(1, sizeof(LuaAfbContextT)); - lua_pushlightuserdata(luaState, afbContext); - if (!afbContext) { - AFB_ERROR ("LuaCtxPush fail to allocate user data context"); +STATIC LuaAfbSourceT *LuaSourcePush (lua_State *luaState, CtlSourceT *source) { + LuaAfbSourceT *afbSource = (LuaAfbSourceT *)calloc(1, sizeof(LuaAfbSourceT)); + if (!afbSource) { + AFB_ApiError(source->api, "LuaSourcePush fail to allocate user data context"); return NULL; } - afbContext->ctxMagic=CTX_MAGIC; - afbContext->info=strdup(info); - afbContext->request= request; - afbContext->handle= handle; - return afbContext; -} - -STATIC void LuaCtxFree (LuaAfbContextT *afbContext) { - free(afbContext->info); - free(afbContext); + + lua_pushlightuserdata(luaState, afbSource); + afbSource->ctxMagic=CTX_MAGIC; + afbSource->source= source; + return afbSource; } // Push a json structure on the stack as a LUA table -STATIC int LuaPushArgument (json_object *argsJ) { +STATIC int LuaPushArgument (CtlSourceT *source, json_object *argsJ) { //AFB_NOTICE("LuaPushArgument argsJ=%s", json_object_get_string(argsJ)); @@ -120,7 +105,7 @@ STATIC int LuaPushArgument (json_object *argsJ) { case json_type_object: { lua_newtable (luaState); json_object_object_foreach (argsJ, key, val) { - int done = LuaPushArgument (val); + int done = LuaPushArgument (source, val); if (done) { lua_setfield(luaState,-2, key); } @@ -132,7 +117,7 @@ STATIC int LuaPushArgument (json_object *argsJ) { lua_newtable (luaState); for (int idx=0; idx < length; idx ++) { json_object *val=json_object_array_get_idx(argsJ, idx); - LuaPushArgument (val); + LuaPushArgument (source, val); lua_seti (luaState,-2, idx); } break; @@ -150,23 +135,23 @@ STATIC int LuaPushArgument (json_object *argsJ) { 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)); + AFB_ApiWarning(source->api, "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(argsJ)); + AFB_ApiError(source->api, "LuaPushArgument: unsupported Json object type %s", json_object_get_string(argsJ)); return 0; } return 1; } -STATIC json_object *LuaPopOneArg (lua_State* luaState, int idx); +STATIC json_object *LuaPopOneArg (CtlSourceT *source, lua_State* luaState, int idx); // Move a table from Internal Lua representation to Json one // Numeric table are transformed in json array, string one in object // Mix numeric/string key are not supported -STATIC json_object *LuaTableToJson (lua_State* luaState, int index) { +STATIC json_object *LuaTableToJson (CtlSourceT *source, lua_State* luaState, int index) { #define LUA_KEY_INDEX -2 #define LUA_VALUE_INDEX -1 @@ -185,12 +170,12 @@ STATIC json_object *LuaTableToJson (lua_State* luaState, int index) { tableJ= json_object_new_object(); tableType=LUA_TSTRING; } else if (tableType != LUA_TSTRING){ - AFB_ERROR("MIX Lua Table with key string/numeric not supported"); + AFB_ApiError(source->api, "MIX Lua Table with key string/numeric not supported"); return NULL; } const char *key= lua_tostring(luaState, LUA_KEY_INDEX); - json_object *argJ= LuaPopOneArg(luaState, LUA_VALUE_INDEX); + json_object *argJ= LuaPopOneArg(source, luaState, LUA_VALUE_INDEX); json_object_object_add(tableJ, key, argJ); } else { @@ -198,11 +183,11 @@ STATIC json_object *LuaTableToJson (lua_State* luaState, int index) { tableJ= json_object_new_array(); tableType=LUA_TNUMBER; } else if(tableType != LUA_TNUMBER) { - AFB_ERROR("MIX Lua Table with key numeric/string not supported"); + AFB_ApiError(source->api, "MIX Lua Table with key numeric/string not supported"); return NULL; } - json_object *argJ= LuaPopOneArg(luaState, LUA_VALUE_INDEX); + json_object *argJ= LuaPopOneArg(source, luaState, LUA_VALUE_INDEX); json_object_array_add(tableJ, argJ); } @@ -218,7 +203,7 @@ STATIC json_object *LuaTableToJson (lua_State* luaState, int index) { return tableJ; } -STATIC json_object *LuaPopOneArg (lua_State* luaState, int idx) { +STATIC json_object *LuaPopOneArg (CtlSourceT *source, lua_State* luaState, int idx) { json_object *value=NULL; int luaType = lua_type(luaState, idx); @@ -240,7 +225,7 @@ STATIC json_object *LuaPopOneArg (lua_State* luaState, int idx) { value= json_object_new_string(lua_tostring(luaState, idx)); break; case LUA_TTABLE: - value= LuaTableToJson(luaState, idx); + value= LuaTableToJson(source, luaState, idx); break; case LUA_TNIL: value=json_object_new_string("nil") ; @@ -250,14 +235,14 @@ STATIC json_object *LuaPopOneArg (lua_State* luaState, int idx) { break; default: - AFB_NOTICE ("LuaPopOneArg: script returned Unknown/Unsupported idx=%d type:%d/%s", idx, luaType, lua_typename(luaState, luaType)); + AFB_ApiNotice (source->api, "LuaPopOneArg: script returned Unknown/Unsupported idx=%d type:%d/%s", idx, luaType, lua_typename(luaState, luaType)); value=NULL; } return value; } -static json_object *LuaPopArgs (lua_State* luaState, int start) { +static json_object *LuaPopArgs (CtlSourceT *source, lua_State* luaState, int start) { json_object *responseJ; int stop = lua_gettop(luaState); @@ -265,12 +250,12 @@ static json_object *LuaPopArgs (lua_State* luaState, int start) { // start at 2 because we are using a function array lib if (start == stop) { - responseJ=LuaPopOneArg (luaState, start); + responseJ=LuaPopOneArg (source, luaState, start); } else { // loop on remaining return arguments responseJ= json_object_new_array(); for (int idx=start; idx <= stop; idx++) { - json_object *argJ=LuaPopOneArg (luaState, idx); + json_object *argJ=LuaPopOneArg (source, luaState, idx); if (!argJ) goto OnErrorExit; json_object_array_add(responseJ, argJ); } @@ -283,10 +268,41 @@ static json_object *LuaPopArgs (lua_State* luaState, int start) { } -STATIC int LuaFormatMessage(lua_State* luaState, LuaAfbMessageT action) { - char *message; - json_object *responseJ= LuaPopArgs(luaState, LUA_FIST_ARG); + /* + * 'level' is defined by syslog standard: + * EMERGENCY 0 System is unusable + * ALERT 1 Action must be taken immediately + * CRITICAL 2 Critical conditions + * ERROR 3 Error conditions + * WARNING 4 Warning conditions + * NOTICE 5 Normal but significant condition + * INFO 6 Informational + * DEBUG 7 Debug-level messages + */ +typedef enum { + AFB_MSG_INFO=6, + AFB_MSG_WARNING=4, + AFB_MSG_NOTICE=5, + AFB_MSG_DEBUG=7, + AFB_MSG_ERROR=3, +} LuaAfbLevelT; + +STATIC int LuaFormatMessage(lua_State* luaState, LuaAfbLevelT level) { + char *message; + + CtlSourceT *source= LuaSourcePop(luaState, LUA_FIST_ARG); + if (!source) goto OnErrorExit; +\ + + // if log level low then silently ignore message +#ifdef AFB_BINDING_PREV3 + if(source->api->verbosity < level) return 0; +#else + if(afb_get_verbosity() < level) return 0; +#endif + + json_object *responseJ= LuaPopArgs(source, luaState, LUA_FIST_ARG+1); if (!responseJ) { luaL_error(luaState,"LuaFormatMessage empty message"); @@ -329,6 +345,10 @@ STATIC int LuaFormatMessage(lua_State* luaState, LuaAfbMessageT action) { message[targetIdx]='%'; targetIdx++; break; + + case 'A': + targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"level: %s", source->label); + break; case 's': default: @@ -339,7 +359,7 @@ STATIC int LuaFormatMessage(lua_State* luaState, LuaAfbMessageT action) { } else { if (targetIdx >= LUA_MSG_MAX_LENGTH) { - AFB_WARNING ("LuaFormatMessage: message[%s] owerverflow LUA_MSG_MAX_LENGTH=%d", format, LUA_MSG_MAX_LENGTH); + AFB_ApiWarning (source->api, "LuaFormatMessage: message[%s] owerverflow LUA_MSG_MAX_LENGTH=%d", format, LUA_MSG_MAX_LENGTH); targetIdx --; // move backward for EOL break; } else { @@ -350,36 +370,22 @@ STATIC int LuaFormatMessage(lua_State* luaState, LuaAfbMessageT action) { message[targetIdx]='\0'; PrintMessage: - switch (action) { - case AFB_MSG_WARNING: - AFB_WARNING ("%s", message); - break; - case AFB_MSG_NOTICE: - AFB_NOTICE ("%s", message); - break; - case AFB_MSG_DEBUG: - AFB_DEBUG ("%s", message); - break; - case AFB_MSG_INFO: - AFB_INFO ("%s", message); - break; - case AFB_MSG_ERROR: - default: - AFB_ERROR ("%s", message); - } + // TBD: __file__ and __line__ should match LUA source code + AFB_ApiVerbose(source->api, level,__FILE__,__LINE__,source->label, message); return 0; // nothing return to lua OnErrorExit: // on argument to return (the error message) return 1; } + STATIC int LuaPrintInfo(lua_State* luaState) { int err=LuaFormatMessage (luaState, AFB_MSG_INFO); return err; } STATIC int LuaPrintError(lua_State* luaState) { - int err=LuaFormatMessage (luaState, AFB_MSG_ERROR); + int err=LuaFormatMessage (luaState, AFB_MSG_DEBUG); return err; // no value return } @@ -394,21 +400,20 @@ STATIC int LuaPrintNotice(lua_State* luaState) { } STATIC int LuaPrintDebug(lua_State* luaState) { - int err=LuaFormatMessage (luaState, AFB_MSG_DEBUG); + int err=LuaFormatMessage (luaState, AFB_MSG_ERROR); return err; } STATIC int LuaAfbSuccess(lua_State* luaState) { - LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG); - if (!afbContext) goto OnErrorExit; + CtlSourceT *source= LuaSourcePop(luaState, LUA_FIST_ARG); + if (!source) goto OnErrorExit; // ignore context argument - json_object *responseJ= LuaPopArgs(luaState, LUA_FIST_ARG+1); + json_object *responseJ= LuaPopArgs(source, luaState, LUA_FIST_ARG+1); if (responseJ == JSON_ERROR) return 1; - afb_req_success(afbContext->request, responseJ, NULL); + AFB_ReqSucess (source->request, responseJ, NULL); - LuaCtxFree(afbContext); return 0; OnErrorExit: @@ -417,15 +422,14 @@ STATIC int LuaAfbSuccess(lua_State* luaState) { } STATIC int LuaAfbFail(lua_State* luaState) { - LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG); - if (!afbContext) goto OnErrorExit; + CtlSourceT *source= LuaSourcePop(luaState, LUA_FIST_ARG); + if (!source) goto OnErrorExit; - json_object *responseJ= LuaPopArgs(luaState, LUA_FIST_ARG+1); + json_object *responseJ= LuaPopArgs(source, luaState, LUA_FIST_ARG+1); if (responseJ == JSON_ERROR) return 1; - afb_req_fail(afbContext->request, afbContext->info, json_object_get_string(responseJ)); + AFB_ReqFail(source->request, source->label, json_object_get_string(responseJ)); - LuaCtxFree(afbContext); return 0; OnErrorExit: @@ -433,46 +437,52 @@ STATIC int LuaAfbFail(lua_State* luaState) { return 1; } -STATIC void LuaAfbServiceCB(void *handle, int iserror, struct json_object *responseJ) { - LuaCallServiceT *contextCB= (LuaCallServiceT*)handle; +STATIC void LuaAfbServiceCB(void *handle, int iserror, struct json_object *responseJ, AFB_ApiT apiHandle) { + LuaCbHandleT *handleCb= (LuaCbHandleT*)handle; int count=1; - lua_getglobal(luaState, contextCB->callback); + lua_getglobal(luaState, handleCb->callback); // push error status & response lua_pushboolean(luaState, iserror); - count+= LuaPushArgument(responseJ); - count+= LuaPushArgument(contextCB->context); + count+= LuaPushArgument(handleCb->source, responseJ); + count+= LuaPushArgument(handleCb->source, handleCb->context); 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) ); + AFB_ApiError(apiHandle, "LUA-SERICE-CB:FAIL response=%s err=%s", json_object_get_string(responseJ), lua_tostring(luaState,-1) ); } - free (contextCB); + free (handleCb); } STATIC int LuaAfbService(lua_State* luaState) { int count = lua_gettop(luaState); + CtlSourceT *source= LuaSourcePop(luaState, LUA_FIST_ARG); + if (!source) { + lua_pushliteral (luaState, "LuaAfbService-Fail Invalid request handle"); + 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)) { + if (count <6 || !lua_isstring(luaState, 3) || !lua_isstring(luaState, 4) || !lua_istable(luaState, 5) || !lua_isstring(luaState, 6)) { lua_pushliteral (luaState, "ERROR: syntax AFB:service(api, verb, {[Lua Table]})"); 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); + const char *api = lua_tostring(luaState,3); + const char *verb= lua_tostring(luaState,4); + json_object *queryJ= LuaTableToJson(source, luaState, 5); if (queryJ == JSON_ERROR) return 1; - LuaCallServiceT *contextCB = calloc (1, sizeof(LuaCallServiceT)); - contextCB->callback= lua_tostring(luaState, 5); - contextCB->context = LuaPopArgs(luaState, 6); + LuaCbHandleT *handleCb = calloc (1, sizeof(LuaCbHandleT)); + handleCb->callback= lua_tostring(luaState, 6); + handleCb->context = LuaPopArgs(source, luaState, 7); - afb_service_call(api, verb, queryJ, LuaAfbServiceCB, contextCB); + AFB_ServiceCall(source->api, api, verb, queryJ, LuaAfbServiceCB, handleCb); return 0; // no value return @@ -485,22 +495,29 @@ STATIC int LuaAfbServiceSync(lua_State* luaState) { int count = lua_gettop(luaState); json_object *responseJ; + CtlSourceT *source= LuaSourcePop(luaState, LUA_FIST_ARG); + if (!source) { + lua_pushliteral (luaState, "LuaAfbServiceSync-Fail Invalid request handle"); + goto OnErrorExit; + } + // note: argument start at 2 because of AFB: table - if (count <3 || !lua_isstring(luaState, 2) || !lua_isstring(luaState, 3) || !lua_istable(luaState, 4)) { + if (count <4 || !lua_isstring(luaState, 3) || !lua_isstring(luaState, 4) || !lua_istable(luaState, 5)) { lua_pushliteral (luaState, "ERROR: syntax AFB:servsync(api, verb, {[Lua Table]})"); 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); + + // get source/api/verb+query + const char *api = lua_tostring(luaState,LUA_FIST_ARG+2); + const char *verb= lua_tostring(luaState,LUA_FIST_ARG+3); + json_object *queryJ= LuaTableToJson(source, luaState, LUA_FIST_ARG+4); - int iserror=afb_service_call_sync (api, verb, queryJ, &responseJ); + int iserror=AFB_ServiceSync(source->api, api, verb, queryJ, &responseJ); // push error status & response count=1; lua_pushboolean(luaState, iserror); - count+= LuaPushArgument(responseJ); + count+= LuaPushArgument(source, responseJ); return count; // return count values @@ -511,38 +528,42 @@ STATIC int LuaAfbServiceSync(lua_State* luaState) { STATIC int LuaAfbEventPush(lua_State* luaState) { LuaAfbEvent *afbevt; - int index; + CtlSourceT *source= LuaSourcePop(luaState, LUA_FIST_ARG); + if (!source) { + lua_pushliteral (luaState, "LuaAfbEventSubscribe-Fail Invalid request handle"); + goto OnErrorExit; + } + // if no private event handle then use default binding event - if (lua_islightuserdata(luaState, LUA_FIST_ARG)) { - afbevt = (LuaAfbEvent*) lua_touserdata(luaState, LUA_FIST_ARG); - index=LUA_FIST_ARG+1; - } else { - index=LUA_FIST_ARG; - afbevt=luaDefaultEvt; + if (!lua_islightuserdata(luaState, LUA_FIST_ARG+1)) { + lua_pushliteral (luaState, "LuaAfbMakePush-Fail missing event handle"); + goto OnErrorExit; } - - if (!afb_event_is_valid(afbevt->event)) { + + afbevt = (LuaAfbEvent*) lua_touserdata(luaState, LUA_FIST_ARG+1); + + if (!AFB_EventIsValid(afbevt->event)) { lua_pushliteral (luaState, "LuaAfbMakePush-Fail invalid event"); goto OnErrorExit; } - json_object *ctlEventJ= LuaTableToJson(luaState, index); + json_object *ctlEventJ= LuaTableToJson(source, luaState, LUA_FIST_ARG+2); if (!ctlEventJ) { lua_pushliteral (luaState, "LuaAfbEventPush-Syntax is AFB:signal ([evtHandle], {lua table})"); goto OnErrorExit; } - int done = afb_event_push(afbevt->event, ctlEventJ); + int done = AFB_EventPush(afbevt->event, ctlEventJ); if (!done) { lua_pushliteral (luaState, "LuaAfbEventPush-Fail No Subscriber to event"); - AFB_ERROR ("LuaAfbEventPush-Fail name subscriber event=%s count=%d", afbevt->name, afbevt->count); + AFB_ApiError(source->api, "LuaAfbEventPush-Fail name subscriber event=%s count=%d", afbevt->name, afbevt->count); goto OnErrorExit; } afbevt->count++; return 0; - OnErrorExit: +OnErrorExit: lua_error(luaState); return 1; } @@ -550,28 +571,29 @@ STATIC int LuaAfbEventPush(lua_State* luaState) { STATIC int LuaAfbEventSubscribe(lua_State* luaState) { LuaAfbEvent *afbevt; - LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG); - if (!afbContext) { + CtlSourceT *source= LuaSourcePop(luaState, LUA_FIST_ARG); + if (!source) { lua_pushliteral (luaState, "LuaAfbEventSubscribe-Fail Invalid request handle"); goto OnErrorExit; } // if no private event handle then use default binding event - if (lua_islightuserdata(luaState, LUA_FIST_ARG+1)) { - afbevt = (LuaAfbEvent*) lua_touserdata(luaState, LUA_FIST_ARG+1); - } else { - afbevt=luaDefaultEvt; + if (!lua_islightuserdata(luaState, LUA_FIST_ARG+1)) { + lua_pushliteral (luaState, "LuaAfbMakePush-Fail missing event handle"); + goto OnErrorExit; } + + afbevt = (LuaAfbEvent*) lua_touserdata(luaState, LUA_FIST_ARG+1); - if (!afb_event_is_valid(afbevt->event)) { + if (!AFB_EventIsValid(afbevt->event)) { lua_pushliteral (luaState, "LuaAfbMakePush-Fail invalid event handle"); goto OnErrorExit; } - int err = afb_req_subscribe(afbContext->request, afbevt->event); + int err = AFB_ReqSubscribe(source->request, afbevt->event); if (err) { lua_pushliteral (luaState, "LuaAfbEventSubscribe-Fail No Subscriber to event"); - AFB_ERROR ("LuaAfbEventPush-Fail name subscriber event=%s count=%d", afbevt->name, afbevt->count); + AFB_ApiError(source->api, "LuaAfbEventPush-Fail name subscriber event=%s count=%d", afbevt->name, afbevt->count); goto OnErrorExit; } afbevt->count++; @@ -586,17 +608,24 @@ STATIC int LuaAfbEventMake(lua_State* luaState) { int count = lua_gettop(luaState); LuaAfbEvent *afbevt=calloc(1,sizeof(LuaAfbEvent)); - if (count != LUA_FIST_ARG || !lua_isstring(luaState, LUA_FIST_ARG)) { + CtlSourceT *source= LuaSourcePop(luaState, LUA_FIST_ARG); + if (!source) { + lua_pushliteral (luaState, "LuaAfbEventMake-Fail Invalid request handle"); + goto OnErrorExit; + } + + if (count != LUA_FIST_ARG+1 || !lua_isstring(luaState, LUA_FIST_ARG+1)) { lua_pushliteral (luaState, "LuaAfbEventMake-Syntax is evtHandle= AFB:event ('myEventName')"); goto OnErrorExit; } // event name should be the only argument - afbevt->name= strdup (lua_tostring(luaState,LUA_FIST_ARG)); + afbevt->name= strdup (lua_tostring(luaState,LUA_FIST_ARG+1)); // create a new binder event - afbevt->event = afb_daemon_make_event(afbevt->name); - if (!afb_event_is_valid(afbevt->event)) { + afbevt->event = AFB_EventMake(source->api, afbevt->name); + if (!AFB_EventIsValid(afbevt->event)) { + AFB_ApiError (source->api,"Fail to CreateEvent evtname=%s", afbevt->name); lua_pushliteral (luaState, "LuaAfbEventMake-Fail to Create Binder event"); goto OnErrorExit; } @@ -610,38 +639,63 @@ STATIC int LuaAfbEventMake(lua_State* luaState) { return 1; } +STATIC int LuaAfbGetLabel (lua_State* luaState) { + + CtlSourceT *source= LuaSourcePop(luaState, LUA_FIST_ARG); + if (!source) { + lua_pushliteral (luaState, "LuaAfbEventSubscribe-Fail Invalid request handle"); + goto OnErrorExit; + } + + // extract and return afbSource from timer handle + lua_pushstring(luaState, source->label); + + return 1; // return argument + +OnErrorExit: + return 0; +} + // Function call from LUA when lua2c plugin L2C is used -PUBLIC int Lua2cWrapper(lua_State* luaState, char *funcname, Lua2cFunctionT callback) { +PUBLIC int Lua2cWrapper(void* luaHandle, char *funcname, Lua2cFunctionT callback) { + lua_State* luaState = (lua_State*)luaHandle; + json_object *responseJ=NULL; + + CtlSourceT *source= LuaSourcePop(luaState, LUA_FIST_ARG); - json_object *argsJ= LuaPopArgs(luaState, LUA_FIST_ARG+1); - int response = (*callback) (funcname, argsJ); + json_object *argsJ= LuaPopArgs(source, luaState, LUA_FIST_ARG+1); + int err= (*callback) (source, argsJ, &responseJ); - // push response to LUA - lua_pushinteger(luaState, response); - return 1; + // push error code and eventual response to LUA + int count=1; + lua_pushinteger (luaState, err); + if (!responseJ) count += LuaPushArgument (source, responseJ); + + return count; } // Call a Lua function from a control action -PUBLIC int LuaCallFunc (CtlActionT *action, json_object *queryJ) { +PUBLIC int LuaCallFunc (CtlSourceT *source, CtlActionT *action, json_object *queryJ) { int err, count; json_object* argsJ = action->argsJ; - const char* func = action->call; + const char* func = action->exec.lua.funcname; // load function (should exist in CONTROL_PATH_LUA lua_getglobal(luaState, func); // push source on the stack count=1; - lua_pushstring(luaState, action->source.label); + // Push AFB client context on the stack + LuaAfbSourceT *afbSource= LuaSourcePush(luaState, source); + if (!afbSource) goto OnErrorExit; // push argsJ on the stack if (!argsJ) { - lua_pushnil(luaState); - count++; + lua_pushnil(luaState); count++; } else { - count+= LuaPushArgument (argsJ); + count+= LuaPushArgument (source, argsJ); } // push queryJ on the stack @@ -649,13 +703,13 @@ PUBLIC int LuaCallFunc (CtlActionT *action, json_object *queryJ) { lua_pushnil(luaState); count++; } else { - count+= LuaPushArgument (queryJ); + count+= LuaPushArgument (source, queryJ); } // 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)); + AFB_ApiError(source->api, "LuaCallFunc Fail calling %s error=%s", func, lua_tostring(luaState,-1)); goto OnErrorExit; } @@ -669,11 +723,14 @@ PUBLIC int LuaCallFunc (CtlActionT *action, json_object *queryJ) { // Execute LUA code from received API request -STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { +STATIC void LuaDoAction (LuaDoActionT action, AFB_ReqT request) { int err, count=0; + CtlSourceT *source = alloca(sizeof(CtlSourceT)); + source->request = request; - json_object* queryJ = afb_req_json(request); + json_object* queryJ = AFB_ReqJson(request); + switch (action) { @@ -681,12 +738,12 @@ STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { const char *script = json_object_get_string(queryJ); err=luaL_loadstring(luaState, script); if (err) { - AFB_ERROR ("LUA-DO-COMPILE:FAIL String=%s err=%s", script, lua_tostring(luaState,-1) ); + AFB_ApiError(source->api, "LUA-DO-COMPILE:FAIL String=%s err=%s", script, lua_tostring(luaState,-1) ); goto OnErrorExit; } // Push AFB client context on the stack - LuaAfbContextT *afbContext= LuaCtxPush(luaState, request,NULL,script); - if (!afbContext) goto OnErrorExit; + LuaAfbSourceT *afbSource= LuaSourcePush(luaState, source); + if (!afbSource) goto OnErrorExit; break; } @@ -697,7 +754,7 @@ STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { err= wrap_json_unpack (queryJ, "{s:s, s?o !}", "target", &func, "args", &argsJ); if (err) { - AFB_ERROR ("LUA-DOCALL-SYNTAX missing target|args query=%s", json_object_get_string(queryJ)); + AFB_ApiError(source->api, "LUA-DOCALL-SYNTAX missing target|args query=%s", json_object_get_string(queryJ)); goto OnErrorExit; } @@ -705,15 +762,15 @@ STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { lua_getglobal(luaState, func); // Push AFB client context on the stack - LuaAfbContextT *afbContext= LuaCtxPush(luaState, request, NULL, func); - if (!afbContext) goto OnErrorExit; + LuaAfbSourceT *afbSource= LuaSourcePush(luaState, source); + if (!afbSource) goto OnErrorExit; // push query on the stack if (!argsJ) { lua_pushnil(luaState); count++; } else { - count+= LuaPushArgument (argsJ); + count+= LuaPushArgument (source, argsJ); } break; @@ -732,7 +789,7 @@ STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { json_object *argsJ=NULL; err= wrap_json_unpack (queryJ, "{s:s,s?s,s?s,s?o !}","target", &target,"path",&luaScriptPathJ,"function",&func,"args",&argsJ); if (err) { - AFB_ERROR ("LUA-DOSCRIPT-SYNTAX:missing target|[path]|[function]|[args] query=%s", json_object_get_string(queryJ)); + AFB_ApiError(source->api, "LUA-DOSCRIPT-SYNTAX:missing target|[path]|[function]|[args] query=%s", json_object_get_string(queryJ)); goto OnErrorExit; } @@ -748,11 +805,11 @@ STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { err= wrap_json_unpack (entryJ, "{s:s, s:s !}", "fullpath", &fullpath,"filename", &filename); if (err) { - AFB_ERROR ("LUA-DOSCRIPT-SCAN:HOOPs invalid config file path = %s", json_object_get_string(entryJ)); + AFB_ApiError(source->api, "LUA-DOSCRIPT-SCAN:HOOPs invalid config file path = %s", json_object_get_string(entryJ)); goto OnErrorExit; } - if (index > 0) AFB_WARNING("LUA-DOSCRIPT-SCAN:Ignore second script=%s path=%s", filename, fullpath); + if (index > 0) AFB_ApiWarning(source->api, "LUA-DOSCRIPT-SCAN:Ignore second script=%s path=%s", filename, fullpath); else { strncpy (luaScriptPath, fullpath, sizeof(luaScriptPath)); strncat (luaScriptPath, "/", sizeof(luaScriptPath)); @@ -762,14 +819,14 @@ STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { err= luaL_loadfile(luaState, luaScriptPath); if (err) { - AFB_ERROR ("LUA-DOSCRIPT HOOPs Error in LUA loading scripts=%s err=%s", luaScriptPath, lua_tostring(luaState,-1)); + AFB_ApiError(source->api, "LUA-DOSCRIPT HOOPs Error in LUA loading scripts=%s err=%s", luaScriptPath, lua_tostring(luaState,-1)); goto OnErrorExit; } // script was loaded we need to parse to make it executable err=lua_pcall(luaState, 0, 0, 0); if (err) { - AFB_ERROR ("LUA-DOSCRIPT:FAIL to load %s", luaScriptPath); + AFB_ApiError(source->api, "LUA-DOSCRIPT:FAIL to load %s", luaScriptPath); goto OnErrorExit; } @@ -780,7 +837,7 @@ STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { func=luaScriptPath; } if (!func) { - AFB_ERROR ("LUA-DOSCRIPT:FAIL to deduct funcname from %s", filename); + AFB_ApiError(source->api, "LUA-DOSCRIPT:FAIL to deduct funcname from %s", filename); goto OnErrorExit; } @@ -788,60 +845,73 @@ STATIC void LuaDoAction (LuaDoActionT action, afb_req request) { lua_getglobal(luaState, func); // Push AFB client context on the stack - LuaAfbContextT *afbContext= LuaCtxPush(luaState, request, NULL, func); - if (!afbContext) goto OnErrorExit; + LuaAfbSourceT *afbSource= LuaSourcePush(luaState, source); + if (!afbSource) goto OnErrorExit; // push function arguments if (!argsJ) { lua_pushnil(luaState); count++; } else { - count+= LuaPushArgument(argsJ); + count+= LuaPushArgument(source, argsJ); } break; } default: - AFB_ERROR ("LUA-DOSCRIPT-ACTION unknown query=%s", json_object_get_string(queryJ)); + AFB_ApiError(source->api, "LUA-DOSCRIPT-ACTION unknown query=%s", json_object_get_string(queryJ)); goto OnErrorExit; } // effectively exec LUA code (afb_reply/fail done later from callback) err=lua_pcall(luaState, count+1, 0, 0); if (err) { - AFB_ERROR ("LUA-DO-EXEC:FAIL query=%s err=%s", json_object_get_string(queryJ), lua_tostring(luaState,-1)); + AFB_ApiError(source->api, "LUA-DO-EXEC:FAIL query=%s err=%s", json_object_get_string(queryJ), lua_tostring(luaState,-1)); goto OnErrorExit; } return; OnErrorExit: - afb_req_fail(request,"LUA:ERROR", lua_tostring(luaState,-1)); + AFB_ReqFail(request,"LUA:ERROR", lua_tostring(luaState,-1)); return; } -PUBLIC void ctlapi_execlua (afb_req request) { +PUBLIC void ctlapi_execlua (AFB_ReqT request) { LuaDoAction (LUA_DOSTRING, request); } -PUBLIC void ctlapi_request (afb_req request) { +PUBLIC void ctlapi_request (AFB_ReqT request) { LuaDoAction (LUA_DOCALL, request); } -PUBLIC void ctlapi_debuglua (afb_req request) { +PUBLIC void ctlapi_debuglua (AFB_ReqT request) { LuaDoAction (LUA_DOSCRIPT, request); } -STATIC int LuaTimerClear (lua_State* luaState) { - // Get Timer Handle - LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG); - if (!afbContext) goto OnErrorExit; +STATIC TimerHandleT *LuaTimerPop (lua_State *luaState, int index) { + TimerHandleT *timerHandle; + + luaL_checktype(luaState, index, LUA_TLIGHTUSERDATA); + timerHandle = (TimerHandleT *) lua_touserdata(luaState, index); + + if (timerHandle == NULL && timerHandle->magic != TIMER_MAGIC) { + luaL_error(luaState, "Invalid source handle"); + fprintf(stderr, "LuaSourcePop error retrieving afbSource"); + return NULL; + } + return timerHandle; +} + +STATIC int LuaTimerClear (lua_State* luaState) { // retrieve useful information opaque handle - TimerHandleT *timerHandle = (TimerHandleT*)afbContext->handle; + TimerHandleT *timerHandle = LuaTimerPop(luaState, LUA_FIST_ARG); + if (!timerHandle) goto OnErrorExit; + LuaCbHandleT *luaCbHandle = (LuaCbHandleT*) timerHandle->context; - AFB_NOTICE ("LuaTimerClear timer=%s", timerHandle->label); + AFB_ApiNotice (luaCbHandle->source->api,"LuaTimerClear timer=%s", timerHandle->label); TimerEvtStop(timerHandle); return 0; //happy end @@ -851,13 +921,11 @@ OnErrorExit: } STATIC int LuaTimerGet (lua_State* luaState) { - // Get Timer Handle - LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG); - if (!afbContext) goto OnErrorExit; - // retrieve useful information opaque handle - TimerHandleT *timerHandle = (TimerHandleT*)afbContext->handle; - + TimerHandleT *timerHandle = LuaTimerPop(luaState, LUA_FIST_ARG); + if (!timerHandle) goto OnErrorExit; + LuaCbHandleT *luaCbHandle = (LuaCbHandleT*) timerHandle->context; + // create response as a JSON object json_object *responseJ= json_object_new_object(); json_object_object_add(responseJ,"label", json_object_new_string(timerHandle->label)); @@ -865,7 +933,7 @@ STATIC int LuaTimerGet (lua_State* luaState) { json_object_object_add(responseJ,"count", json_object_new_int(timerHandle->count)); // return JSON object as Lua table - int count=LuaPushArgument(responseJ); + int count=LuaPushArgument(luaCbHandle->source, responseJ); // free json object json_object_put(responseJ); @@ -880,24 +948,24 @@ OnErrorExit: // Set timer STATIC int LuaTimerSetCB (void *handle) { - LuaCallServiceT *contextCB =(LuaCallServiceT*) handle; - TimerHandleT *timerHandle = (TimerHandleT*) contextCB->handle; + LuaCbHandleT *LuaCbHandle = (LuaCbHandleT*) handle; int count; // push timer handle and user context on Lua stack - lua_getglobal(luaState, contextCB->callback); + lua_getglobal(luaState, LuaCbHandle->callback); - // Push timer handle - LuaAfbContextT *afbContext= LuaCtxPush(luaState, NULL_AFBREQ, contextCB->handle, timerHandle->label); - if (!afbContext) goto OnErrorExit; count=1; + // Push AFB client context on the stack + LuaAfbSourceT *afbSource= LuaSourcePush(luaState, LuaCbHandle->source); + if (!afbSource) goto OnErrorExit; // Push user Context - count+= LuaPushArgument(contextCB->context); + count+= LuaPushArgument(LuaCbHandle->source, LuaCbHandle->context); int err=lua_pcall(luaState, count, LUA_MULTRET, 0); if (err) { - AFB_ERROR ("LUA-TIMER-CB:FAIL response=%s err=%s", json_object_get_string(contextCB->context), lua_tostring(luaState,-1)); + printf ("LUA-TIMER-CB:FAIL response=%s err=%s\n", json_object_get_string(LuaCbHandle->context), lua_tostring(luaState,-1)); + AFB_ApiError (LuaCbHandle->source->api,"LUA-TIMER-CB:FAIL response=%s err=%s", json_object_get_string(LuaCbHandle->context), lua_tostring(luaState,-1)); goto OnErrorExit; } @@ -906,26 +974,36 @@ STATIC int LuaTimerSetCB (void *handle) { return (lua_toboolean(luaState, -1)); } - // timer last run free context resource - if (timerHandle->count == 1) { - LuaCtxFree(afbContext); - } return 0; // By default we are happy OnErrorExit: return 1; // stop timer } +// Free Timer context handle +STATIC int LuaTimerCtxFree(void *handle) { + LuaCbHandleT *LuaCbHandle = (LuaCbHandleT*) handle; + + free (LuaCbHandle->source); + free (LuaCbHandle); + + return 0; +} + STATIC int LuaTimerSet(lua_State* luaState) { const char *label=NULL, *info=NULL; int delay=0, count=0; + + // Get source handle + CtlSourceT *source= LuaSourcePop(luaState, LUA_FIST_ARG); + if (!source) goto OnErrorExit; - json_object *timerJ = LuaPopOneArg(luaState, LUA_FIST_ARG); - const char *callback = lua_tostring(luaState, LUA_FIST_ARG + 1); - json_object *contextJ = LuaPopOneArg(luaState, LUA_FIST_ARG + 2); + json_object *timerJ = LuaPopOneArg(source, luaState, LUA_FIST_ARG+1); + const char *callback = lua_tostring(luaState, LUA_FIST_ARG + 2); + json_object *contextJ = LuaPopOneArg(source, luaState, LUA_FIST_ARG + 3); - if (lua_gettop(luaState) != LUA_FIST_ARG+2 || !timerJ || !callback || !contextJ) { - lua_pushliteral(luaState, "LuaTimerSet-Syntax timerset (timerT, 'callback', contextT)"); + if (lua_gettop(luaState) != LUA_FIST_ARG+3 || !timerJ || !callback || !contextJ) { + lua_pushliteral(luaState, "LuaTimerSet-Syntax timerset (source, timerT, 'callback', contextT)"); goto OnErrorExit; } @@ -935,22 +1013,30 @@ STATIC int LuaTimerSet(lua_State* luaState) { goto OnErrorExit; } + // Allocate handle to store context and callback + LuaCbHandleT *handleCb = calloc (1, sizeof(LuaCbHandleT)); + handleCb->callback= callback; + handleCb->context = contextJ; + handleCb->source = malloc(sizeof(CtlSourceT)); + memcpy (handleCb->source, source, sizeof(CtlSourceT)); // Fulup need to be free when timer is done + // everything look fine create timer structure TimerHandleT *timerHandle = malloc (sizeof (TimerHandleT)); + timerHandle->magic= TIMER_MAGIC; timerHandle->delay=delay; timerHandle->count=count; timerHandle->label=label; - - // Allocate handle to store context and callback - LuaCallServiceT *contextCB = calloc (1, sizeof(LuaCallServiceT)); - contextCB->callback= callback; - contextCB->context = contextJ; - contextCB->handle = timerHandle; + timerHandle->freeCB=LuaTimerCtxFree; // fire timer - TimerEvtStart (timerHandle, LuaTimerSetCB, contextCB); + TimerEvtStart (source->api, timerHandle, LuaTimerSetCB, handleCb); + + // Fulup finir les timers avec handle - return 0; // Happy No Return Function + // return empty error code plus timer handle + lua_pushnil(luaState); + lua_pushlightuserdata(luaState, timerHandle); + return 2; OnErrorExit: lua_error(luaState); @@ -982,18 +1068,23 @@ static const luaL_Reg afbFunction[] = { {"subscribe" , LuaAfbEventSubscribe}, {"evtmake" , LuaAfbEventMake}, {"evtpush" , LuaAfbEventPush}, + {"getlabel" , LuaAfbGetLabel}, {NULL, NULL} /* sentinel */ }; // Load Lua Interpreter -PUBLIC int LuaConfigLoad () { - +PUBLIC int LuaConfigLoad (AFB_ApiT apiHandle) { + static int luaLoaded=0; + // Lua loads only once + if (luaLoaded) return 0; + luaLoaded=1; + // open a new LUA interpretor luaState = luaL_newstate(); if (!luaState) { - AFB_ERROR ("LUA_INIT: Fail to open lua interpretor"); + AFB_ApiError(apiHandle, "LUA_INIT: Fail to open lua interpretor"); goto OnErrorExit; } @@ -1004,6 +1095,15 @@ PUBLIC int LuaConfigLoad () { luaL_newlib(luaState, afbFunction); lua_setglobal(luaState, "AFB"); + // initialise static magic for context + #ifndef CTX_MAGIC + CTX_MAGIC=CtlConfigMagicNew(); + #endif + + #ifndef TIMER_MAGIC + TIMER_MAGIC=CtlConfigMagicNew(); + #endif + return 0; OnErrorExit: @@ -1011,17 +1111,9 @@ PUBLIC int LuaConfigLoad () { } // Create Binding Event at Init Exec Time -PUBLIC int LuaConfigExec () { +PUBLIC int LuaConfigExec (AFB_ApiT apiHandle) { int err, index; - // 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;; - } // search for default policy config file char fullprefix[CONTROL_MAXPATH_LEN]; @@ -1046,7 +1138,7 @@ PUBLIC int LuaConfigExec () { char *filename; char*fullpath; err= wrap_json_unpack (entryJ, "{s:s, s:s !}", "fullpath", &fullpath,"filename", &filename); if (err) { - AFB_ERROR ("LUA-INIT HOOPs invalid config file path = %s", json_object_get_string(entryJ)); + AFB_ApiError(apiHandle, "LUA-INIT HOOPs invalid config file path = %s", json_object_get_string(entryJ)); goto OnErrorExit; } @@ -1056,24 +1148,26 @@ PUBLIC int LuaConfigExec () { strncat(filepath, filename, sizeof(filepath)); err= luaL_loadfile(luaState, filepath); if (err) { - AFB_ERROR ("LUA-LOAD HOOPs Error in LUA loading scripts=%s err=%s", filepath, lua_tostring(luaState,-1)); + AFB_ApiError(apiHandle, "LUA-LOAD HOOPs Error in LUA loading scripts=%s err=%s", filepath, lua_tostring(luaState,-1)); goto OnErrorExit; } // exec/compil script err = lua_pcall(luaState, 0, 0, 0); if (err) { - AFB_ERROR ("LUA-LOAD HOOPs Error in LUA exec scripts=%s err=%s", filepath, lua_tostring(luaState,-1)); + AFB_ApiError(apiHandle, "LUA-LOAD HOOPs Error in LUA exec scripts=%s err=%s", filepath, lua_tostring(luaState,-1)); goto OnErrorExit; + } else { + AFB_ApiNotice(apiHandle, "LUA-LOAD '%s'", filepath); } } // no policy config found remove control API from binder if (index == 0) { - AFB_WARNING ("POLICY-INIT:WARNING (setenv CONTROL_LUA_PATH) No LUA '%s*.lua' in '%s'", fullprefix, dirList); + AFB_ApiWarning (apiHandle, "POLICY-INIT:WARNING (setenv CONTROL_LUA_PATH) No LUA '%s*.lua' in '%s'", fullprefix, dirList); } - AFB_DEBUG ("Audio control-LUA Init Done"); + AFB_ApiDebug (apiHandle, "Audio control-LUA Init Done"); return 0; OnErrorExit: diff --git a/ctl-lib/ctl-lua.h b/ctl-lib/ctl-lua.h index 6f2ce7d..53eb6cb 100644 --- a/ctl-lib/ctl-lua.h +++ b/ctl-lib/ctl-lua.h @@ -49,13 +49,6 @@ PUBLIC int LuaLibInit (); -typedef int (*Lua2cFunctionT)(char *funcname, json_object *argsJ); -typedef int (*Lua2cWrapperT) (lua_State* luaState, char *funcname, Lua2cFunctionT callback); - -#define CTLP_LUALOAD Lua2cWrapperT Lua2cWrap; -#define CTLP_LUA2C(FuncName, label,argsJ, context) static int FuncName(char*label,json_object*argsJ);\ - int lua2c_ ## FuncName(lua_State* luaState){return((*Lua2cWrap)(luaState, MACRO_STR_VALUE(FuncName), FuncName, PLUGIN_NAME));};\ - static int FuncName(char* label, json_object* argsJ, void* context) typedef enum { LUA_DOCALL, @@ -64,11 +57,11 @@ typedef enum { } LuaDoActionT; -PUBLIC int LuaConfigLoad(); -PUBLIC int LuaConfigExec(); +PUBLIC int LuaConfigLoad (AFB_ApiT apiHandle); +PUBLIC int LuaConfigExec(AFB_ApiT apiHandle); PUBLIC void LuaL2cNewLib(const char *label, luaL_Reg *l2cFunc, int count); -PUBLIC int Lua2cWrapper(lua_State* luaState, char *funcname, Lua2cFunctionT callback); -PUBLIC int LuaCallFunc (CtlActionT *action, json_object *queryJ) ; +PUBLIC int Lua2cWrapper(void* luaHandle, char *funcname, Lua2cFunctionT callback); +PUBLIC int LuaCallFunc (CtlSourceT *source, CtlActionT *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); diff --git a/ctl-lib/ctl-onload.c b/ctl-lib/ctl-onload.c index 97bd109..1dec75a 100644 --- a/ctl-lib/ctl-onload.c +++ b/ctl-lib/ctl-onload.c @@ -23,29 +23,31 @@ #include "ctl-config.h" // onload section receive one action or an array of actions -PUBLIC int OnloadConfig(CtlSectionT *section, json_object *actionsJ) { - CtlActionT *actions; - - // Load time parse actions in config file +PUBLIC int OnloadConfig(AFB_ApiT apiHandle, CtlSectionT *section, json_object *actionsJ) { + + // Load time parse actions in control file if (actionsJ != NULL) { - actions= ActionLoad(actionsJ); - section->handle=actions; + section->actions= ActionConfig(apiHandle, actionsJ, 0); - if (!actions) { - AFB_ERROR ("OnloadLoad config fail processing onload actions"); + if (!section->actions) { + AFB_ApiError (apiHandle, "OnloadConfig control fail processing onload actions"); goto OnErrorExit; } } else { // Exec time process onload action now - actions=(CtlActionT*)section->handle; - if (!actions) { - AFB_ERROR ("OnloadLoad Cannot Exec Non Existing Onload Action"); + if (!section->actions) { + AFB_ApiError (apiHandle, "OnloadConfig Cannot Exec Non Existing Onload Action"); goto OnErrorExit; } - for (int idx=0; actions[idx].source.label != NULL; idx ++) { - ActionExecOne(&actions[idx], NULL); + for (int idx=0; section->actions[idx].label != NULL; idx ++) { + CtlSourceT source; + source.label = section->actions[idx].label; + source.api = section->actions[idx].api; + source.request = AFB_ReqNone; + + ActionExecOne(&source, §ion->actions[idx], NULL); } } diff --git a/ctl-lib/ctl-plugin.c b/ctl-lib/ctl-plugin.c index f589035..03f4c34 100644 --- a/ctl-lib/ctl-plugin.c +++ b/ctl-lib/ctl-plugin.c @@ -26,20 +26,19 @@ static CtlPluginT *ctlPlugins=NULL; -PUBLIC int PluginGetCB (CtlActionT *action , json_object *callbackJ) { +PUBLIC int PluginGetCB (AFB_ApiT apiHandle, CtlActionT *action , json_object *callbackJ) { const char *plugin=NULL, *function=NULL; json_object *argsJ; int idx; if (!ctlPlugins) { - AFB_ERROR ("PluginGetCB plugin section missing cannot call '%s'", json_object_get_string(callbackJ)); + AFB_ApiError(apiHandle, "PluginGetCB plugin section missing cannot call '%s'", json_object_get_string(callbackJ)); goto OnErrorExit; } - - + int err = wrap_json_unpack(callbackJ, "{ss,ss,s?s,s?o!}", "plugin", &plugin, "function", &function, "args", &argsJ); if (err) { - AFB_ERROR("PluginGet missing plugin|function|[args] in %s", json_object_get_string(callbackJ)); + AFB_ApiError(apiHandle, "PluginGet missing plugin|function|[args] in %s", json_object_get_string(callbackJ)); goto OnErrorExit; } @@ -48,15 +47,16 @@ PUBLIC int PluginGetCB (CtlActionT *action , json_object *callbackJ) { } if (!ctlPlugins[idx].label) { - AFB_ERROR ("PluginGetCB no plugin with label=%s", plugin); + AFB_ApiError(apiHandle, "PluginGetCB no plugin with label=%s", plugin); goto OnErrorExit; } - action->actionCB = dlsym(ctlPlugins[idx].dlHandle, function); - action->source.context = ctlPlugins[idx].context; + action->exec.cb.funcname = function; + action->exec.cb.callback = dlsym(ctlPlugins[idx].dlHandle, function); + action->exec.cb.plugin= &ctlPlugins[idx]; - if (!action->actionCB) { - AFB_ERROR ("PluginGetCB no plugin=%s no function=%s", plugin, function); + if (!action->exec.cb.callback) { + AFB_ApiError(apiHandle, "PluginGetCB no plugin=%s no function=%s", plugin, function); goto OnErrorExit; } return 0; @@ -67,9 +67,9 @@ OnErrorExit: } // Wrapper to Lua2c plugin command add context and delegate to LuaWrapper -STATIC int DispatchOneL2c(lua_State* luaState, char *funcname, Lua2cFunctionT callback) { +STATIC int DispatchOneL2c(void* luaState, char *funcname, Lua2cFunctionT callback) { #ifndef CONTROL_SUPPORT_LUA - AFB_ERROR("CTL-ONE-L2C: LUA support not selected (cf:CONTROL_SUPPORT_LUA) in config.cmake"); + fprintf(stderr, "CTL-ONE-L2C: LUA support not selected (cf:CONTROL_SUPPORT_LUA) in config.cmake"); return 1; #else int err=Lua2cWrapper(luaState, funcname, callback); @@ -77,8 +77,8 @@ STATIC int DispatchOneL2c(lua_State* luaState, char *funcname, Lua2cFunctionT ca #endif } -STATIC int PluginLoadOne (CtlPluginT *ctlPlugin, json_object *pluginJ, void* handle) { - json_object *lua2csJ = NULL, *actionsJ = NULL; +STATIC int PluginLoadOne (AFB_ApiT apiHandle, CtlPluginT *ctlPlugin, json_object *pluginJ, void* handle) { + json_object *lua2csJ = NULL; const char*ldSearchPath = NULL, *basename = NULL; void *dlHandle; @@ -86,12 +86,15 @@ STATIC int PluginLoadOne (CtlPluginT *ctlPlugin, json_object *pluginJ, void* han // plugin initialises at 1st load further init actions should be place into onload section if (!pluginJ) return 0; - int err = wrap_json_unpack(pluginJ, "{ss,s?s,s?s,s?s,ss,s?o,s?o!}", - "label", &ctlPlugin->label, "version", &ctlPlugin->version, "info", &ctlPlugin->info, "ldpath", &ldSearchPath, "basename", &basename, "lua2c", &lua2csJ, "actions", &actionsJ); + int err = wrap_json_unpack(pluginJ, "{ss,s?s,s?s,s?s !}", + "label", &ctlPlugin->label, "info", &ctlPlugin->info, "ldpath", &ldSearchPath, "basename", &basename); if (err) { - AFB_ERROR("CTL-PLUGIN-LOADONE Plugin missing label|basename|version|[info]|[ldpath]|[lua2c]|[actions] in:\n-- %s", json_object_get_string(pluginJ)); + AFB_ApiError(apiHandle, "CTL-PLUGIN-LOADONE Plugin missing label|[info]|[basename]|[ldpath] in:\n-- %s", json_object_get_string(pluginJ)); goto OnErrorExit; } + + // default basename equal label + if (!basename) basename=ctlPlugin->label; // if search path not in Json config file, then try default if (!ldSearchPath) ldSearchPath = CONTROL_PLUGIN_PATH; @@ -99,7 +102,7 @@ STATIC int PluginLoadOne (CtlPluginT *ctlPlugin, json_object *pluginJ, void* han // search for default policy config file json_object *pluginPathJ = ScanForConfig(ldSearchPath, CTL_SCAN_RECURSIVE, basename, CTL_PLUGIN_EXT); if (!pluginPathJ || json_object_array_length(pluginPathJ) == 0) { - AFB_ERROR("CTL-PLUGIN-LOADONE Missing plugin=%s*%s (config ldpath?) search=\n-- %s", basename, CTL_PLUGIN_EXT, ldSearchPath); + AFB_ApiError(apiHandle, "CTL-PLUGIN-LOADONE Missing plugin=%s*%s (config ldpath?) search=\n-- %s", basename, CTL_PLUGIN_EXT, ldSearchPath); goto OnErrorExit; } @@ -107,12 +110,12 @@ STATIC int PluginLoadOne (CtlPluginT *ctlPlugin, json_object *pluginJ, void* han 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("CTL-PLUGIN-LOADONE HOOPs invalid plugin file path=\n-- %s", json_object_get_string(pluginPathJ)); + AFB_ApiError(apiHandle, "CTL-PLUGIN-LOADONE HOOPs invalid plugin file path=\n-- %s", json_object_get_string(pluginPathJ)); goto OnErrorExit; } if (json_object_array_length(pluginPathJ) > 1) { - AFB_WARNING("CTL-PLUGIN-LOADONE plugin multiple instances in searchpath will use %s/%s", fullpath, filename); + AFB_ApiWarning(apiHandle, "CTL-PLUGIN-LOADONE plugin multiple instances in searchpath will use %s/%s", fullpath, filename); } char pluginpath[CONTROL_MAXPATH_LEN]; @@ -121,24 +124,26 @@ STATIC int PluginLoadOne (CtlPluginT *ctlPlugin, json_object *pluginJ, void* han strncat(pluginpath, filename, sizeof (pluginpath)); dlHandle = dlopen(pluginpath, RTLD_NOW); if (!dlHandle) { - AFB_ERROR("CTL-PLUGIN-LOADONE Fail to load pluginpath=%s err= %s", pluginpath, dlerror()); + AFB_ApiError(apiHandle, "CTL-PLUGIN-LOADONE Fail to load pluginpath=%s err= %s", pluginpath, dlerror()); goto OnErrorExit; } CtlPluginMagicT *ctlPluginMagic = (CtlPluginMagicT*) dlsym(dlHandle, "CtlPluginMagic"); if (!ctlPluginMagic || ctlPluginMagic->magic != CTL_PLUGIN_MAGIC) { - AFB_ERROR("CTL-PLUGIN-LOADONE symbol'CtlPluginMagic' missing or != CTL_PLUGIN_MAGIC plugin=%s", pluginpath); + AFB_ApiError(apiHandle, "CTL-PLUGIN-LOADONE symbol'CtlPluginMagic' missing or != CTL_PLUGIN_MAGIC plugin=%s", pluginpath); goto OnErrorExit; } else { - AFB_NOTICE("CTL-PLUGIN-LOADONE %s successfully registered", ctlPluginMagic->label); + AFB_ApiNotice(apiHandle, "CTL-PLUGIN-LOADONE %s successfully registered", ctlPluginMagic->label); } // store dlopen handle to enable onload action at exec time ctlPlugin->dlHandle = dlHandle; - // Jose hack to make verbosity visible from sharelib +#ifndef AFB_BINDING_PREV3 + // Jose hack to make verbosity visible from sharelib with API-V2 struct afb_binding_data_v2 *afbHidenData = dlsym(dlHandle, "afbBindingV2data"); if (afbHidenData) *afbHidenData = afbBindingV2data; +#endif // Push lua2cWrapper @ into plugin Lua2cWrapperT *lua2cInPlug = dlsym(dlHandle, "Lua2cWrap"); @@ -156,7 +161,7 @@ STATIC int PluginLoadOne (CtlPluginT *ctlPlugin, json_object *pluginJ, void* han Lua2cFunctionT l2cFunction = (Lua2cFunctionT) dlsym(dlHandle, funcName); if (!l2cFunction) { - AFB_ERROR("CTL-PLUGIN-LOADONE symbol'%s' missing err=%s", funcName, dlerror()); + AFB_ApiError(apiHandle, "CTL-PLUGIN-LOADONE symbol'%s' missing err=%s", funcName, dlerror()); return 1; } l2cFunc[index].func = (void*) l2cFunction; @@ -184,13 +189,14 @@ STATIC int PluginLoadOne (CtlPluginT *ctlPlugin, json_object *pluginJ, void* han errCount = Lua2cAddOne(l2cFunc, l2cName, 0); } if (errCount) { - AFB_ERROR("CTL-PLUGIN-LOADONE %d symbols not found in plugin='%s'", errCount, pluginpath); + AFB_ApiError(apiHandle, "CTL-PLUGIN-LOADONE %d symbols not found in plugin='%s'", errCount, pluginpath); goto OnErrorExit; } } #endif DispatchPluginInstallCbT ctlPluginOnload = dlsym(dlHandle, "CtlPluginOnload"); if (ctlPluginOnload) { + ctlPlugin->api = apiHandle; ctlPlugin->context = (*ctlPluginOnload) (ctlPlugin, handle); } return 0; @@ -200,7 +206,7 @@ OnErrorExit: } -PUBLIC int PluginConfig(CtlSectionT *section, json_object *pluginsJ) { +PUBLIC int PluginConfig(AFB_ApiT apiHandle, CtlSectionT *section, json_object *pluginsJ) { int err=0; if (json_object_get_type(pluginsJ) == json_type_array) { @@ -208,11 +214,11 @@ PUBLIC int PluginConfig(CtlSectionT *section, json_object *pluginsJ) { ctlPlugins = calloc (length+1, sizeof(CtlPluginT)); for (int idx=0; idx < length; idx++) { json_object *pluginJ = json_object_array_get_idx(pluginsJ, idx); - err += PluginLoadOne(&ctlPlugins[idx], pluginJ, section->handle); + err += PluginLoadOne(apiHandle, &ctlPlugins[idx], pluginJ, section->handle); } } else { ctlPlugins = calloc (2, sizeof(CtlPluginT)); - err += PluginLoadOne(&ctlPlugins[0], pluginsJ, section->handle); + err += PluginLoadOne(apiHandle, &ctlPlugins[0], pluginsJ, section->handle); } return err; diff --git a/ctl-lib/ctl-plugin.h b/ctl-lib/ctl-plugin.h index e0ab3dd..a678af4 100644 --- a/ctl-lib/ctl-plugin.h +++ b/ctl-lib/ctl-plugin.h @@ -20,9 +20,112 @@ #ifndef _CTL_PLUGIN_INCLUDE_ #define _CTL_PLUGIN_INCLUDE_ + #define _GNU_SOURCE #include <json-c/json.h> +// Waiting for a clean AppFW-V3 API +#ifdef USE_API_DYN + #define AFB_BINDING_VERSION dyn + #include <afb/afb-binding.h> + + #define AFB_BINDING_PREV3 + #define AFB_ReqNone NULL + typedef afb_request* AFB_ReqT; + typedef afb_dynapi* AFB_ApiT; + + typedef afb_eventid* AFB_EventT; + #define AFB_EventIsValid(eventid) eventid + #define AFB_EventPush afb_eventid_push + #define AFB_ReqSubscribe afb_request_subscribe + #define AFB_EventMake(api, name) afb_dynapi_make_eventid(api, name) + + #define AFB_ReqJson(request) afb_request_json(request) + + #define AFB_ReqSucess afb_request_success + #define AFB_ReqSucessF afb_request_success_f + #define AFB_ReqFail afb_request_fail + #define AFB_ReqFailF afb_request_fail_f + + #define AFB_ReqNotice(request, ...) AFB_REQUEST_NOTICE (request, __VA_ARGS__) + #define AFB_ReqWarning(request, ...) AFB_REQUEST_WARNING (request, __VA_ARGS__) + #define AFB_ReqDebug(request, ...) AFB_REQUEST_DEBUG (request, __VA_ARGS__) + #define AFB_ReqError(request, ...) AFB_REQUEST_ERROR (request, __VA_ARGS__) + #define AFB_ReqInfo(request, ...) AFB_REQUEST_INFO (request, __VA_ARGS__) + + #define AFB_ApiVerbose(api, level, ...) afb_dynapi_verbose(api, level, __VA_ARGS__) + #define AFB_ApiNotice(api, ...) AFB_DYNAPI_NOTICE (api, __VA_ARGS__) + #define AFB_ApiWarning(api, ...) AFB_DYNAPI_WARNING (api, __VA_ARGS__) + #define AFB_ApiDebug(api, ...) AFB_DYNAPI_DEBUG (api, __VA_ARGS__) + #define AFB_ApiError(api, ...) AFB_DYNAPI_ERROR (api, __VA_ARGS__) + #define AFB_ApiInfo(api, ...) AFB_DYNAPI_INFO (api, __VA_ARGS__) + + #define AFB_ReqIsValid(request) request + #define AFB_EvtIsValid(evtHandle) evtHandle + + #define AFB_ServiceCall(api, ...) afb_dynapi_call(api, __VA_ARGS__) + #define AFB_ServiceSync(api, ...) afb_dynapi_call_sync(api, __VA_ARGS__) + + #define AFB_RequireApi(api, ...) afb_dynapi_require_api(api, __VA_ARGS__) + + #define AFB_GetEventLoop(api) afb_dynapi_get_event_loop(api) + + + typedef struct { + const char *verb; /* name of the verb, NULL only at end of the array */ + void (*callback)(AFB_ReqT req); /* callback function implementing the verb */ + const struct afb_auth *auth; /* required authorisation, can be NULL */ + const char *info; /* some info about the verb, can be NULL */ + uint32_t session; + } AFB_ApiVerbs; + +#else + #define AFB_BINDING_VERSION 2 + #include <afb/afb-binding.h> + + typedef afb_req AFB_ReqT; + typedef void* AFB_ApiT; + #define AFB_ReqNone (struct afb_req){0,0} + + typedef afb_event AFB_EventT; + #define AFB_EventPush afb_event_push + #define AFB_ReqSubscribe afb_req_subscribe + #define AFB_EventIsValid(event) afb_event_is_valid(event) + #define AFB_EventMake(api, name) afb_daemon_make_event(name) + + #define AFB_ReqJson(request) afb_req_json(request) + #define AFB_ReqSucess afb_req_success + #define AFB_ReqSucessF afb_req_success_f + #define AFB_ReqFail afb_req_fail + #define AFB_ReqFailF afb_req_fail_f + + #define AFB_ReqNotice(request, ...) AFB_NOTICE (__VA_ARGS__) + #define AFB_ReqWarning(request, ...) AFB_WARNING (__VA_ARGS__) + #define AFB_ReqDebug(request, ...) AFB_DEBUG (__VA_ARGS__) + #define AFB_ReqError(request, ...) AFB_ERROR (__VA_ARGS__) + #define AFB_ReqInfo(request, ...) AFB_INFO (__VA_ARGS__) + + #define AFB_ApiVerbose(api, level, ...) afb_daemon_verbose_v2(level,__VA_ARGS__) + #define AFB_ApiNotice(api, ...) AFB_NOTICE (__VA_ARGS__) + #define AFB_ApiWarning(api, ...) AFB_WARNING (__VA_ARGS__) + #define AFB_ApiDebug(api, ...) AFB_DEBUG (__VA_ARGS__) + #define AFB_ApiError(api, ...) AFB_ERROR (__VA_ARGS__) + #define AFB_ApiInfo(api, ...) AFB_INFO (__VA_ARGS__) + + #define AFB_ReqIsValid(request) afb_req_is_valid(request) + #define AFB_EvtIsValid(evtHandle) afb_event_is_valid(evtHandle) + + #define AFB_ServiceCall(api, ...) afb_service_call(__VA_ARGS__) + #define AFB_ServiceSync(api, ...) afb_service_call_sync(__VA_ARGS__) + + #define AFB_RequireApi (api, ...) afb_daemon_require_api(__VA_ARGS__) + + #define AFB_GetEventLoop(api) afb_daemon_get_event_loop() + + #define AFB_ApiVerbs afb_verb_v2 +#endif + + #ifndef CTL_PLUGIN_MAGIC #define CTL_PLUGIN_MAGIC 852369147 #endif @@ -40,35 +143,76 @@ #define UNUSED_FUNCTION(x) __attribute__((__unused__)) UNUSED_ ## x #endif -typedef struct { - char *label; - char *info; - afb_req request; - void *context; -} CtlSourceT; - + typedef struct { - long magic; - char *label; - void *handle; + const char *label; + const long magic; } CtlPluginMagicT; +typedef struct { + const char *label; + const char *info; + AFB_ApiT api; + void *dlHandle; + void *context; +} CtlPluginT; + + +typedef enum { + CTL_TYPE_NONE=0, + CTL_TYPE_API, + CTL_TYPE_CB, + CTL_TYPE_LUA, +} CtlActionTypeT; typedef struct { const char *label; - const char *info; - const char *version; + AFB_ApiT api; + AFB_ReqT request; void *context; - void *dlHandle; -} CtlPluginT; +} CtlSourceT; + +typedef struct { + const char *label; + const char *info; + AFB_ApiT api; + json_object *argsJ; + CtlActionTypeT type; + union { + struct { + const char* api; + const char* verb; + } subcall; + + struct { + const char* load; + const char* funcname; + } lua; + + struct { + const char* funcname; + int (*callback)(CtlSourceT *source, json_object *argsJ, json_object *queryJ); + CtlPluginT *plugin; + } cb; + } exec; +} CtlActionT; -typedef void*(*DispatchPluginInstallCbT)(CtlPluginT *plugin, void* handle); +typedef void*(*DispatchPluginInstallCbT)(CtlPluginT *plugin, void* handle); #define MACRO_STR_VALUE(arg) #arg -#define CTLP_REGISTER(pluglabel) CtlPluginMagicT CtlPluginMagic={.magic=CTL_PLUGIN_MAGIC,.label=pluglabel}; struct afb_binding_data_v2; +#define CTLP_CAPI_REGISTER(pluglabel) CtlPluginMagicT CtlPluginMagic={.magic=CTL_PLUGIN_MAGIC,.label=pluglabel}; struct afb_binding_data_v2; #define CTLP_ONLOAD(plugin, handle) void* CtlPluginOnload(CtlPluginT *plugin, void* handle) #define CTLP_CAPI(funcname, source, argsJ, queryJ) int funcname(CtlSourceT *source, json_object* argsJ, json_object* queryJ) +// LUA2c Wrapper macro. Allows to call C code from Lua script +typedef int (*Lua2cFunctionT)(CtlSourceT *source, json_object *argsJ, json_object **responseJ); +typedef int (*Lua2cWrapperT) (void*luaHandle, char *funcname, Lua2cFunctionT callback); + +#define CTLP_LUA_REGISTER(pluglabel) Lua2cWrapperT Lua2cWrap; CTLP_CAPI_REGISTER(pluglabel); +#define CTLP_LUA2C(funcname, source, argsJ, responseJ) static int funcname (CtlSourceT* source, json_object* argsJ, json_object** responseJ);\ + int lua2c_ ## funcname (void* luaState){return((*Lua2cWrap)(luaState, MACRO_STR_VALUE(funcname), funcname));};\ + static int funcname (CtlSourceT* source, json_object* argsJ, json_object** responseJ) + #endif /* _CTL_PLUGIN_INCLUDE_ */
\ No newline at end of file diff --git a/ctl-lib/ctl-timer.c b/ctl-lib/ctl-timer.c index 1de6f99..81aa984 100644 --- a/ctl-lib/ctl-timer.c +++ b/ctl-lib/ctl-timer.c @@ -30,7 +30,6 @@ typedef struct { const char *label; } AutoTestCtxT; -static afb_event afbevt; STATIC int TimerNext (sd_event_source* source, uint64_t timer, void* handle) { TimerHandleT *timerHandle = (TimerHandleT*) handle; @@ -41,12 +40,13 @@ STATIC int TimerNext (sd_event_source* source, uint64_t timer, void* handle) { timerHandle->count --; if (timerHandle->count == 0) { sd_event_source_unref(source); + if (timerHandle->freeCB) timerHandle->freeCB(timerHandle->context); free (handle); return 0; } else { // otherwise validate timer for a new run - sd_event_now(afb_daemon_get_event_loop(), CLOCK_MONOTONIC, &usec); + sd_event_now(AFB_GetEventLoop(timerHandle->api), CLOCK_MONOTONIC, &usec); sd_event_source_set_enabled(source, SD_EVENT_ONESHOT); sd_event_source_set_time(source, usec + timerHandle->delay*1000); } @@ -57,7 +57,7 @@ STATIC int TimerNext (sd_event_source* source, uint64_t timer, void* handle) { return 0; OnErrorExit: - AFB_WARNING("TimerNext Callback Fail Tag=%s", timerHandle->label); + AFB_ApiWarning(timerHandle->api, "TimerNext Callback Fail Tag=%s", timerHandle->label); return -1; } @@ -68,34 +68,24 @@ PUBLIC void TimerEvtStop(TimerHandleT *timerHandle) { } -PUBLIC void TimerEvtStart(TimerHandleT *timerHandle, timerCallbackT callback, void *context) { +PUBLIC void TimerEvtStart(AFB_ApiT apiHandle, TimerHandleT *timerHandle, timerCallbackT callback, void *context) { uint64_t usec; // populate CB handle timerHandle->callback=callback; timerHandle->context=context; + timerHandle->api=apiHandle; // set a timer with ~250us accuracy - sd_event_now(afb_daemon_get_event_loop(), CLOCK_MONOTONIC, &usec); - sd_event_add_time(afb_daemon_get_event_loop(), &timerHandle->evtSource, CLOCK_MONOTONIC, usec+timerHandle->delay*1000, 250, TimerNext, timerHandle); -} - -PUBLIC afb_event TimerEvtGet(void) { - return afbevt; + sd_event_now(AFB_GetEventLoop(apiHandle), CLOCK_MONOTONIC, &usec); + sd_event_add_time(AFB_GetEventLoop(apiHandle), &timerHandle->evtSource, CLOCK_MONOTONIC, usec+timerHandle->delay*1000, 250, TimerNext, timerHandle); } // Create Binding Event at Init -PUBLIC int TimerEvtInit () { - - // create binder event to send test pause/resume - afbevt = afb_daemon_make_event("control"); - if (!afb_event_is_valid(afbevt)) { - AFB_ERROR ("POLCTL_INIT: Cannot register ctl-events"); - return 1; - } +PUBLIC int TimerEvtInit (AFB_ApiT apiHandle) { - AFB_DEBUG ("Audio Control-Events Init Done"); + AFB_ApiDebug (apiHandle, "Timer-Init Done"); return 0; } diff --git a/ctl-lib/ctl-timer.h b/ctl-lib/ctl-timer.h index b08299f..ced0417 100644 --- a/ctl-lib/ctl-timer.h +++ b/ctl-lib/ctl-timer.h @@ -26,17 +26,19 @@ typedef int (*timerCallbackT)(void *context); typedef struct TimerHandleS { + int magic; int count; int delay; const char*label; void *context; timerCallbackT callback; sd_event_source *evtSource; + AFB_ApiT api; + timerCallbackT freeCB; } TimerHandleT; -PUBLIC int TimerEvtInit (void); -PUBLIC afb_event TimerEvtGet(void); -PUBLIC void TimerEvtStart(TimerHandleT *timerHandle, timerCallbackT callback, void *context); +PUBLIC int TimerEvtInit (AFB_ApiT apiHandle); +PUBLIC void TimerEvtStart(AFB_ApiT apiHandle, TimerHandleT *timerHandle, timerCallbackT callback, void *context); PUBLIC void TimerEvtStop(TimerHandleT *timerHandle); #endif // CTL_TIMER_INCLUDE |