From f4fba8a2744991ff8c5cb8af4a67c7d9456f1057 Mon Sep 17 00:00:00 2001 From: Romain Forlot Date: Tue, 19 Sep 2017 01:17:28 +0200 Subject: Modification about conf definition - Argument for each signal subscription. (getSignalsArgs) - differentiation between Signal as raw signal from another API and virtual signal depending upon other signals - changing way to specify function with uri that specify everythings that could be needed to invoke a function. Change-Id: I8917c5ae3c2c1e3fa48ddfdda41fc75eaba32bb7 Signed-off-by: Romain Forlot --- signal-composer-binding/signal-composer.cpp | 184 ++++++++++++++++++++-------- 1 file changed, 134 insertions(+), 50 deletions(-) (limited to 'signal-composer-binding/signal-composer.cpp') diff --git a/signal-composer-binding/signal-composer.cpp b/signal-composer-binding/signal-composer.cpp index b29df22..151de6c 100644 --- a/signal-composer-binding/signal-composer.cpp +++ b/signal-composer-binding/signal-composer.cpp @@ -16,6 +16,7 @@ */ #include +#include #include "signal-composer.hpp" @@ -26,15 +27,23 @@ extern "C" void setSignalValueHandle(const char* aName, long long int timestamp, {sig->set(timestamp, value);} } +bool startsWith(const std::string& str, const std::string& pattern) +{ + size_t sep; + if( (sep = str.find(pattern)) != std::string::npos && !sep) + {return true;} + return false; +} + static struct pluginCBT pluginHandle = { .setSignalValue = setSignalValueHandle, }; CtlSectionT bindingApp::ctlSections_[] = { - [0]={.key="plugins" ,.label = "plugins", .info=nullptr, + [0]={.key="plugins" , .label = "plugins", .info=nullptr, .loadCB=PluginConfig, .handle=&pluginHandle}, - [1]={.key="sources" ,.label = "sources", .info=nullptr, + [1]={.key="sources" , .label = "sources", .info=nullptr, .loadCB=loadSourcesAPI, .handle=nullptr}, [2]={.key="signals" , .label= "signals", .info=nullptr, @@ -68,7 +77,7 @@ bindingApp& bindingApp::instance() SourceAPI* bindingApp::getSourceAPI(const std::string& api) { - for(auto& source: sourcesList_) + for(auto& source: sourcesListV_) { if (source.api() == api) {return &source;} @@ -76,6 +85,27 @@ SourceAPI* bindingApp::getSourceAPI(const std::string& api) return nullptr; } +std::vector bindingApp::parseURI(const std::string& uri) +{ + std::vector uriV; + std::string delimiters = "/"; + + std::string::size_type start = 0; + auto pos = uri.find_first_of(delimiters, start); + while(pos != std::string::npos) + { + if(pos != start) // ignore empty tokens + uriV.emplace_back(uri, start, pos - start); + start = pos + 1; + pos = uri.find_first_of(delimiters, start); + } + + if(start < uri.length()) // ignore trailing delimiter + uriV.emplace_back(uri, start, uri.length() - start); // add what's left of the string + + return uriV; +} + CtlActionT* bindingApp::convert2Action(const std::string& name, json_object* actionJ) { json_object *functionArgsJ = nullptr, *action = nullptr; @@ -88,35 +118,52 @@ CtlActionT* bindingApp::convert2Action(const std::string& name, json_object* act "args", &functionArgsJ)) { action = nullptr; - if(::strcasestr(function, "lua")) + if(startsWith(function, "lua://")) { + std::string fName = std::string(function).substr(6); wrap_json_pack(&action, "{ss,ss,so*}", "label", name.c_str(), - "lua", function, + "lua", fName, "args", functionArgsJ); } - else if(strstr(function, "/")) + else if(startsWith(function, "api://")) { - const char* api = strsep(&function, "/"); - //std::string api = functionS.substr(0, sep); - //std::string verb = functionS.substr(sep); + std::string uri = std::string(function).substr(6); + std::vector uriV = bindingApp::parseURI(uri); + if(uriV.size() != 2) + { + AFB_ERROR("Miss something in uri either plugin name or function name. Uri has to be like: api:///"); + return nullptr; + } wrap_json_pack(&action, "{ss,ss,ss,so*}", "label", name.c_str(), - "api", api, - "verb", function, + "api", uriV[0].c_str(), + "verb", uriV[1].c_str(), "args", functionArgsJ); } - else + else if(startsWith(function, "plugin://")) { + std::string uri = std::string(function).substr(9); + std::vector uriV = bindingApp::parseURI(uri); + if(uriV.size() != 2) + { + AFB_ERROR("Miss something in uri either plugin name or function name. Uri has to be like: plugin:///"); + return nullptr; + } json_object *callbackJ = nullptr; wrap_json_pack(&callbackJ, "{ss,ss,so*}", - "plugin", plugin, - "function", function, + "plugin", uriV[0].c_str(), + "function", uriV[1].c_str(), "args", functionArgsJ); wrap_json_pack(&action, "{ss,so}", "label", name.c_str(), "callback", callbackJ); } + else + { + AFB_ERROR("Wrong function uri specified. You have to specified 'lua://', 'plugin://' or 'api://'. (%s)", function); + return nullptr; + } } if(action) {return ActionLoad(action);} return nullptr; @@ -124,18 +171,18 @@ CtlActionT* bindingApp::convert2Action(const std::string& name, json_object* act int bindingApp::loadOneSourceAPI(json_object* sourceJ) { - json_object *initJ = nullptr, *getSignalJ = nullptr; - CtlActionT *initCtl = nullptr, *getSignalCtl = nullptr; + json_object *initJ = nullptr, *getSignalsJ = nullptr; + CtlActionT *initCtl = nullptr, *getSignalsCtl = nullptr; 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); + "getSignals", &getSignalsJ); if (err) { - AFB_ERROR("Missing something api|[info]|[init]|[getSignal] in %s", json_object_get_string(sourceJ)); + AFB_ERROR("Missing something api|[info]|[init]|[getSignals] in %s", json_object_get_string(sourceJ)); return err; } @@ -147,9 +194,9 @@ int bindingApp::loadOneSourceAPI(json_object* sourceJ) } if(initJ) {initCtl = convert2Action("init", initJ);} - if(getSignalJ) {getSignalCtl = convert2Action("getSignal", getSignalJ);} + if(getSignalsJ) {getSignalsCtl = convert2Action("getSignals", getSignalsJ);} - sourcesList_.push_back(SourceAPI(api, info, initCtl, getSignalCtl)); + sourcesListV_.push_back(SourceAPI(api, info, initCtl, getSignalsCtl)); return err; } @@ -192,64 +239,96 @@ int bindingApp::loadSourcesAPI(CtlSectionT* section, json_object *sourcesJ) int bindingApp::loadOneSignal(json_object* signalJ) { - json_object *onReceivedJ = nullptr, *sourcesJ = nullptr; + json_object *onReceivedJ = nullptr, *dependsJ = nullptr, *getSignalsArgs = nullptr; CtlActionT* onReceivedCtl; const char *id = nullptr, + *event = nullptr, *sClass = nullptr, *unit = nullptr; - double frequency; + double frequency=0.0; std::string api; - std::vector sourcesV; + std::vector dependsV; ssize_t sep; - int err = wrap_json_unpack(signalJ, "{ss,so,s?s,s?s,s?F,s?o !}", + int err = wrap_json_unpack(signalJ, "{ss,s?s,s?o,s?o,s?s,s?s,s?F,s?o !}", "id", &id, - "source", &sourcesJ, + "event", &event, + "depends", &dependsJ, + "getSignalsArgs", &getSignalsArgs, "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)); + AFB_ERROR("Missing something id|[event|depends]|[getSignalsArgs]|[class]|[unit]|[frequency]|[onReceived] in %s", json_object_get_string(signalJ)); return err; } - // Process sources JSON object - if (json_object_get_type(sourcesJ) == json_type_array) + // Set default sClass is not specified + sClass = !sClass ? "state" : sClass; + unit = !unit ? "" : unit; + + // Get an action handler + onReceivedCtl = onReceivedJ ? convert2Action("onReceived", onReceivedJ) : nullptr; + + // event or depends field manadatory + if( (!event && !dependsJ) || (event && dependsJ) ) + { + AFB_ERROR("Missing something id|[event|depends]|[getSignalsArgs]|[class]|[unit]|[frequency]|[onReceived] in %s. Or you declare event AND depends, only one of them is needed.", json_object_get_string(signalJ)); + return -1; + } + + // Process depends JSON object to declare virtual signal dependencies + if (dependsJ) { - int count = json_object_array_length(sourcesJ); - for(int i = 0; i < count; i++) + if(json_object_get_type(dependsJ) == json_type_array) + { + int count = json_object_array_length(dependsJ); + for(int i = 0; i < count; i++) + { + std::string sourceStr = json_object_get_string(json_object_array_get_idx(dependsJ, i)); + 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; + } + dependsV.push_back(sourceStr); + } + api = sourcesListV_.rbegin()->api(); + } + else { - std::string sourceStr = json_object_get_string(json_object_array_get_idx(sourcesJ, i)); + std::string sourceStr = json_object_get_string(dependsJ); 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); + dependsV.push_back(sourceStr); + api = sourcesListV_.rbegin()->api(); } } - else + + // Declare a raw signal + if(event) { - std::string sourceStr = json_object_get_string(sourcesJ); - if( (sep = sourceStr.find("/")) != std::string::npos) + std::string eventStr = std::string(event); + if( (sep = eventStr.find("/")) == std::string::npos) { - api = sourceStr.substr(0, sep); + AFB_ERROR("Missing something in event declaration. Has to be like: /"); + return -1; } - sourcesV.push_back(sourceStr); + api = eventStr.substr(0, sep); + } + else + { + event = ""; } - - // Set default sClass is not specified - sClass = !sClass ? "state" : sClass; - unit = !unit ? "" : unit; - - // Get an action handler - onReceivedCtl = convert2Action("onReceived", onReceivedJ); SourceAPI* src = getSourceAPI(api) ? getSourceAPI(api):getSourceAPI("signal-composer"); - if( src != nullptr) - {src->addSignal(id, sourcesV, sClass, unit, frequency, onReceivedCtl);} + if(src != nullptr) + {src->addSignal(id, event, dependsV, sClass, unit, frequency, onReceivedCtl, getSignalsArgs);} else {err = -1;} @@ -281,6 +360,11 @@ int bindingApp::loadSignals(CtlSectionT* section, json_object *signalsJ) return err; } +int bindingApp::loadSignals(json_object* signalsJ) +{ + return loadSignals(nullptr, signalsJ); +} + std::shared_ptr bindingApp::searchSignal(const std::string& aName) { std::string api; @@ -306,7 +390,7 @@ std::shared_ptr bindingApp::searchSignal(const std::string& aName) std::vector> bindingApp::getAllSignals() { std::vector> allSignals; - for( auto& source : sourcesList_) + for( auto& source : sourcesListV_) { std::vector> srcSignals = source.getSignals(); allSignals.insert(allSignals.end(), srcSignals.begin(), srcSignals.end()); @@ -320,14 +404,14 @@ CtlConfigT* bindingApp::ctlConfig() return ctlConfig_; } -int bindingApp::execSubscription() const +int bindingApp::execSubscription() { int err = 0; - for(const SourceAPI& srcAPI: sourcesList_) + for(SourceAPI& srcAPI: sourcesListV_) { if (srcAPI.api() != std::string(ctlConfig_->api)) { - err += srcAPI.makeSubscription(); + err = srcAPI.makeSubscription(); } } return err; -- cgit 1.2.3-korg