summaryrefslogtreecommitdiffstats
path: root/signal-composer-binding
diff options
context:
space:
mode:
Diffstat (limited to 'signal-composer-binding')
-rw-r--r--signal-composer-binding/CMakeLists.txt3
-rw-r--r--signal-composer-binding/ctl-dispatch.c705
-rw-r--r--signal-composer-binding/ctl-lua.c1057
-rw-r--r--signal-composer-binding/ctl-lua.h28
-rw-r--r--signal-composer-binding/observer.hpp30
-rw-r--r--signal-composer-binding/signal-composer-apidef.h32
-rw-r--r--signal-composer-binding/signal-composer-apidef.json2
-rw-r--r--signal-composer-binding/signal-composer-binding.cpp64
-rw-r--r--signal-composer-binding/signal-composer-binding.hpp9
-rw-r--r--signal-composer-binding/signal-composer.cpp243
-rw-r--r--signal-composer-binding/signal-composer.hpp92
-rw-r--r--signal-composer-binding/signal.cpp86
-rw-r--r--signal-composer-binding/signal.hpp44
-rw-r--r--signal-composer-binding/source.cpp42
-rw-r--r--signal-composer-binding/source.hpp42
15 files changed, 567 insertions, 1912 deletions
diff --git a/signal-composer-binding/CMakeLists.txt b/signal-composer-binding/CMakeLists.txt
index 78db103..8757204 100644
--- a/signal-composer-binding/CMakeLists.txt
+++ b/signal-composer-binding/CMakeLists.txt
@@ -21,7 +21,7 @@
PROJECT_TARGET_ADD(signal-composer)
# Define project Targets
- add_library(${TARGET_NAME} MODULE ${TARGET_NAME}-binding.cpp ${TARGET_NAME}.cpp ctl-lua.c ctl-dispatch.c)
+ add_library(${TARGET_NAME} MODULE ${TARGET_NAME}-binding.cpp ${TARGET_NAME}.cpp signal-composer.cpp source.cpp)
# Binder exposes a unique public entry point
SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES
@@ -37,5 +37,6 @@ PROJECT_TARGET_ADD(signal-composer)
# Library dependencies (include updates automatically)
TARGET_LINK_LIBRARIES(${TARGET_NAME}
afb-utilities
+ afb-controller
${link_libraries}
)
diff --git a/signal-composer-binding/ctl-dispatch.c b/signal-composer-binding/ctl-dispatch.c
deleted file mode 100644
index b84c86e..0000000
--- a/signal-composer-binding/ctl-dispatch.c
+++ /dev/null
@@ -1,705 +0,0 @@
-/*
- * Copyright (C) 2016 "IoT.bzh"
- * Author Fulup Ar Foll <fulup@iot.bzh>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, something express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Reference:
- * Json load using json_unpack https://jansson.readthedocs.io/en/2.9/apiref.html#parsing-and-validating-values
- */
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <string.h>
-#include <dlfcn.h>
-#include <sys/prctl.h>
-#include <filescan-utils.h>
-#include <wrap-json.h>
-
-#include "ctl-lua.h"
-#include "signal-composer-binding.hpp"
-
-typedef void*(*DispatchPluginInstallCbT)(const char* label, const char*version, const char*info);
-
-static afb_req NULL_AFBREQ = {};
-
-typedef struct {
- const char* id;
- const char* source;
- const char* class;
- DispatchActionT* onReceived;
-} DispatchSignalT;
-
-typedef struct {
- const char* label;
- const char* info;
- const char* ssource;
- const char* sclass;
- DispatchActionT* actions;
-} DispatchHandleT;
-
-typedef struct {
- const char *label;
- const char *info;
- void *context;
- char *sharelib;
- void *dlHandle;
- luaL_Reg *l2cFunc;
- int l2cCount;
-} DispatchPluginT;
-
-typedef struct {
- const char* label;
- const char *info;
- const char *version;
- DispatchPluginT *plugin;
- DispatchHandleT **sources;
- DispatchHandleT **signals;
-} DispatchConfigT;
-
-// global config handle
-static DispatchConfigT *configHandle = NULL;
-
-static int DispatchSignalToIndex(DispatchHandleT **signals, const char* controlLabel) {
-
- for (int idx = 0; signals[idx]; idx++) {
- if (!strcasecmp(controlLabel, signals[idx]->label)) return idx;
- }
- return -1;
-}
-
-static int DispatchOneSignal(DispatchSourceT source, DispatchHandleT **signals, const char* controlLabel, json_object *queryJ, afb_req request) {
- int err;
-
- if (!configHandle) {
- AFB_ERROR("DISPATCH-CTL-API: (Hoops/Bug!!!) No Config Loaded");
- return -1;
- }
-
- if (!configHandle->signals) {
- AFB_ERROR("DISPATCH-CTL-API: No Signal Action in Json config label=%s version=%s", configHandle->label, configHandle->version);
- return -1;
- }
-
- int index = DispatchSignalToIndex(signals, controlLabel);
- if (index < 0 || !signals[index]->actions) {
- AFB_ERROR("DISPATCH-CTL-API:NotFound/Error label=%s in Json Signal Config File", controlLabel);
- return -1;
- }
-
- // 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 = signals[index]->actions;
- for (int idx = 0; actions[idx].label; idx++) {
-
- switch (actions[idx].mode) {
- case CTL_MODE_API:
- {
- json_object *returnJ;
-
- // if query is empty increment usage count and pass args
- if (!queryJ || json_object_get_type(queryJ) != json_type_object) {
- json_object_get(actions[idx].argsJ);
- queryJ= actions[idx].argsJ;
- } else if (actions[idx].argsJ) {
-
- // Merge queryJ and argsJ before sending request
- if (json_object_get_type(actions[idx].argsJ) == json_type_object) {
- json_object_object_foreach(actions[idx].argsJ, key, val) {
- json_object_object_add(queryJ, key, val);
- }
- } else {
- json_object_object_add(queryJ, "args", actions[idx].argsJ);
- }
- }
-
- int err = afb_service_call_sync(actions[idx].api, actions[idx].call, queryJ, &returnJ);
- if (err) {
- static const char*format = "DispatchOneSignal(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);
- return -1;
- }
- break;
- }
-
-#ifdef CONTROL_SUPPORT_LUA
- case CTL_MODE_LUA:
- err = LuaCallFunc(source, &actions[idx], queryJ);
- if (err) {
- static const char*format = "DispatchOneSignal(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));
- return -1;
- }
- break;
-#endif
-
- case CTL_MODE_CB:
- err = (*actions[idx].actionCB) (source, actions[idx].label, actions[idx].argsJ, queryJ, configHandle->plugin->context);
- if (err) {
- static const char*format = "DispatchOneSignal(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));
- return -1;
- }
- break;
-
- default:
- {
- static const char*format = "DispatchOneSignal(unknown) mode control=%s action=%s";
- AFB_ERROR(format, signals[index]->label);
- if (afb_req_is_valid(request))afb_req_fail_f(request, "DISPATCH-CTL-MODE:Unknown", format, signals[index]->label);
- }
- }
- }
-
- // everything when fine
- if (afb_req_is_valid(request)) afb_req_success(request, NULL, signals[index]->label);
- return 0;
-}
-
-// Event name is mapped on control label and executed as a standard control
-/*
-void DispatchOneEvent(const char *evtLabel, json_object *eventJ) {
- DispatchHandleT **events = configHandle->events;
-
- (void) DispatchOneSignal(CTL_SOURCE_EVENT, events, evtLabel, eventJ, NULL_AFBREQ);
-}
-*/
-// Event name is mapped on control label and executed as a standard control
-
-int DispatchSources() {
- if (!configHandle) return 1;
-
- int err = 0;
- DispatchHandleT **sources = configHandle->sources;
- ssize_t i = 0, nSources = sizeof(*sources) / sizeof(DispatchHandleT);
-
- while(i < nSources) {
- const char* sourceLabel = sources[i++]->label;
- err = DispatchOneSignal(CTL_SOURCE_ONLOAD, sources, sourceLabel, NULL, NULL_AFBREQ);
- }
-
- return err;
-}
-
-void ctlapi_dispatch(afb_req request) {
- DispatchHandleT **signals = configHandle->signals;
- json_object *queryJ, *argsJ=NULL;
- const char *target;
- DispatchSourceT source= CTL_SOURCE_UNKNOWN;
-
- queryJ = afb_req_json(request);
- int err = wrap_json_unpack(queryJ, "{s:s, s?i s?o !}", "target", &target, "source", &source, "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));
- return;
- }
-
- (void) DispatchOneSignal(source, signals, target, argsJ, request);
-}
-
-// Wrapper to Lua2c plugin command add context dans delegate to LuaWrapper
-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
-
-void ctlapi_config(struct afb_req request) {
- json_object*tmpJ;
- char *dirList;
- // Compile some default directories to browse
- char defaultConfPath[CONTROL_MAXPATH_LEN];
- strncpy(defaultConfPath, GetBindingDirPath(), sizeof(GetBindingDirPath()));
- strncat(defaultConfPath, "/etc:", sizeof(defaultConfPath) - strlen(defaultConfPath) - 1);
- strncat(defaultConfPath, GetBindingDirPath(), sizeof(defaultConfPath) - strlen(defaultConfPath) - 1);
- strncat(defaultConfPath, "/data", sizeof(defaultConfPath) - strlen(defaultConfPath) - 1);
-
-
- 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 = getenv("CONTROL_CONFIG_PATH");
- if (!dirList) dirList = defaultConfPath;
- AFB_NOTICE("CONFIG-MISSING: use default CONTROL_CONFIG_PATH=%s", defaultConfPath);
- }
-
- // 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");
- } 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, *function = NULL;
- int err, modeCount = 0;
-
- err = wrap_json_unpack(actionJ, "{s?s,s?s,s?s,s?s,s?s,s?s,s?s,s?o !}"
- , "label", &action->label
- , "info", &action->info
- , "function", &function
- , "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));
- return -1;
- }
-
- // Generic way to specify a C or LUA actions
- if(function) {
- if(strcasestr(function, "lua")) {
- action->mode = CTL_MODE_LUA;
- action->call = function;
- modeCount++;
- }
- else if(controlConfig->plugin) {
- action->mode = CTL_MODE_CB;
- action->call = callback;
- modeCount++;
-
- 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->sharelib);
- return -1;
- }
- }
- // If label not already set then use function name
- if(! &action->label) action->label = function;
- }
-
- if (lua) {
- action->mode = CTL_MODE_LUA;
- action->call = lua;
- modeCount++;
- // If label not already set then use function name
- if(! &action->label) action->label = lua;
- }
-
- if (api && verb) {
- action->mode = CTL_MODE_API;
- action->api = api;
- action->call = verb;
- modeCount++;
- char* apiVerb = strdup(api);
- apiVerb = strncat(apiVerb, "/", sizeof(*apiVerb) - strlen(apiVerb) - 1);
- apiVerb = strncat(apiVerb, verb, sizeof(*apiVerb) - strlen(apiVerb) - 1);
- // If label not already set then use function name
- if(! &action->label) action->label = apiVerb;
- free(apiVerb);
- }
-
- if (callback && controlConfig->plugin) {
- action->mode = CTL_MODE_CB;
- action->call = callback;
- modeCount++;
-
- 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->sharelib);
- return -1;
- }
- }
-
- // 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));
- return -1;
- }
-
- if (modeCount > 1) {
- AFB_ERROR("DISPATCH-LOAD-ACTION:Too Many arguments lua|callback|(api+verb) in %s", json_object_get_string(actionJ));
- return -1;
- }
- return 0;
-};
-
-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++) {
- json_object *actionJ = json_object_array_get_idx(actionsJ, idx);
- err = DispatchLoadOneAction(controlConfig, actionJ, &actions[idx]);
- if (err) return NULL;
- }
-
- } else {
- actions = calloc(2, sizeof (DispatchActionT));
- err = DispatchLoadOneAction(controlConfig, actionsJ, &actions[0]);
- if (err) return NULL;
- }
-
- return actions;
-}
-
-static void DispatchLoadPlugin(DispatchConfigT *controlConfig, json_object* sourcesJ, json_object* pluginJ)
-{
- int err = 0;
- json_object *lua2csJ = NULL;
- DispatchPluginT *dPlugin= calloc(1, sizeof(DispatchPluginT));
- controlConfig->plugin = dPlugin;
- const char*ldSearchPath=NULL;
-
- err = wrap_json_unpack(pluginJ, "{ss,s?s,s?s,ss,s?o!}",
- "label", &dPlugin->label, "info", &dPlugin->info, "ldpath", &ldSearchPath, "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(sourcesJ));
- return;
- }
-
- // if search path not in Json config file, then try default
- if (!ldSearchPath) ldSearchPath= strncat(GetBindingDirPath(), "/data", sizeof(GetBindingDirPath()) - strlen(GetBindingDirPath()) - 1);
-
- // search for default policy config file
- json_object *pluginPathJ = ScanForConfig(ldSearchPath, 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", dPlugin->sharelib, ldSearchPath);
- return;
- }
-
- 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));
- return;
- }
-
- if (json_object_array_length(pluginPathJ) > 1) {
- 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)-strlen(pluginpath)-1);
- strncat(pluginpath, filename, sizeof (pluginpath)-strlen(pluginpath)-1);
- dPlugin->dlHandle = dlopen(pluginpath, RTLD_NOW);
- if (!dPlugin->dlHandle) {
- AFB_ERROR("DISPATCH-LOAD-CONFIG:PLUGIN Fail to load pluginpath=%s err= %s", pluginpath, dlerror());
- return;
- }
-
- 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);
- return;
- } else {
- AFB_NOTICE("DISPATCH-LOAD-CONFIG:Plugin %s successfully registered", ctlPluginMagic->label);
- }
-
- // Jose hack to make verbosity visible from sharelib
- 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)-strlen(funcName)-1);
-
- 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;
- }
-
- 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);
- return;
- } else {
- dPlugin->l2cFunc= l2cFunc;
- dPlugin->l2cCount= count;
- }
- }
-#endif
- DispatchPluginInstallCbT ctlPluginOnload = dlsym(dPlugin->dlHandle, "CtlPluginOnload");
- if (ctlPluginOnload) {
- dPlugin->context = (*ctlPluginOnload) (controlConfig->label, controlConfig->version, controlConfig->info);
- }
-}
-
-static DispatchHandleT *DispatchLoadSignal(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,ss,ss,s?o,so !}"
- , "id", &dispatchHandle->label
- , "info", &dispatchHandle->info
- , "source", &dispatchHandle->ssource
- , "class", &dispatchHandle->sclass
- , "permissions", &permissionsJ
- , "onReceived", &actionsJ);
- if (err) {
- AFB_ERROR("DISPATCH-LOAD-CONFIG:CONTROL Missing something label|[info]|actions in %s", json_object_get_string(controlJ));
- return NULL;
- }
-
- dispatchHandle->actions = DispatchLoadActions(controlConfig, actionsJ);
- if (!dispatchHandle->actions) {
- AFB_ERROR("DISPATCH-LOAD-CONFIG:CONTROL Error when parsing actions %s", dispatchHandle->label);
- return NULL;
- }
- return dispatchHandle;
-}
-
-static DispatchHandleT *DispatchLoadSource(DispatchConfigT *controlConfig, json_object *sourcesJ) {
- json_object *actionsJ = NULL, *pluginJ = NULL;
- int err;
-
- DispatchHandleT *dispatchSources = calloc(1, sizeof (DispatchHandleT));
- err = wrap_json_unpack(sourcesJ, "{ss,s?s,s?o,s?o,s?o !}",
- "api", &dispatchSources->label, "info", &dispatchSources->info, "plugin", &pluginJ, "actions", &actionsJ);
- if (err) {
- AFB_ERROR("DISPATCH-LOAD-CONFIG:ONLOAD Missing something label|[info]|[plugin]|[actions] in %s", json_object_get_string(sourcesJ));
- return NULL;
- }
-
- // best effort to initialise everything before starting
- err = afb_daemon_require_api(dispatchSources->label, 1);
- if (err) {
- AFB_WARNING("DISPATCH-LOAD-CONFIG:REQUIRE Fail to get=%s", dispatchSources->label);
- }
-
- if (pluginJ) {
- DispatchLoadPlugin(controlConfig, sourcesJ, pluginJ);
- }
-
- dispatchSources->actions = DispatchLoadActions(controlConfig, actionsJ);
- if (!dispatchSources->actions) {
- AFB_ERROR("DISPATCH-LOAD-CONFIG:ONLOAD Error when parsing actions %s", dispatchSources->label);
- return NULL;
- }
- return dispatchSources;
-}
-
-static DispatchConfigT *DispatchLoadConfig(const char* filepath) {
- json_object *controlConfigJ, *ignoreJ;
- int err;
-
- // Load JSON file
- controlConfigJ = json_object_from_file(filepath);
- if (!controlConfigJ) {
- AFB_ERROR("DISPATCH-LOAD-CONFIG:JsonLoad invalid JSON %s ", filepath);
- return NULL;
- }
-
- AFB_INFO("DISPATCH-LOAD-CONFIG: loading config filepath=%s", filepath);
-
- json_object *metadataJ = NULL, *sourcesJ = NULL, *signalsJ = NULL;
- err = wrap_json_unpack(controlConfigJ, "{s?s,s?o,s?o,s?o !}", "$schema", &ignoreJ, "metadata", &metadataJ, "sources", &sourcesJ, "signals", &signalsJ);
- if (err) {
- AFB_ERROR("DISPATCH-LOAD-CONFIG Missing something metadata|[sources]|[signals] in %s", json_object_get_string(controlConfigJ));
- return NULL;
- }
-
- DispatchConfigT *controlConfig = calloc(1, sizeof (DispatchConfigT));
- if (metadataJ) {
- const char*ctlname=NULL;
- err = wrap_json_unpack(metadataJ, "{ss,s?s,s?s,ss !}", "label", &controlConfig->label, "version", &controlConfig->version, "name", &ctlname, "info", &controlConfig->info);
- if (err) {
- AFB_ERROR("DISPATCH-LOAD-CONFIG:METADATA Missing something label|version|[label] in %s", json_object_get_string(metadataJ));
- return NULL;
- }
-
- // if ctlname is provided change process name now
- if (ctlname) {
- err= prctl(PR_SET_NAME, ctlname,NULL,NULL,NULL);
- if (err) AFB_WARNING("Fail to set Process Name to:%s",ctlname);
- }
- }
-
- if (sourcesJ) {
- DispatchHandleT *dispatchHandle;
-
- if (json_object_get_type(sourcesJ) != json_type_array) {
- controlConfig->sources = (DispatchHandleT**) calloc(2, sizeof (void*));
- dispatchHandle = DispatchLoadSource(controlConfig, sourcesJ);
- controlConfig->sources[0] = dispatchHandle;
- } else {
- int length = json_object_array_length(sourcesJ);
- controlConfig->sources = (DispatchHandleT**) calloc(length + 1, sizeof (void*));
-
- for (int jdx = 0; jdx < length; jdx++) {
- json_object *sourcesJ = json_object_array_get_idx(sourcesJ, jdx);
- dispatchHandle = DispatchLoadSource(controlConfig, sourcesJ);
- controlConfig->sources[jdx] = dispatchHandle;
- }
- }
- }
-
- if (signalsJ) {
- DispatchHandleT* dispatchHandle;
-
- if (json_object_get_type(signalsJ) != json_type_array) {
- controlConfig->signals = (DispatchHandleT**) calloc(2, sizeof (void*));
- dispatchHandle = DispatchLoadSignal(controlConfig, signalsJ);
- controlConfig->signals[0] = dispatchHandle;
- } else {
- int length = json_object_array_length(signalsJ);
- controlConfig->signals = (DispatchHandleT**) calloc(length + 1, sizeof (void*));
-
- for (int jdx = 0; jdx < length; jdx++) {
- json_object *controlJ = json_object_array_get_idx(signalsJ, jdx);
- dispatchHandle = DispatchLoadSignal(controlConfig, controlJ);
- controlConfig->signals[jdx] = dispatchHandle;
- }
- }
- }
-/*
- if (eventsJ) {
- DispatchHandleT *dispatchHandle;
-
- if (json_object_get_type(eventsJ) != json_type_array) {
- controlConfig->events = (DispatchHandleT**) calloc(2, sizeof (void*));
- dispatchHandle = DispatchLoadSignal(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 = DispatchLoadSignal(controlConfig, eventJ);
- controlConfig->events[jdx] = dispatchHandle;
- }
- }
- }
-*/
- return controlConfig;
-}
-
-
-// Load default config file at init
-
-int DispatchInit() {
- int index, luaLoaded = 0;
- char controlFile [CONTROL_MAXPATH_LEN];
- // Compile some default directories to browse
- char defaultConfPath[CONTROL_MAXPATH_LEN];
- strncpy(defaultConfPath, GetBindingDirPath(), sizeof(GetBindingDirPath()));
- strncat(defaultConfPath, "/etc:", sizeof(defaultConfPath) - strlen(defaultConfPath) - 1);
- strncat(defaultConfPath, GetBindingDirPath(), sizeof(defaultConfPath) - strlen(defaultConfPath) - 1);
- strncat(defaultConfPath, "/data", sizeof(defaultConfPath) - strlen(defaultConfPath) - 1);
-
- const char *dirList = getenv("CONTROL_CONFIG_PATH");
- if (!dirList) dirList = defaultConfPath;
-
- strncpy(controlFile, CONTROL_CONFIG_PRE "-", CONTROL_MAXPATH_LEN);
- strncat(controlFile, GetBinderName(), CONTROL_MAXPATH_LEN-strlen(controlFile)-1);
-
- // search for default dispatch config file
- json_object* responseJ = ScanForConfig(dirList, 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;
- int 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));
- return -1;
- }
-
- if (index == 0) {
- if (strcasestr(filename, controlFile)) {
- char filepath[CONTROL_MAXPATH_LEN];
- strncpy(filepath, fullpath, sizeof (filepath));
- strncat(filepath, "/", sizeof (filepath)-strlen(filepath)-1);
- strncat(filepath, filename, sizeof (filepath)-strlen(filepath)-1);
- configHandle = DispatchLoadConfig(filepath);
- if (!configHandle) {
- AFB_ERROR("DISPATCH-INIT:ERROR Fail loading [%s]", filepath);
- return -1;
- }
- luaLoaded = 1;
- break;
- }
- } else {
- AFB_WARNING("DISPATCH-INIT:WARNING Secondary Signal Config Ignored %s/%s", fullpath, filename);
- }
- }
-
- // no dispatch config found remove control API from binder
- if (!luaLoaded) {
- AFB_WARNING("DISPATCH-INIT:WARNING (setenv CONTROL_CONFIG_PATH) No Config '%s-*.json' in '%s'", controlFile, dirList);
- }
-
- AFB_NOTICE("DISPATCH-INIT:SUCCES: Signal Dispatch Init");
- return 0;
-}
diff --git a/signal-composer-binding/ctl-lua.c b/signal-composer-binding/ctl-lua.c
deleted file mode 100644
index 2773696..0000000
--- a/signal-composer-binding/ctl-lua.c
+++ /dev/null
@@ -1,1057 +0,0 @@
-/*
- * Copyright (C) 2016 "IoT.bzh"
- * Author Fulup Ar Foll <fulup@iot.bzh>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ref:
- * (manual) https://www.lua.org/manual/5.3/manual.html
- * (lua->C) http://www.troubleshooters.com/codecorn/lua/lua_c_calls_lua.htm#_Anatomy_of_a_Lua_Call
- * (lua/C Var) http://acamara.es/blog/2012/08/passing-variables-from-lua-5-2-to-c-and-vice-versa/
- * (Lua/C Lib)https://john.nachtimwald.com/2014/07/12/wrapping-a-c-library-in-lua/
- * (Lua/C Table) https://gist.github.com/SONIC3D/10388137
- * (Lua/C Nested table) https://stackoverflow.com/questions/45699144/lua-nested-table-from-lua-to-c
- * (Lua/C Wrapper) https://stackoverflow.com/questions/45699950/lua-passing-handle-to-function-created-with-newlib
- *
- */
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <string.h>
-#include <filescan-utils.h>
-#include <wrap-json.h>
-
-#include "ctl-lua.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
-
-#define CTX_MAGIC 123456789
-#define CTX_TOKEN "AFB_ctx"
-
-static afb_req NULL_AFBREQ = {};
-
-static lua_State* luaState;
-
-typedef struct {
- char *name;
- int count;
- afb_event event;
-} LuaAfbEvent;
-static LuaAfbEvent *luaDefaultEvt;
-
-typedef struct {
- int ctxMagic;
- afb_req request;
- void *handle;
- char *info;
-} LuaAfbContextT;
-
-typedef struct {
- const char *callback;
- json_object *context;
- void *handle;
-} LuaCallServiceT;
-
-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
- * handle while waiting for someone smarter than me to find a better solution
- * 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);
- 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");
- return NULL;
- }
- return afbContext;
-}
-
-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");
- 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);
-}
-
-// Push a json structure on the stack as a LUA table
-static int LuaPushArgument (json_object *argsJ) {
-
- //AFB_NOTICE("LuaPushArgument argsJ=%s", json_object_get_string(argsJ));
-
- json_type jtype= json_object_get_type(argsJ);
- switch (jtype) {
- case json_type_object: {
- lua_newtable (luaState);
- json_object_object_foreach (argsJ, key, val) {
- int done = LuaPushArgument (val);
- if (done) {
- lua_setfield(luaState,-2, key);
- }
- }
- break;
- }
- case json_type_array: {
- int length= json_object_array_length(argsJ);
- lua_newtable (luaState);
- for (int idx=0; idx < length; idx ++) {
- json_object *val=json_object_array_get_idx(argsJ, idx);
- LuaPushArgument (val);
- lua_seti (luaState,-2, idx);
- }
- break;
- }
- case json_type_int:
- lua_pushinteger(luaState, json_object_get_int(argsJ));
- break;
- case json_type_string:
- lua_pushstring(luaState, json_object_get_string(argsJ));
- break;
- case json_type_boolean:
- lua_pushboolean(luaState, json_object_get_boolean(argsJ));
- break;
- case json_type_double:
- lua_pushnumber(luaState, json_object_get_double(argsJ));
- break;
- case json_type_null:
- AFB_WARNING("LuaPushArgument: NULL object type %s", json_object_get_string(argsJ));
- return 0;
- break;
-
- default:
- AFB_ERROR("LuaPushArgument: unsupported Json object type %s", json_object_get_string(argsJ));
- return 0;
- }
- return 1;
-}
-
-static json_object *LuaPopOneArg (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) {
- #define LUA_KEY_INDEX -2
- #define LUA_VALUE_INDEX -1
-
- int idx;
- int tableType;
- json_object *tableJ= NULL;
-
- lua_pushnil(luaState); // 1st key
- if (index < 0) index--;
- for (idx=1; lua_next(luaState, index) != 0; idx++) {
-
- // uses 'key' (at index -2) and 'value' (at index -1)
- if (lua_type(luaState,LUA_KEY_INDEX) == LUA_TSTRING) {
-
- if (!tableJ) {
- tableJ= json_object_new_object();
- tableType=LUA_TSTRING;
- } else if (tableType != LUA_TSTRING){
- AFB_ERROR("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_object_add(tableJ, key, argJ);
-
- } else {
- if (!tableJ) {
- tableJ= json_object_new_array();
- tableType=LUA_TNUMBER;
- } else if(tableType != LUA_TNUMBER) {
- AFB_ERROR("MIX Lua Table with key numeric/string not supported");
- return NULL;
- }
-
- json_object *argJ= LuaPopOneArg(luaState, LUA_VALUE_INDEX);
- json_object_array_add(tableJ, argJ);
- }
-
-
- lua_pop(luaState, 1); // removes 'value'; keeps 'key' for next iteration
- }
-
- // Query is empty free empty json object
- if (idx == 1) {
- json_object_put(tableJ);
- return NULL;
- }
- return tableJ;
-}
-
-static json_object *LuaPopOneArg (lua_State* luaState, int idx) {
- json_object *value=NULL;
-
- int luaType = lua_type(luaState, idx);
- switch(luaType) {
- case LUA_TNUMBER: {
- lua_Number number= lua_tonumber(luaState, idx);;
- int nombre = (int)number; // evil trick to determine wether n fits in an integer. (stolen from ltcl.c)
- if (number == nombre) {
- value= json_object_new_int((int)number);
- } else {
- value= json_object_new_double(number);
- }
- break;
- }
- case LUA_TBOOLEAN:
- value= json_object_new_boolean(lua_toboolean(luaState, idx));
- break;
- case LUA_TSTRING:
- value= json_object_new_string(lua_tostring(luaState, idx));
- break;
- case LUA_TTABLE:
- value= LuaTableToJson(luaState, idx);
- break;
- case LUA_TNIL:
- value=json_object_new_string("nil") ;
- break;
- case LUA_TUSERDATA:
- value=json_object_new_int64((int64_t)lua_touserdata(luaState, idx)); // store userdata as int !!!
- break;
-
- default:
- AFB_NOTICE ("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) {
- json_object *responseJ;
-
- int stop = lua_gettop(luaState);
- if(stop-start <0) goto OnErrorExit;
-
- // start at 2 because we are using a function array lib
- if (start == stop) {
- responseJ=LuaPopOneArg (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);
- if (!argJ) goto OnErrorExit;
- json_object_array_add(responseJ, argJ);
- }
- }
-
- return responseJ;
-
- OnErrorExit:
- return NULL;
-}
-
-
-static int LuaFormatMessage(lua_State* luaState, LuaAfbMessageT action) {
- char *message;
-
- json_object *responseJ= LuaPopArgs(luaState, LUA_FIST_ARG);
-
- if (!responseJ) {
- luaL_error(luaState,"LuaFormatMessage empty message");
- goto OnErrorExit;
- }
-
- // if we have only on argument just return the value.
- if (json_object_get_type(responseJ)!=json_type_array || json_object_array_length(responseJ) <2) {
- message= (char*)json_object_get_string(responseJ);
- goto PrintMessage;
- }
-
- // extract format and push all other parameter on the stack
- message = alloca (LUA_MSG_MAX_LENGTH);
- const char *format = json_object_get_string(json_object_array_get_idx(responseJ, 0));
-
- int arrayIdx=1;
- int targetIdx=0;
-
- for (int idx=0; format[idx] !='\0'; idx++) {
-
- if (format[idx]=='%' && format[idx] !='\0') {
- json_object *slotJ= json_object_array_get_idx(responseJ, arrayIdx);
- //if (slotJ) AFB_NOTICE("**** idx=%d slotJ=%s", arrayIdx, json_object_get_string(slotJ));
-
-
- switch (format[++idx]) {
- case 'd':
- if (slotJ) targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"%d", json_object_get_int(slotJ));
- else targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"nil");
- arrayIdx++;
- break;
- case 'f':
- if (slotJ) targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"%f", json_object_get_double(slotJ));
- else targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"nil");
- arrayIdx++;
- break;
-
- case'%':
- message[targetIdx]='%';
- targetIdx++;
- break;
-
- case 's':
- default:
- if (slotJ) targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"%s", json_object_get_string(slotJ));
- else targetIdx += snprintf (&message[targetIdx], LUA_MSG_MAX_LENGTH-targetIdx,"nil");
- arrayIdx++;
- }
-
- } else {
- 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';
-
-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);
- }
- 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);
- return err; // no value return
-}
-
-static int LuaPrintWarning(lua_State* luaState) {
- int err=LuaFormatMessage (luaState, AFB_MSG_WARNING);
- return err;
-}
-
-static int LuaPrintNotice(lua_State* luaState) {
- int err=LuaFormatMessage (luaState, AFB_MSG_NOTICE);
- return err;
-}
-
-static int LuaPrintDebug(lua_State* luaState) {
- int err=LuaFormatMessage (luaState, AFB_MSG_DEBUG);
- return err;
-}
-
-static int LuaAfbSuccess(lua_State* luaState) {
- LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG);
- if (!afbContext) goto OnErrorExit;
-
- // ignore context argument
- json_object *responseJ= LuaPopArgs(luaState, LUA_FIST_ARG+1);
- if (responseJ == JSON_ERROR) return 1;
-
- afb_req_success(afbContext->request, responseJ, NULL);
-
- LuaCtxFree(afbContext);
- return 0;
-
- OnErrorExit:
- lua_error(luaState);
- return 1;
-}
-
-static int LuaAfbFail(lua_State* luaState) {
- LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG);
- if (!afbContext) goto OnErrorExit;
-
- json_object *responseJ= LuaPopArgs(luaState, LUA_FIST_ARG+1);
- if (responseJ == JSON_ERROR) return 1;
-
- afb_req_fail(afbContext->request, afbContext->info, json_object_get_string(responseJ));
-
- LuaCtxFree(afbContext);
- return 0;
-
- OnErrorExit:
- lua_error(luaState);
- return 1;
-}
-
-static void LuaAfbServiceCB(void *handle, int iserror, struct json_object *responseJ) {
- LuaCallServiceT *contextCB= (LuaCallServiceT*)handle;
- int count=1;
-
- lua_getglobal(luaState, contextCB->callback);
-
- // push error status & response
- lua_pushboolean(luaState, iserror);
- count+= LuaPushArgument(responseJ);
- count+= LuaPushArgument(contextCB->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) );
- }
-
- free (contextCB);
-}
-
-
-static int LuaAfbService(lua_State* luaState) {
- int count = lua_gettop(luaState);
-
- // note: argument start at 2 because of AFB: table
- if (count <5 || !lua_isstring(luaState, 2) || !lua_isstring(luaState, 3) || !lua_istable(luaState, 4) || !lua_isstring(luaState, 5)) {
- lua_pushliteral (luaState, "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);
- if (queryJ == JSON_ERROR) return 1;
-
- LuaCallServiceT *contextCB = calloc (1, sizeof(LuaCallServiceT));
- contextCB->callback= lua_tostring(luaState, 5);
- contextCB->context = LuaPopArgs(luaState, 6);
-
- afb_service_call(api, verb, queryJ, LuaAfbServiceCB, contextCB);
-
- return 0; // no value return
-
- OnErrorExit:
- lua_error(luaState);
- return 1;
-}
-
-static int LuaAfbServiceSync(lua_State* luaState) {
- int count = lua_gettop(luaState);
- json_object *responseJ;
-
- // note: argument start at 2 because of AFB: table
- if (count <3 || !lua_isstring(luaState, 2) || !lua_isstring(luaState, 3) || !lua_istable(luaState, 4)) {
- 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);
-
- int iserror=afb_service_call_sync (api, verb, queryJ, &responseJ);
-
- // push error status & response
- count=1; lua_pushboolean(luaState, iserror);
- count+= LuaPushArgument(responseJ);
-
- return count; // return count values
-
- OnErrorExit:
- lua_error(luaState);
- return 1;
-}
-
-static int LuaAfbEventPush(lua_State* luaState) {
- LuaAfbEvent *afbevt;
- int index;
-
- // 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 (!afb_event_is_valid(afbevt->event)) {
- lua_pushliteral (luaState, "LuaAfbMakePush-Fail invalid event");
- goto OnErrorExit;
- }
-
- json_object *ctlEventJ= LuaTableToJson(luaState, index);
- if (!ctlEventJ) {
- lua_pushliteral (luaState, "LuaAfbEventPush-Syntax is AFB:signal ([evtHandle], {lua table})");
- goto OnErrorExit;
- }
-
- int done = afb_event_push(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);
- goto OnErrorExit;
- }
- afbevt->count++;
- return 0;
-
- OnErrorExit:
- lua_error(luaState);
- return 1;
-}
-
-static int LuaAfbEventSubscribe(lua_State* luaState) {
- LuaAfbEvent *afbevt;
-
- LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG);
- if (!afbContext) {
- 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 (!afb_event_is_valid(afbevt->event)) {
- lua_pushliteral (luaState, "LuaAfbMakePush-Fail invalid event handle");
- goto OnErrorExit;
- }
-
- int err = afb_req_subscribe(afbContext->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);
- goto OnErrorExit;
- }
- afbevt->count++;
- return 0;
-
- OnErrorExit:
- lua_error(luaState);
- return 1;
-}
-
-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)) {
- 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));
-
- // create a new binder event
- afbevt->event = afb_daemon_make_event(afbevt->name);
- if (!afb_event_is_valid(afbevt->event)) {
- lua_pushliteral (luaState, "LuaAfbEventMake-Fail to Create Binder event");
- goto OnErrorExit;
- }
-
- // push event handler as a LUA opaque handle
- lua_pushlightuserdata(luaState, afbevt);
- return 1;
-
- OnErrorExit:
- lua_error(luaState);
- return 1;
-}
-
-// Function call from LUA when lua2c plugin L2C is used
-int Lua2cWrapper(lua_State* luaState, char *funcname, Lua2cFunctionT callback, void *context) {
-
- json_object *argsJ= LuaPopArgs(luaState, LUA_FIST_ARG+1);
- int response = (*callback) (funcname, argsJ, context);
-
- // push response to LUA
- lua_pushinteger(luaState, response);
- return 1;
-}
-
-// Generated some fake event based on watchdog/counter
-int LuaCallFunc (DispatchSourceT source, DispatchActionT *action, json_object *queryJ) {
-
- int err, count;
-
- json_object* argsJ = action->argsJ;
- const char* func = action->call;
-
- // load function (should exist in CONTROL_PATH_LUA
- lua_getglobal(luaState, func);
-
- // push source on the stack
- count=1;
- lua_pushinteger(luaState, source);
-
- // push argsJ on the stack
- if (!argsJ) {
- lua_pushnil(luaState);
- count++;
- } else {
- count+= LuaPushArgument (argsJ);
- }
-
- // push queryJ on the stack
- if (!queryJ) {
- lua_pushnil(luaState);
- count++;
- } else {
- count+= LuaPushArgument (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));
- return -1;
- }
-
- // return LUA script value
- int rc= (int)lua_tointeger(luaState, -1);
- return rc;
-}
-
-// Execute LUA code from received API request
-static void LuaDoAction (LuaDoActionT action, afb_req request) {
-
- int err, count=0;
-
- json_object* queryJ = afb_req_json(request);
-
- switch (action) {
-
- case LUA_DOSTRING: {
- 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) );
- goto OnErrorExit;
- }
- // Push AFB client context on the stack
- LuaAfbContextT *afbContext= LuaCtxPush(luaState, request,NULL,script);
- if (!afbContext) goto OnErrorExit;
-
- break;
- }
-
- case LUA_DOCALL: {
- const char *func;
- json_object *argsJ=NULL;
-
- 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));
- goto OnErrorExit;
- }
-
- // load function (should exist in CONTROL_PATH_LUA
- lua_getglobal(luaState, func);
-
- // Push AFB client context on the stack
- LuaAfbContextT *afbContext= LuaCtxPush(luaState, request, NULL, func);
- if (!afbContext) goto OnErrorExit;
-
- // push query on the stack
- if (!argsJ) {
- lua_pushnil(luaState);
- count++;
- } else {
- count+= LuaPushArgument (argsJ);
- }
-
- break;
- }
-
- case LUA_DOSCRIPT: { // Fulup need to fix argument passing
- char *filename; char*fullpath;
- char luaScriptPath[CONTROL_MAXPATH_LEN];
- int index;
-
- // scan luascript search path once
- static json_object *luaScriptPathJ =NULL;
-
- // extract value from query
- const char *target=NULL,*func=NULL;
- json_object *argsJ=NULL;
- err= wrap_json_unpack (queryJ, "{s:s,s?s,s?s,s?o !}","target", &target,"path",&luaScriptPathJ,"function",&func,"args",&argsJ);
- if (err) {
- AFB_ERROR ("LUA-DOSCRIPT-SYNTAX:missing target|[path]|[function]|[args] query=%s", json_object_get_string(queryJ));
- goto OnErrorExit;
- }
-
- // search for filename=script in CONTROL_LUA_PATH
- if (!luaScriptPathJ) {
- strncpy(luaScriptPath, CONTROL_DOSCRIPT_PRE, sizeof(luaScriptPath));
- strncat(luaScriptPath,"-", sizeof(luaScriptPath)-strlen(luaScriptPath)-1);
- strncat(luaScriptPath,target, sizeof(luaScriptPath)-strlen(luaScriptPath)-1);
- luaScriptPathJ= ScanForConfig(strncat(GetBindingDirPath(), "/etc", sizeof(GetBindingDirPath()) - strlen(GetBindingDirPath()) - 1), CTL_SCAN_RECURSIVE,luaScriptPath,".lua");
- }
- for (index=0; index < json_object_array_length(luaScriptPathJ); index++) {
- json_object *entryJ=json_object_array_get_idx(luaScriptPathJ, index);
-
- err= wrap_json_unpack (entryJ, "{s:s, s:s !}", "fullpath", &fullpath,"filename", &filename);
- if (err) {
- AFB_ERROR ("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);
- else {
- strncpy (luaScriptPath, fullpath, sizeof(luaScriptPath));
- strncat (luaScriptPath, "/", sizeof(luaScriptPath)-strlen(luaScriptPath)-1);
- strncat (luaScriptPath, filename, sizeof(luaScriptPath)-strlen(luaScriptPath)-1);
- }
- }
-
- 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));
- 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);
- goto OnErrorExit;
- }
-
- // if no func name given try to deduct from filename
- if (!func && (func=(char*)GetMidleName(filename))!=NULL) {
- strncpy(luaScriptPath,"_", sizeof(luaScriptPath));
- strncat(luaScriptPath,func, sizeof(luaScriptPath)-strlen(luaScriptPath)-1);
- func=luaScriptPath;
- }
- if (!func) {
- AFB_ERROR ("LUA-DOSCRIPT:FAIL to deduct funcname from %s", filename);
- goto OnErrorExit;
- }
-
- // load function (should exist in CONTROL_PATH_LUA
- lua_getglobal(luaState, func);
-
- // Push AFB client context on the stack
- LuaAfbContextT *afbContext= LuaCtxPush(luaState, request, NULL, func);
- if (!afbContext) goto OnErrorExit;
-
- // push function arguments
- if (!argsJ) {
- lua_pushnil(luaState);
- count++;
- } else {
- count+= LuaPushArgument(argsJ);
- }
-
- break;
- }
-
- default:
- AFB_ERROR ("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));
- goto OnErrorExit;
- }
- return;
-
- OnErrorExit:
- afb_req_fail(request,"LUA:ERROR", lua_tostring(luaState,-1));
- return;
-}
-
-void ctlapi_execlua (afb_req request) {
- LuaDoAction (LUA_DOSTRING, request);
-}
-
-void ctlapi_request (afb_req request) {
- LuaDoAction (LUA_DOCALL, request);
-}
-
-void ctlapi_debuglua (afb_req request) {
- LuaDoAction (LUA_DOSCRIPT, request);
-}
-
-static int LuaTimerClear (lua_State* luaState) {
-
- // Get Timer Handle
- LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG);
- if (!afbContext) return -1;
-
- // retrieve useful information opaque handle
- TimerHandleT *timerHandle = (TimerHandleT*)afbContext->handle;
-
- AFB_NOTICE ("LuaTimerClear timer=%s", timerHandle->label);
- TimerEvtStop(timerHandle);
-
- return 0; //happy end
-}
-static int LuaTimerGet (lua_State* luaState) {
-
- // Get Timer Handle
- LuaAfbContextT *afbContext= LuaCtxCheck(luaState, LUA_FIST_ARG);
- if (!afbContext) return 0;
-
- // retrieve useful information opaque handle
- TimerHandleT *timerHandle = (TimerHandleT*)afbContext->handle;
-
- // 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));
- json_object_object_add(responseJ,"delay", json_object_new_int(timerHandle->delay));
- json_object_object_add(responseJ,"count", json_object_new_int(timerHandle->count));
-
- // return JSON object as Lua table
- int count=LuaPushArgument(responseJ);
-
- // free json object
- json_object_put(responseJ);
-
- return count; // return argument
-}
-
-// Timer Callback
-
-// Set timer
-static int LuaTimerSetCB (void *handle) {
- LuaCallServiceT *contextCB =(LuaCallServiceT*) handle;
- TimerHandleT *timerHandle = (TimerHandleT*) contextCB->handle;
- int count;
-
- // push timer handle and user context on Lua stack
- lua_getglobal(luaState, contextCB->callback);
-
- // Push timer handle
- LuaAfbContextT *afbContext= LuaCtxPush(luaState, NULL_AFBREQ, contextCB->handle, timerHandle->label);
- if (!afbContext) return 1;
- count=1;
-
- // Push user Context
- count+= LuaPushArgument(contextCB->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));
- return 1;
- }
-
- // get return parameter
- if (!lua_isboolean(luaState, -1)) {
- return (lua_toboolean(luaState, -1));
- }
-
- // timer last run free context resource
- if (timerHandle->count == 1) {
- LuaCtxFree(afbContext);
- }
- return 0; // By default we are happy
-}
-
-static int LuaTimerSet(lua_State* luaState) {
- const char *label=NULL, *info=NULL;
- int delay=0, count=0;
-
- 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);
-
- if (lua_gettop(luaState) != LUA_FIST_ARG+2 || !timerJ || !callback || !contextJ) {
- lua_pushliteral(luaState, "LuaTimerSet-Syntax timerset (timerT, 'callback', contextT)");
- goto OnErrorExit;
- }
-
- int err = wrap_json_unpack(timerJ, "{ss, s?s si, si !}", "label", &label, "info", &info, "delay", &delay, "count", &count);
- if (err) {
- lua_pushliteral(luaState, "LuaTimerSet-Syntax timerT={label:xxx delay:ms, count:xx}");
- goto OnErrorExit;
- }
-
- // everything look fine create timer structure
- TimerHandleT *timerHandle = malloc (sizeof (TimerHandleT));
- 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;
-
- // fire timer
- TimerEvtStart (timerHandle, LuaTimerSetCB, contextCB);
-
- return 0; // Happy No Return Function
-
-OnErrorExit:
- lua_error(luaState);
- return 1; // return error code
-}
-
-// Register a new L2c list of LUA user plugin commands
-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[] = {
- {"timerclear", LuaTimerClear},
- {"timerget" , LuaTimerGet},
- {"timerset" , LuaTimerSet},
- {"notice" , LuaPrintNotice},
- {"info" , LuaPrintInfo},
- {"warning" , LuaPrintWarning},
- {"debug" , LuaPrintDebug},
- {"error" , LuaPrintError},
- {"servsync" , LuaAfbServiceSync},
- {"service" , LuaAfbService},
- {"success" , LuaAfbSuccess},
- {"fail" , LuaAfbFail},
- {"subscribe" , LuaAfbEventSubscribe},
- {"evtmake" , LuaAfbEventMake},
- {"evtpush" , LuaAfbEventPush},
-
- {NULL, NULL} /* sentinel */
-};
-
-// Create Binding Event at Init
-int LuaLibInit () {
- int err, index;
-
- // search for default policy config file
- char fullprefix[CONTROL_MAXPATH_LEN];
- strncpy (fullprefix, CONTROL_CONFIG_PRE, sizeof(fullprefix));
- strncat (fullprefix, GetBinderName(), sizeof(fullprefix)-strlen(fullprefix)-1);
- strncat (fullprefix, "-", sizeof(fullprefix)-strlen(fullprefix)-1);
-
- const char *dirList= getenv("CONTROL_LUA_PATH");
- if (!dirList) dirList= strncat(GetBindingDirPath(), "/etc", sizeof(GetBindingDirPath()) - strlen(GetBindingDirPath()) - 1);
-
- json_object *luaScriptPathJ = ScanForConfig(dirList , CTL_SCAN_RECURSIVE, fullprefix, "lua");
-
- // open a new LUA interpretor
- luaState = luaL_newstate();
- if (!luaState) {
- AFB_ERROR ("LUA_INIT: Fail to open lua interpretor");
- goto OnErrorExit;
- }
-
- // load auxiliary libraries
- luaL_openlibs(luaState);
-
- // redirect print to AFB_NOTICE
- luaL_newlib(luaState, afbFunction);
- lua_setglobal(luaState, "AFB");
-
- // create default lua event to send test pause/resume
- luaDefaultEvt=calloc(1,sizeof(LuaAfbEvent));
- luaDefaultEvt->name=CONTROL_LUA_EVENT;
- luaDefaultEvt->event = afb_daemon_make_event(CONTROL_LUA_EVENT);
- if (!afb_event_is_valid(luaDefaultEvt->event)) {
- AFB_ERROR ("POLCTL_INIT: Cannot register lua-events=%s ", CONTROL_LUA_EVENT);
- goto OnErrorExit;
- }
-
- // load+exec any file found in LUA search path
- for (index=0; index < json_object_array_length(luaScriptPathJ); index++) {
- json_object *entryJ=json_object_array_get_idx(luaScriptPathJ, index);
-
- 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));
- goto OnErrorExit;
- }
-
- char filepath[CONTROL_MAXPATH_LEN];
- strncpy(filepath, fullpath, sizeof(filepath));
- strncat(filepath, "/", sizeof(filepath)-strlen(filepath)-1);
- strncat(filepath, filename, sizeof(filepath)-strlen(filepath)-1);
- 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));
- 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));
- goto OnErrorExit;
- }
- }
-
- // 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_DEBUG ("Audio control-LUA Init Done");
- return 0;
-
- OnErrorExit:
- return 1;
-}
diff --git a/signal-composer-binding/ctl-lua.h b/signal-composer-binding/ctl-lua.h
deleted file mode 100644
index c5f472d..0000000
--- a/signal-composer-binding/ctl-lua.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifdef SUSE_LUA_INCDIR
- #include <lua5.3/lua.h>
- #include <lua5.3/lauxlib.h>
- #include <lua5.3/lualib.h>
-#else
- #include <lua.h>
- #include <lauxlib.h>
- #include <lualib.h>
-#endif
-
-#include <json-c/json.h>
-
-#include "signal-composer-binding.hpp"
-
-typedef enum {
- LUA_DOCALL,
- LUA_DOSTRING,
- LUA_DOSCRIPT,
-} LuaDoActionT;
-
-typedef int (*Lua2cFunctionT)(char *funcname, json_object *argsJ, void*context);
-
-typedef int (*Lua2cWrapperT) (lua_State* luaState, char *funcname, Lua2cFunctionT callback);
-
-int LuaLibInit ();
-void LuaL2cNewLib(const char *label, luaL_Reg *l2cFunc, int count);
-int Lua2cWrapper(lua_State* luaState, char *funcname, Lua2cFunctionT callback, void *context);
-int LuaCallFunc (DispatchSourceT source, DispatchActionT *action, json_object *queryJ) ;
diff --git a/signal-composer-binding/observer.hpp b/signal-composer-binding/observer.hpp
new file mode 100644
index 0000000..e4129c6
--- /dev/null
+++ b/signal-composer-binding/observer.hpp
@@ -0,0 +1,30 @@
+#include <vector>
+
+class Observer
+{
+public:
+ virtual void update(double timestamp, double value) = 0;
+};
+
+class Subject
+{
+ double timestamp_;
+ double value_;
+ std::vector<Observer*> m_views;
+public:
+ void attach(Observer *obs)
+ {
+ m_views.push_back(obs);
+ }
+ void set_val(double timestamp, double value)
+ {
+ timestamp_ = timestamp;
+ value_ = value;
+ notify();
+ }
+ void notify()
+ {
+ for (int i = 0; i < m_views.size(); ++i)
+ m_views[i]->update(timestamp_, value_);
+ }
+};
diff --git a/signal-composer-binding/signal-composer-apidef.h b/signal-composer-binding/signal-composer-apidef.h
index a652de5..b480430 100644
--- a/signal-composer-binding/signal-composer-apidef.h
+++ b/signal-composer-binding/signal-composer-apidef.h
@@ -1,19 +1,19 @@
-static const char _afb_description_v2_signals_composer[] =
+static const char _afb_description_v2_signal_composer[] =
"{\"openapi\":\"3.0.0\",\"$schema\":\"http:iot.bzh/download/openapi/schem"
"a-3.0/default-schema.json\",\"info\":{\"description\":\"\",\"title\":\"s"
"ignals-composer-service\",\"version\":\"4.0\",\"x-binding-c-generator\":"
- "{\"api\":\"signals-composer\",\"version\":2,\"prefix\":\"\",\"postfix\":"
- "\"\",\"start\":null,\"onevent\":\"onEvent\",\"preinit\":\"loadConf\",\"i"
- "nit\":\"execConf\",\"scope\":\"\",\"private\":false}},\"servers\":[{\"ur"
- "l\":\"ws://{host}:{port}/api/monitor\",\"description\":\"Signals compose"
- "r API connected to low level AGL services\",\"variables\":{\"host\":{\"d"
- "efault\":\"localhost\"},\"port\":{\"default\":\"1234\"}},\"x-afb-events\""
- ":[{\"$ref\":\"#/components/schemas/afb-event\"}]}],\"components\":{\"sch"
- "emas\":{\"afb-reply\":{\"$ref\":\"#/components/schemas/afb-reply-v2\"},\""
- "afb-event\":{\"$ref\":\"#/components/schemas/afb-event-v2\"},\"afb-reply"
- "-v2\":{\"title\":\"Generic response.\",\"type\":\"object\",\"required\":"
- "[\"jtype\",\"request\"],\"properties\":{\"jtype\":{\"type\":\"string\",\""
+ "{\"api\":\"signal-composer\",\"version\":2,\"prefix\":\"\",\"postfix\":\""
+ "\",\"start\":null,\"onevent\":\"onEvent\",\"preinit\":\"loadConf\",\"ini"
+ "t\":\"execConf\",\"scope\":\"\",\"private\":false}},\"servers\":[{\"url\""
+ ":\"ws://{host}:{port}/api/monitor\",\"description\":\"Signals composer A"
+ "PI connected to low level AGL services\",\"variables\":{\"host\":{\"defa"
+ "ult\":\"localhost\"},\"port\":{\"default\":\"1234\"}},\"x-afb-events\":["
+ "{\"$ref\":\"#/components/schemas/afb-event\"}]}],\"components\":{\"schem"
+ "as\":{\"afb-reply\":{\"$ref\":\"#/components/schemas/afb-reply-v2\"},\"a"
+ "fb-event\":{\"$ref\":\"#/components/schemas/afb-event-v2\"},\"afb-reply-"
+ "v2\":{\"title\":\"Generic response.\",\"type\":\"object\",\"required\":["
+ "\"jtype\",\"request\"],\"properties\":{\"jtype\":{\"type\":\"string\",\""
"const\":\"afb-reply\"},\"request\":{\"type\":\"object\",\"required\":[\""
"status\"],\"properties\":{\"status\":{\"type\":\"string\"},\"info\":{\"t"
"ype\":\"string\"},\"token\":{\"type\":\"string\"},\"uuid\":{\"type\":\"s"
@@ -44,7 +44,7 @@ static const char _afb_description_v2_signals_composer[] =
void get(struct afb_req req);
void loadConf(struct afb_req req);
-static const struct afb_verb_v2 _afb_verbs_v2_signals_composer[] = {
+static const struct afb_verb_v2 _afb_verbs_v2_signal_composer[] = {
{
.verb = "subscribe",
.callback = subscribe,
@@ -83,10 +83,10 @@ static const struct afb_verb_v2 _afb_verbs_v2_signals_composer[] = {
};
const struct afb_binding_v2 afbBindingV2 = {
- .api = "signals-composer",
- .specification = _afb_description_v2_signals_composer,
+ .api = "signal-composer",
+ .specification = _afb_description_v2_signal_composer,
.info = "",
- .verbs = _afb_verbs_v2_signals_composer,
+ .verbs = _afb_verbs_v2_signal_composer,
.preinit = loadConf,
.init = execConf,
.onevent = onEvent,
diff --git a/signal-composer-binding/signal-composer-apidef.json b/signal-composer-binding/signal-composer-apidef.json
index 7085dc2..c9e898e 100644
--- a/signal-composer-binding/signal-composer-apidef.json
+++ b/signal-composer-binding/signal-composer-apidef.json
@@ -6,7 +6,7 @@
"title": "signals-composer-service",
"version": "4.0",
"x-binding-c-generator": {
- "api": "signals-composer",
+ "api": "signal-composer",
"version": 2,
"prefix": "",
"postfix": "",
diff --git a/signal-composer-binding/signal-composer-binding.cpp b/signal-composer-binding/signal-composer-binding.cpp
index 2ca1dec..90401f2 100644
--- a/signal-composer-binding/signal-composer-binding.cpp
+++ b/signal-composer-binding/signal-composer-binding.cpp
@@ -13,27 +13,27 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- */
+*/
-#include <ctl-config.h>
+#include <string.h>
+// afb-utilities
+#include <wrap-json.h>
+#include <filescan-utils.h>
+// controller
+#include <ctl-lua.h>
#include "signal-composer-binding.hpp"
#include "signal-composer-apidef.h"
-#include "wrap-json.h"
#include "signal-composer.hpp"
-SignalComposer SigComp;
-static CtlConfigT *ctlConfig=NULL;
-
/// @brief callback for receiving message from low binding. Treatment itself is made in SigComp class.
void onEvent(const char *event, json_object *object)
{
- SigComp.treatMessage(object);
}
/// @brief entry point for client subscription request. Treatment itself is made in SigComp class.
void subscribe(afb_req request)
{
- if(SigComp.subscribe(request))
+ if(true)
afb_req_success(request, NULL, NULL);
else
afb_req_fail(request, "error", NULL);
@@ -42,7 +42,7 @@ void subscribe(afb_req request)
/// @brief entry point for client un-subscription request. Treatment itself is made in SigComp class.
void unsubscribe(afb_req request)
{
- if(SigComp.unsubscribe(request))
+ if(true)
afb_req_success(request, NULL, NULL);
else
afb_req_fail(request, "error when unsubscribe", NULL);
@@ -55,7 +55,7 @@ void loadConf(afb_req request)
const char* confd;
wrap_json_unpack(args, "{s:s}", "path", &confd);
- int ret = SigComp.parseConfigAndSubscribe(confd);
+ int ret = 0;
if( ret == 0)
afb_req_success(request, NULL, NULL);
else
@@ -66,39 +66,49 @@ void loadConf(afb_req request)
void get(afb_req request)
{
json_object *jobj;
- if(SigComp.get(request, &jobj))
+ if(true)
{
afb_req_success(request, jobj, NULL);
- } else {
+ }
+ else
+ {
afb_req_fail(request, "error", NULL);
}
}
-/// @brief entry point for systemD timers. Treatment itself is made in SigComp class.
-/// @param[in] source: systemD timer, t: time of tick, data: interval (ms).
-int ticked(sd_event_source *source, uint64_t t, void* data)
-{
- SigComp.tick(source, t, data);
- return 0;
-}
-
int loadConf()
{
- int errcount=0;
+ int ret = 0;
+ const char* rootdir = strncat(GetBindingDirPath(), "/etc",
+ sizeof(GetBindingDirPath()) - strlen(GetBindingDirPath()) -1);
- ctlConfig = CtlConfigLoad();
+ bindingApp& bApp = bindingApp::instance();
+ bApp.loadConfig(rootdir);
#ifdef CONTROL_SUPPORT_LUA
- errcount += LuaLibInit();
+ ret += LuaConfigLoad();
#endif
- return errcount;
+ return ret;
}
int execConf()
{
- int err = CtlConfigExec();
+ bindingApp& bApp = bindingApp::instance();
+ int ret = CtlConfigExec(bApp.ctlConfig());
+ std::vector<std::shared_ptr<Signal>> allSignals = bApp.getAllSignals();
+ ssize_t sigCount = allSignals.size();
+
+ for(auto& sig: allSignals)
+ {
+ if( (ret = sig->recursionCheck()) )
+ {
+ AFB_ERROR("There is an infinite recursion loop in your signals definition. Root coming from signal: %s", sig->id().c_str());
+ return ret;
+ }
+ }
+
+ AFB_DEBUG("Signal Composer Control configuration Done.\n signals=%d", (int)sigCount);
- AFB_DEBUG ("Signal Composer Control configuration Done errcount=%d", errcount);
- return errcount;
+ return ret;
}
diff --git a/signal-composer-binding/signal-composer-binding.hpp b/signal-composer-binding/signal-composer-binding.hpp
index 7bf1df1..e73438b 100644
--- a/signal-composer-binding/signal-composer-binding.hpp
+++ b/signal-composer-binding/signal-composer-binding.hpp
@@ -1,19 +1,14 @@
#pragma once
#include <systemd/sd-event.h>
+#include <ctl-config.h>
-#ifdef __cplusplus
- #include <cstddef>
extern "C"
{
-#endif
#define AFB_BINDING_VERSION 2
#include <afb/afb-binding.h>
-#ifdef __cplusplus
-};
-#endif
+}
void onEvent(const char *event, struct json_object *object);
int loadConf();
int execConf();
-int ticked(sd_event_source *source, uint64_t t, void *data);
diff --git a/signal-composer-binding/signal-composer.cpp b/signal-composer-binding/signal-composer.cpp
index 73f2450..6f629e1 100644
--- a/signal-composer-binding/signal-composer.cpp
+++ b/signal-composer-binding/signal-composer.cpp
@@ -13,4 +13,245 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- */
+*/
+
+#include "signal-composer.hpp"
+
+CtlSectionT bindingApp::ctlSections_[] = {
+ [0]={.key="sources" ,.label = "sources", .info=nullptr,
+ .loadCB=loadSources,
+ .handle=nullptr},
+ [1]={.key="signals" , .label= "signals", .info=nullptr,
+ .loadCB=loadSignals,
+ .handle=nullptr},
+ [2]={.key=nullptr, .label=nullptr, .info=nullptr,
+ .loadCB=nullptr,
+ .handle=nullptr}
+};
+
+bindingApp::bindingApp()
+{}
+
+void bindingApp::loadConfig(const std::string& filepath)
+{
+ ctlConfig_ = CtlConfigLoad(filepath.c_str(), ctlSections_);
+}
+
+bindingApp& bindingApp::instance()
+{
+ static bindingApp bApp;
+ return bApp;
+}
+
+Source* bindingApp::getSource(const std::string& api)
+{
+ for(auto& source: sourcesList_)
+ {
+ if (source.api() == api)
+ {return &source;}
+ }
+ return nullptr;
+}
+
+CtlActionT* bindingApp::convert2Action(const std::string& name, json_object* action)
+{
+ json_object *functionArgsJ = nullptr;
+ const char* function;
+
+ if(action &&
+ wrap_json_unpack(action, "{ss,s?o !}", "function", &function, "args", &functionArgsJ))
+ {
+ std::string functionS = function;
+ json_object* action = nullptr;
+ ssize_t sep;
+ if(functionS.find("lua") != std::string::npos)
+ {
+ wrap_json_pack(&action, "{ss,s?s,s?o,s?s,s?s,s?s,s?o !}",
+ "label", name,
+ "lua", function,
+ "args", functionArgsJ);
+ }
+ else if( (sep = functionS.find_first_of("/")) != std::string::npos)
+ {
+ std::string api = functionS.substr(0, sep);
+ std::string verb = functionS.substr(sep);
+ wrap_json_pack(&action, "{ss,s?s,s?o,s?s,s?s,s?s,s?o !}",
+ "label", name,
+ "api", api,
+ "verb", verb,
+ "args", functionArgsJ);
+ }
+ else
+ {
+ wrap_json_pack(&action, "{ss,s?s,s?o,s?s,s?s,s?s,s?o !}",
+ "label", name,
+ "callback", function,
+ "args", functionArgsJ);
+ }
+ }
+ return ActionLoad(action);
+}
+
+int bindingApp::loadOneSource(json_object* sourceJ)
+{
+ json_object *initJ = nullptr, *getSignalJ = nullptr;
+ CtlActionT *initCtl, *getSignalCtl;
+ const char *api, *info;
+
+ int err = wrap_json_unpack(sourceJ, "{ss,s?s,s?o,s?o !}",
+ "api", &api,
+ "info", &info,
+ "init", &initJ,
+ "getSignal", &getSignalJ);
+ if (err)
+ {
+ AFB_ERROR("Missing something api|[info]|[init]|[getSignal] in %s", json_object_get_string(sourceJ));
+ return err;
+ }
+
+ initCtl = convert2Action("init", initJ);
+ getSignalCtl =convert2Action("getSignal", getSignalJ);
+
+ sourcesList_.push_back(Source(api, info, initCtl, getSignalCtl));
+
+ return err;
+}
+
+int bindingApp::loadSources(CtlSectionT* section, json_object *sourcesJ)
+{
+ int err = 0;
+ bindingApp& bApp = instance();
+ // add the signal composer itself as source
+ json_object *sigCompJ = nullptr;
+ wrap_json_pack(&sigCompJ, "{ss,ss,so,so !}",
+ "api", "signal-composer",
+ "info", "Api on behalf the virtual signals are sent",
+ "init", nullptr,
+ "getSignal", nullptr);
+
+ json_object_array_add(sourcesJ, sigCompJ);
+
+ if (json_object_get_type(sourcesJ) == json_type_array)
+ {
+ int count = json_object_array_length(sourcesJ);
+
+ for (int idx = 0; idx < count; idx++)
+ {
+ json_object *sourceJ = json_object_array_get_idx(sourcesJ, idx);
+ err = bApp.loadOneSource(sourceJ);
+ if (err) return err;
+ }
+ }
+ else
+ {
+ if ((err = bApp.loadOneSource(sourcesJ))) return err;
+ if ((err = bApp.loadOneSource(sigCompJ))) return err;
+ }
+
+ return err;
+}
+
+int bindingApp::loadOneSignal(json_object* signalJ)
+{
+ json_object *onReceivedJ = nullptr, *sourcesJ = nullptr;
+ CtlActionT* onReceivedCtl;
+ const char *id = nullptr,
+ *sClass = nullptr,
+ *unit = nullptr;
+ double frequency;
+ std::string api;
+ std::vector<std::string> sourcesV;
+ ssize_t sep;
+
+ int err = wrap_json_unpack(signalJ, "{ss,so,s?s,s?s,s?F,s?o !}",
+ "id", &id,
+ "source", &sourcesJ,
+ "class", &sClass,
+ "unit", &unit,
+ "frequency", &frequency,
+ "onReceived", &onReceivedJ);
+ if (err)
+ {
+ AFB_ERROR("Missing something id|source|class|[unit]|[frequency]|onReceived in %s", json_object_get_string(signalJ));
+ return err;
+ }
+
+ // Process sources JSON object
+ // TODO: claneys, really needs to factorize JSON array processing
+ if (json_object_get_type(sourcesJ) == json_type_array)
+ {
+ int count = json_object_array_length(sourcesJ);
+ for(int i = 0; i < count; i++)
+ {
+ std::string sourceStr = json_object_get_string(sourcesJ);
+ if( (sep = sourceStr.find("/")) != std::string::npos)
+ {
+ AFB_ERROR("Signal composition needs to use signal 'id', don't use full low level signal name");
+ return -1;
+ }
+ sourcesV.push_back(sourceStr);
+ }
+ }
+ else
+ {
+ std::string sourceStr = json_object_get_string(sourcesJ);
+ if( (sep = sourceStr.find("/")) != std::string::npos)
+ {
+ api = sourceStr.substr(0, sep);
+ }
+ sourcesV.push_back(sourceStr);
+ }
+
+ // Set default sClass is not specified
+ sClass = "state";
+
+ // Get an action handler
+ onReceivedCtl = convert2Action("onReceived", onReceivedJ);
+
+ Source* src = getSource(api);
+ if( src != nullptr)
+ {src->addSignal(id, sourcesV, sClass, unit, frequency, onReceivedCtl);}
+ else
+ {err = -1;}
+
+ return err;
+}
+
+int bindingApp::loadSignals(CtlSectionT* section, json_object *signalsJ)
+{
+ int err = 0;
+ bindingApp& bApp = instance();
+
+ if (json_object_get_type(signalsJ) == json_type_array)
+ {
+ int count = json_object_array_length(signalsJ);
+
+ for (int idx = 0; idx < count; idx++)
+ {
+ json_object *signalJ = json_object_array_get_idx(signalsJ, idx);
+ err = bApp.loadOneSignal(signalJ);
+ if (err) return err;
+ }
+ }
+ else
+ {err = bApp.loadOneSignal(signalsJ);}
+
+ return err;
+}
+
+std::vector<std::shared_ptr<Signal>> bindingApp::getAllSignals()
+{
+ std::vector<std::shared_ptr<Signal>> allSignals;
+ for( auto& source : sourcesList_)
+ {
+ std::vector<std::shared_ptr<Signal>> srcSignals = source.getSignals();
+ allSignals.insert(allSignals.end(), srcSignals.begin(), srcSignals.end());
+ }
+
+ return allSignals;
+}
+
+CtlConfigT* bindingApp::ctlConfig()
+{
+ return ctlConfig_;
+}
diff --git a/signal-composer-binding/signal-composer.hpp b/signal-composer-binding/signal-composer.hpp
index bcfe60f..44b958f 100644
--- a/signal-composer-binding/signal-composer.hpp
+++ b/signal-composer-binding/signal-composer.hpp
@@ -13,60 +13,46 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- */
- #pragma once
+*/
+#pragma once
- #include <cstddef>
- #include <string>
- #include <vector>
- #include <set>
- #include <map>
- #include <json-c/json.h>
- #include <systemd/sd-event.h>
- extern "C"
- {
- #define AFB_BINDING_VERSION 2
- #include <afb/afb-binding.h>
- };
+#include <memory>
+#include <vector>
+#include <string>
+#include <ctl-config.h>
+#include <json-c/json.h>
+#include <systemd/sd-event.h>
- struct TimedEvent {
- int interval;
- afb_event event;
- std::string name;
- std::string eventName;
- };
+#include "source.hpp"
+#include "signal-composer-binding.hpp"
- struct Signal {
- std::string name;
- std::string source;
- std::string sig_class;
- std::string type;
- };
+class bindingApp
+{
+private:
+ CtlConfigT* ctlConfig_;
- class SignalComposer
- {
- public:
- SignalComposer();
- void treatMessage(json_object *message);
- bool subscribe(afb_req request);
- bool unsubscribe(afb_req request);
- bool get(afb_req request, json_object **json);
- void tick(sd_event_source *source, const long &now, void *interv);
- void startTimer(const int &t);
- ~SignalComposer();
- int parseConfigAndSubscribe(const std::string& confd);
- static bool startsWith(const std::string &s, const std::string &val);
- static void callBackFromSubscribe(void *handle, int iserror, json_object *result);
- private:
- std::map<std::string, afb_event> events;
- std::map<int, std::vector<TimedEvent>> timedEvents;
- std::map<std::string, std::map<std::string, Signal>> registeredObjects;
- std::map<std::string, std::set<std::string>> lowMessagesToObjects;
- std::set<int> timers;
- std::string generateId() const;
- json_object *generateJson(const std::string &messageObject, std::vector<std::string> *fields = nullptr);
- void registerObjects(const std::string& uri, std::map<std::string, Signal>& properties);
- std::map<std::string, std::map<std::string, Signal>> loadDefinitions(json_object* definitionsJ) const;
- void loadResources(json_object* resourcesJ, std::map<std::string, std::map<std::string, Signal>>& properties);
- int subscribeRegisteredObjects() const;
- };
+ static CtlSectionT ctlSections_[]; ///< Config Section definition (note: controls section index should match handle retrieval in)
+ std::vector<Source> sourcesList_;
+
+ explicit bindingApp(const std::string& filepath);
+ bindingApp();
+ ~bindingApp();
+
+ CtlActionT* convert2Action(const std::string& name, json_object* action);
+
+ int loadOneSource(json_object* sourcesJ);
+ static int loadSources(CtlSectionT* section, json_object *sectionJ);
+
+ int loadOneSignal(json_object* signalsJ);
+ static int loadSignals(CtlSectionT* section, json_object *sectionJ);
+
+ Source* getSource(const std::string& api);
+
+public:
+ static bindingApp& instance();
+ void loadConfig(const std::string& filepath);
+ void loadSignalsFile(std::string signalsFile);
+
+ std::vector<std::shared_ptr<Signal>> getAllSignals();
+ CtlConfigT* ctlConfig();
+};
diff --git a/signal-composer-binding/signal.cpp b/signal-composer-binding/signal.cpp
new file mode 100644
index 0000000..6b4947e
--- /dev/null
+++ b/signal-composer-binding/signal.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015, 2016 "IoT.bzh"
+ * Author "Romain Forlot" <romain.forlot@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+#include "signal.hpp"
+
+Signal::Signal()
+{}
+
+Signal(std::string& id,
+ std::vector<std::string>& sources,
+ std::string& unit,
+ float frequency,
+ CtlActionT* onReceived)
+:id_(id),
+ sources_(sources),
+ unit_(unit),
+ frequency_(frequency),
+ onReceived_(onReceived)
+{
+ for (const std::string& src: sources)
+ {
+ if(src.find("/") == std::string::npos)
+ {
+ AFB_NOTICE("Attaching %s to %s", sig->id(), src);
+ if(sig.attach(src))
+ {AFB_WARNING("Can't attach. Is %s exists ?", src);}
+ }
+ }
+}
+
+Signal::operator bool() const
+{
+ if(!id_ || !api_ || !signalName_)
+ {return false;}
+ return true;
+}
+
+int Signal::recursionCheck(const std::string& origId)
+{
+ for (const auto& obs: Observers_)
+ {
+ if( id_ == obs.id())
+ {return -1;}
+ if( origId == obs.id())
+ {return -1;}
+ if(! obs.recursionCheck(origId))
+ {return -1;}
+ }
+ return 0;
+}
+
+std::string Signal::id() const
+{
+ return id_;
+}
+
+int Signal::recursionCheck()
+{
+ for (const auto& obs: Observers_)
+ {
+ if( id_ == obs.id())
+ {return -1;}
+ if(! obs.recursionCheck(id_))
+ {return -1;}
+ }
+ return 0;
+}
+
+void update(double timestamp, double value)
+{
+ AFB_NOTICE("Got an update from observed signal");
+}
diff --git a/signal-composer-binding/signal.hpp b/signal-composer-binding/signal.hpp
index 94878c9..ad944aa 100644
--- a/signal-composer-binding/signal.hpp
+++ b/signal-composer-binding/signal.hpp
@@ -17,30 +17,42 @@
#pragma once
+#include <map>
#include <string>
#include <memory>
#include <vector>
+#include <ctl-config.h>
+
+#include "observer.hpp"
class Signal;
-class Signal
+//TODO: claneys: define observer and observable interface then inherit
+class Signal: public Observer, public Subject
{
private:
- std::string api_;
- std::string name_;
- std::vector<> history_;
- float frequency_;
- st::string unit_;
- float min_;
- float max_;
- float last_;
+ std::string id_;
+ std::vector<std::string> sources_;
+ std::map<long, double> history_; ///< history_ - Hold signal value history in map with <timestamp, value>
+ double frequency_;
+ std::string unit_;
+ CtlActionT* onReceived_;
- std::vector<std::shared_ptr<Signal>> Observers_;
+ std::vector<std::shared_ptr<Signal>> observers_;
+ int recursionCheck(const std::string& origId);
public:
- void notify();
- void infiniteRecursionCheck();
- void attach();
- void detach();
- void notify();
-}
+ Signal();
+ Signal(const std::string& id, std::vector<std::string>& sources, const std::string& unit, double frequency, CtlActionT* onReceived);
+ explicit operator bool() const;
+
+ std::string id() const;
+
+ int recursionCheck();
+ /* virtual */ void update(double timestamp, double value);
+
+ virtual double average() const;
+ virtual double min() const;
+ virtual double max() const;
+ double lastValue() const;
+};
diff --git a/signal-composer-binding/source.cpp b/signal-composer-binding/source.cpp
new file mode 100644
index 0000000..919ae5b
--- /dev/null
+++ b/signal-composer-binding/source.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015, 2016 "IoT.bzh"
+ * Author "Romain Forlot" <romain.forlot@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+#include "source.hpp"
+
+Source::Source()
+{}
+
+Source::Source(const std::string& api, const std::string& info, CtlActionT* init, CtlActionT* getSignal):
+ api_(api), info_(info), init_(init), getSignal_(getSignal)
+{}
+
+std::string Source::api()
+{
+ return api_;
+}
+
+void Source::addSignal(const std::string& id, std::vector<std::string>& sources, const std::string& sClass, const std::string& unit, double frequency, CtlActionT* onReceived)
+{
+ std::shared_ptr<Signal> sig = std::make_shared<Signal>(id, sources, unit, frequency, onReceived);
+
+ signals_.push_back(sig);
+}
+
+std::vector<std::shared_ptr<Signal>> Source::getSignals()
+{
+ return signals_;
+}
diff --git a/signal-composer-binding/source.hpp b/signal-composer-binding/source.hpp
new file mode 100644
index 0000000..694daae
--- /dev/null
+++ b/signal-composer-binding/source.hpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015, 2016 "IoT.bzh"
+ * Author "Romain Forlot" <romain.forlot@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+#pragma once
+
+#include <memory>
+#include <ctl-config.h>
+#include <signal-composer-binding.hpp>
+
+#include "signal.hpp"
+
+class Source {
+private:
+ std::string api_;
+ std::string info_;
+ CtlActionT* init_;
+ CtlActionT* getSignal_;
+
+ std::vector<std::shared_ptr<Signal>> signals_;
+
+public:
+ Source();
+ Source(const std::string& api, const std::string& info, CtlActionT* init, CtlActionT* getSignal);
+
+ std::string api();
+ void addSignal(const std::string& id, std::vector<std::string>& sources, const std::string& sClass, const std::string& unit, double frequency, CtlActionT* onReceived);
+ std::vector<std::shared_ptr<Signal>> getSignals();
+};