summaryrefslogtreecommitdiffstats
path: root/signal-composer-binding/signal-composer.cpp
diff options
context:
space:
mode:
authorRomain Forlot <romain.forlot@iot.bzh>2017-09-19 01:17:28 +0200
committerRomain Forlot <romain.forlot@iot.bzh>2017-12-14 11:00:25 +0100
commitf4fba8a2744991ff8c5cb8af4a67c7d9456f1057 (patch)
tree352231c9342344599ec2af08ef82495deefb238f /signal-composer-binding/signal-composer.cpp
parent9f61a83961cdbf133fdeb80cb978e6c79f4a9547 (diff)
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 <romain.forlot@iot.bzh>
Diffstat (limited to 'signal-composer-binding/signal-composer.cpp')
-rw-r--r--signal-composer-binding/signal-composer.cpp184
1 files changed, 134 insertions, 50 deletions
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 <string.h>
+#include <fnmatch.h>
#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<std::string> bindingApp::parseURI(const std::string& uri)
+{
+ std::vector<std::string> 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<std::string> 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://<plugin-name>/<function-name>");
+ 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<std::string> 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://<plugin-name>/<function-name>");
+ 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<std::string> sourcesV;
+ std::vector<std::string> 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: <api>/<event>");
+ 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<Signal> bindingApp::searchSignal(const std::string& aName)
{
std::string api;
@@ -306,7 +390,7 @@ std::shared_ptr<Signal> bindingApp::searchSignal(const std::string& aName)
std::vector<std::shared_ptr<Signal>> bindingApp::getAllSignals()
{
std::vector<std::shared_ptr<Signal>> allSignals;
- for( auto& source : sourcesList_)
+ for( auto& source : sourcesListV_)
{
std::vector<std::shared_ptr<Signal>> 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;