.
This commit is contained in:
@@ -19,6 +19,7 @@ find_package(APR REQUIRED)
|
||||
find_package(CELIX REQUIRED)
|
||||
find_package(Boost REQUIRED)
|
||||
find_package(libvariant REQUIRED)
|
||||
find_package(Poco REQUIRED COMPONENTS Net NetSSL)
|
||||
|
||||
|
||||
###################################
|
||||
@@ -44,6 +45,7 @@ include_directories(
|
||||
${APR_INCLUDE_DIR}
|
||||
${APR_INCLUDE_DIR}/apr-1.0
|
||||
${libvariant_INCLUDE_DIR}
|
||||
${Poco_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
set(BUNDLE_SYMBOLICNAME "hos.hos_ruleengine")
|
||||
@@ -60,12 +62,14 @@ bundle(hos_cosgi_ruleengine
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rules/conditions/LogicalOrCondition
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rules/conditions/LogicalAndCondition
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rules/conditions/DeviceMsgCondition
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/webresource/RuleEngineHandler
|
||||
)
|
||||
|
||||
target_link_libraries(hos_cosgi_ruleengine
|
||||
${catkin_LIBRARIES}
|
||||
${APR_LIBRARIES}
|
||||
${libvariant_LIBRARY}
|
||||
${Poco_LIBRARIES}
|
||||
)
|
||||
|
||||
|
||||
|
||||
+6
@@ -68,11 +68,16 @@ enum class RuleEngineEventType : int {
|
||||
RULE_REMOVED,
|
||||
RULE_UPDATED,
|
||||
RULE_STATE_CHANGED,
|
||||
RULECONDITION_ADDED,
|
||||
RULECONDITION_REMOVED,
|
||||
RULECONDITION_UPDATED,
|
||||
RULECONDITION_STATE_CHANGED,
|
||||
ALL_EVENTS,
|
||||
CHANGE_EVENTS
|
||||
};
|
||||
|
||||
|
||||
|
||||
class RuleEngineEvent {
|
||||
public:
|
||||
typedef std::chrono::system_clock::time_point timestamp_t;
|
||||
@@ -86,6 +91,7 @@ public:
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Public COSGI interface of the rule engine service.
|
||||
*/
|
||||
|
||||
+7
-1
@@ -3,6 +3,7 @@
|
||||
|
||||
|
||||
#include <hos/cosgi/service/Interface.h>
|
||||
#include <hos/cosgi/service/ruleengine/RuleEngineService.h>
|
||||
#include <Variant/Variant.h>
|
||||
|
||||
|
||||
@@ -14,6 +15,7 @@ namespace service {
|
||||
|
||||
// forward declarations
|
||||
namespace devicerepository { class DeviceRepositoryService; }
|
||||
namespace scripting { class Script; }
|
||||
|
||||
|
||||
// main namespace
|
||||
@@ -34,7 +36,7 @@ class RulePackage;
|
||||
* Public COSGI interface of a rule.
|
||||
*/
|
||||
class Rule
|
||||
: public virtual interface::Object {
|
||||
: public virtual interface::ObservableObject<RuleEngineEventType, RuleEngineEvent> {
|
||||
|
||||
public:
|
||||
|
||||
@@ -91,6 +93,10 @@ public:
|
||||
*/
|
||||
virtual void executeExitScript(const libvariant::Variant& lContext = libvariant::Variant()) = 0;
|
||||
|
||||
virtual std::shared_ptr<scripting::Script> getScript() = 0;
|
||||
|
||||
virtual std::shared_ptr<scripting::Script> getExitScript() = 0;
|
||||
|
||||
/**
|
||||
* Returns whether this rule is enabled.
|
||||
*
|
||||
|
||||
+2
-1
@@ -3,6 +3,7 @@
|
||||
|
||||
|
||||
#include <hos/cosgi/service/Interface.h>
|
||||
#include <hos/cosgi/service/ruleengine/RuleEngineService.h>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -40,7 +41,7 @@ class Rule;
|
||||
* Public COSGI interface of a rule package.
|
||||
*/
|
||||
class RulePackage
|
||||
: public virtual interface::Object {
|
||||
: public virtual interface::ObservableObject<RuleEngineEventType, RuleEngineEvent> {
|
||||
|
||||
public:
|
||||
|
||||
|
||||
+2
-1
@@ -3,6 +3,7 @@
|
||||
|
||||
|
||||
#include <hos/cosgi/service/Interface.h>
|
||||
#include <hos/cosgi/service/ruleengine/RuleEngineService.h>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <Variant/Variant.h>
|
||||
@@ -50,7 +51,7 @@ enum class ConditionTriggerType : int {
|
||||
* Public COSGI interface of a rule condition.
|
||||
*/
|
||||
class RuleCondition
|
||||
: public virtual interface::Object {
|
||||
: public virtual interface::ObservableObject<RuleEngineEventType, RuleEngineEvent> {
|
||||
|
||||
public:
|
||||
|
||||
|
||||
+22
-1
@@ -4,8 +4,29 @@
|
||||
|
||||
#include "RuleCondition.h"
|
||||
#include <hos/cosgi/service/Implementation.h>
|
||||
#include <hos/cosgi/service/core/CoreService.h>
|
||||
|
||||
|
||||
// Quick and dirty workaround
|
||||
// ToDo: Find better solution
|
||||
#ifndef _STD_HASH_RULEENGINEEVENTTYPE_
|
||||
#define _STD_HASH_RULEENGINEEVENTTYPE_
|
||||
namespace std {
|
||||
/**
|
||||
* Specialization of std::hash for RuleEngineEventType.
|
||||
*
|
||||
* Required by std::map.
|
||||
*/
|
||||
template <>
|
||||
class hash <hos::cosgi::service::ruleengine::RuleEngineEventType>{
|
||||
public :
|
||||
size_t operator()(const hos::cosgi::service::ruleengine::RuleEngineEventType& x) const {
|
||||
return static_cast<size_t>(x);
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
#endif
|
||||
|
||||
|
||||
// main namespace
|
||||
namespace hos {
|
||||
@@ -22,7 +43,7 @@ namespace conditions {
|
||||
*/
|
||||
class RuleConditionImpl
|
||||
: public virtual RuleCondition,
|
||||
public implementation::Object {
|
||||
public implementation::ObservableObject<RuleEngineEventType, RuleEngineEvent> {
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <hos/cosgi/celix.h>
|
||||
// CoreService
|
||||
#include "hos/cosgi/service/ruleengine/RuleEngineServiceImpl.h"
|
||||
#include "hos/cosgi/service/ruleengine/webresource/RuleEngineHandler.h"
|
||||
#include <hos/cosgi/service/core/CoreService.h>
|
||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||
|
||||
@@ -23,13 +24,16 @@ using namespace hos::cosgi::service::scripting;
|
||||
using namespace hos::cosgi::service::devicerepository;
|
||||
using namespace hos::cosgi::service::core;
|
||||
using namespace hos::cosgi;
|
||||
namespace ruleweb = hos::cosgi::service::ruleengine::webresource;
|
||||
|
||||
|
||||
|
||||
struct UserData {
|
||||
apr_pool_t* memoryPool = nullptr;
|
||||
std::unique_ptr<RuleEngineServiceImpl> serviceImpl = nullptr;
|
||||
std::unique_ptr<RuleEngineServiceImpl> serviceImpl;
|
||||
std::unique_ptr<ruleweb::RuleEngineHandlerFactory> webResourceImpl;
|
||||
service_registration_pt serviceReg = nullptr;
|
||||
service_registration_pt webResourceReg = nullptr;
|
||||
serviceListener myServiceListener;
|
||||
bundle_context_pt bundleContext;
|
||||
};
|
||||
@@ -56,10 +60,16 @@ celix_status_t cb_serviceChanged(void* listener, service_event_pt event) {
|
||||
checkReg = true;
|
||||
}
|
||||
|
||||
// Register rule engine service
|
||||
// Register rule engine service and webresource
|
||||
if (checkReg && !myUserData->serviceReg && myUserData->serviceImpl->isInitialized()) {
|
||||
RuleEngineService* engineInterface = dynamic_cast<RuleEngineService*>(myUserData->serviceImpl.get());
|
||||
bundleContext_registerService(myUserData->bundleContext, (char*)RuleEngineServiceImpl::SERVICE_NAME, engineInterface, nullptr, &myUserData->serviceReg);
|
||||
// web resource
|
||||
service::webserver::WebResourceHandlerFactory* webInterface = dynamic_cast<service::webserver::WebResourceHandlerFactory*>(myUserData->webResourceImpl.get());
|
||||
// ToDo: Properly delete properties
|
||||
properties_pt webResourceProps = properties_create();
|
||||
properties_set(webResourceProps, (char*)"path", (char*)"/ruleengine0");
|
||||
bundleContext_registerService(myUserData->bundleContext, (char*)service::webserver::WebResourceHandlerFactory::SERVICE_NAME, webInterface, webResourceProps, &myUserData->webResourceReg);
|
||||
}
|
||||
|
||||
} else if (event->type == OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING) {
|
||||
@@ -110,6 +120,12 @@ celix_status_t bundleActivator_start(void * userData, bundle_context_pt context)
|
||||
}
|
||||
myUserData->serviceImpl.reset(new RuleEngineServiceImpl());
|
||||
|
||||
// Create rule engine webresource
|
||||
if (myUserData->webResourceReg != nullptr) {
|
||||
serviceRegistration_unregister(myUserData->webResourceReg);
|
||||
}
|
||||
myUserData->webResourceImpl.reset(new ruleweb::RuleEngineHandlerFactory(myUserData->serviceImpl.get()));
|
||||
|
||||
// Get core Service
|
||||
service_reference_pt ref = nullptr;
|
||||
bundleContext_getServiceReference(context, (char*)CoreService::SERVICE_NAME, &ref);
|
||||
@@ -130,10 +146,16 @@ celix_status_t bundleActivator_start(void * userData, bundle_context_pt context)
|
||||
myUserData->serviceImpl->setRepoService(repoService);
|
||||
}
|
||||
|
||||
// Register rule engine service
|
||||
// Register rule engine service and webresource
|
||||
if (myUserData->serviceImpl->isInitialized()) {
|
||||
RuleEngineService* engineInterface = dynamic_cast<RuleEngineService*>(myUserData->serviceImpl.get());
|
||||
bundleContext_registerService(context, (char*)RuleEngineServiceImpl::SERVICE_NAME, engineInterface, nullptr, &myUserData->serviceReg);
|
||||
// web resource
|
||||
service::webserver::WebResourceHandlerFactory* webInterface = dynamic_cast<service::webserver::WebResourceHandlerFactory*>(myUserData->webResourceImpl.get());
|
||||
// ToDo: Properly delete properties
|
||||
properties_pt webResourceProps = properties_create();
|
||||
properties_set(webResourceProps, (char*)"path", (char*)"/ruleengine0");
|
||||
bundleContext_registerService(context, (char*)service::webserver::WebResourceHandlerFactory::SERVICE_NAME, webInterface, webResourceProps, &myUserData->webResourceReg);
|
||||
}
|
||||
|
||||
// Register service listener
|
||||
@@ -155,6 +177,13 @@ celix_status_t bundleActivator_stop(void * userData, bundle_context_pt context)
|
||||
if (userData != nullptr) {
|
||||
UserData* myUserData = (UserData*)userData;
|
||||
status = bundleContext_removeServiceListener(context, &myUserData->myServiceListener);
|
||||
if (myUserData->webResourceReg != nullptr) {
|
||||
serviceRegistration_unregister(myUserData->webResourceReg);
|
||||
myUserData->webResourceReg = nullptr;
|
||||
}
|
||||
if (myUserData->webResourceImpl) {
|
||||
myUserData->webResourceImpl.reset();
|
||||
}
|
||||
if (myUserData->serviceReg != nullptr) {
|
||||
serviceRegistration_unregister(myUserData->serviceReg);
|
||||
myUserData->serviceReg = nullptr;
|
||||
|
||||
@@ -21,7 +21,10 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
|
||||
// Quick and dirty workaround
|
||||
// ToDo: Find better solution
|
||||
#ifndef _STD_HASH_RULEENGINEEVENTTYPE_
|
||||
#define _STD_HASH_RULEENGINEEVENTTYPE_
|
||||
namespace std {
|
||||
/**
|
||||
* Specialization of std::hash for RuleEngineEventType.
|
||||
@@ -36,6 +39,7 @@ public :
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
#endif
|
||||
|
||||
|
||||
// Service Namespace
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <hos/cosgi/service/ruleengine/rules/conditions/RuleCondition.h>
|
||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||
#include <hos/cosgi/service/scripting/ScriptingService.h>
|
||||
#include <hos/cosgi/service/Implementation.h>
|
||||
#include "RulePackageImpl.h"
|
||||
#include <Variant/Variant.h>
|
||||
#include <string>
|
||||
@@ -31,7 +32,7 @@ using namespace libvariant;
|
||||
*/
|
||||
class RuleImpl
|
||||
: public virtual Rule,
|
||||
public implementation::Object {
|
||||
public implementation::ObservableObject<RuleEngineEventType, RuleEngineEvent> {
|
||||
|
||||
private:
|
||||
|
||||
@@ -74,6 +75,14 @@ public:
|
||||
|
||||
virtual void executeExitScript(const libvariant::Variant& lContext = libvariant::Variant()) override;
|
||||
|
||||
virtual std::shared_ptr<scripting::Script> getScript() override {
|
||||
return script;
|
||||
}
|
||||
|
||||
virtual std::shared_ptr<scripting::Script> getExitScript() override {
|
||||
return exitScript;
|
||||
}
|
||||
|
||||
virtual bool isEnabled() noexcept override {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <hos/cosgi/service/ruleengine/rules/RulePackage.h>
|
||||
#include <hos/cosgi/service/scripting/ScriptingService.h>
|
||||
#include <hos/cosgi/service/Implementation.h>
|
||||
#include "../RuleEngineServiceImpl.h"
|
||||
#include <Variant/Variant.h>
|
||||
#include <vector>
|
||||
@@ -33,7 +34,7 @@ using namespace ::libvariant;
|
||||
*/
|
||||
class RulePackageImpl
|
||||
: public virtual RulePackage,
|
||||
public implementation::Object {
|
||||
public implementation::ObservableObject<RuleEngineEventType, RuleEngineEvent> {
|
||||
|
||||
private:
|
||||
|
||||
|
||||
+324
-6
@@ -1,10 +1,328 @@
|
||||
/*
|
||||
* RuleEngineHandler.cpp
|
||||
*
|
||||
* Created on: 05.06.2015
|
||||
* Author: matthias
|
||||
*/
|
||||
|
||||
#include "RuleEngineHandler.h"
|
||||
#include <hos/cosgi/service/ruleengine/rules/RulePackage.h>
|
||||
#include <hos/cosgi/service/ruleengine/rules/Rule.h>
|
||||
#include <hos/cosgi/service/scripting/ScriptingService.h>
|
||||
#include <hos/utils/Timestamp.h>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <Poco/URI.h>
|
||||
#include <Poco/Timestamp.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <chrono>
|
||||
#include <Poco/Net/HTTPServerRequestImpl.h>
|
||||
#include <Poco/Net/HTTPServerResponseImpl.h>
|
||||
#include <Poco/Net/WebSocket.h>
|
||||
#include "Poco/Net/NetException.h"
|
||||
#include <Poco/Net/StreamSocket.h>
|
||||
|
||||
|
||||
|
||||
// Service Namespace
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace webresource {
|
||||
|
||||
|
||||
|
||||
using namespace Poco;
|
||||
using namespace libvariant;
|
||||
|
||||
|
||||
|
||||
HOS_SERVICE_IMPL_INFO( RuleEngineHandlerFactory, // Implementation
|
||||
service::webserver::WebResourceHandlerFactory::SERVICE_NAME, // Service Name
|
||||
1, 0 ) // Version
|
||||
|
||||
|
||||
RuleEngineHandlerFactory::RuleEngineHandlerFactory(RuleEngineService* ruleService)
|
||||
: ruleService(ruleService),
|
||||
pkgInfoFuncs([](const std::string& key)->pkgInfoFuncs_t::Func_t {
|
||||
throw webserver::webresource::WebResourceHandlerException((boost::format("Unknown category \"%1%\"") % key).str(),
|
||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
||||
}),
|
||||
ruleInfoFuncs([](const std::string& key)->ruleInfoFuncs_t::Func_t {
|
||||
throw webserver::webresource::WebResourceHandlerException((boost::format("Unknown category \"%1%\"") % key).str(),
|
||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
||||
}) {
|
||||
|
||||
pkgInfoFuncs.add("id", [](rules::RulePackage* pkg, const std::string& category)->Variant {
|
||||
return pkg->getName();
|
||||
});
|
||||
|
||||
pkgInfoFuncs.add("language", [](rules::RulePackage* pkg, const std::string& category)->Variant {
|
||||
return pkg->getLanguage();
|
||||
});
|
||||
|
||||
pkgInfoFuncs.add("enabled", [](rules::RulePackage* pkg, const std::string& category)->Variant {
|
||||
return pkg->isEnabled();
|
||||
});
|
||||
|
||||
pkgInfoFuncs.add("globalcontext", [](rules::RulePackage* pkg, const std::string& category)->Variant {
|
||||
auto gc = pkg->getGlobalScriptContext();
|
||||
if (!gc.expired()) {
|
||||
return gc.lock()->getJSONRepresentation();
|
||||
} else {
|
||||
return libvariant::Variant::NullType;
|
||||
}
|
||||
});
|
||||
|
||||
pkgInfoFuncs.add("rules", [this](rules::RulePackage* pkg, const std::string& category)->Variant {
|
||||
Variant retval = libvariant::Variant::List();
|
||||
for (auto r : pkg->getRules()) {
|
||||
if (!r.expired()) {
|
||||
retval.Append(getRuleInfo(r.lock().get()));
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
});
|
||||
|
||||
|
||||
ruleInfoFuncs.add("id", [](rules::Rule* rule, const std::string& category)->Variant {
|
||||
return rule->getName();
|
||||
});
|
||||
|
||||
ruleInfoFuncs.add("enabled", [](rules::Rule* rule, const std::string& category)->Variant {
|
||||
return rule->isEnabled();
|
||||
});
|
||||
|
||||
ruleInfoFuncs.add("script", [](rules::Rule* rule, const std::string& category)->Variant {
|
||||
auto script = rule->getScript();
|
||||
if (script) {
|
||||
return script->getJSONRepresentation();
|
||||
} else {
|
||||
return Variant::NullType;
|
||||
}
|
||||
});
|
||||
|
||||
ruleInfoFuncs.add("exitscript", [](rules::Rule* rule, const std::string& category)->Variant {
|
||||
auto script = rule->getExitScript();
|
||||
if (script) {
|
||||
return script->getJSONRepresentation();
|
||||
} else {
|
||||
return Variant::NullType;
|
||||
}
|
||||
});
|
||||
|
||||
ruleInfoFuncs.add("condition", [](rules::Rule* rule, const std::string& category)->Variant {
|
||||
return "ToDo";
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Net::HTTPRequestHandler* RuleEngineHandlerFactory::createRequestHandler( Poco::URI matchUri, const Net::HTTPServerRequest& request, bool ssl ) noexcept {
|
||||
return new RuleEngineHandler( this, matchUri, ruleService, ssl);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Variant RuleEngineHandlerFactory::getRulePkgInfo( rules::RulePackage* pkg, const std::string& category, const std::string& path ) {
|
||||
Variant retval;
|
||||
// We want all info categories
|
||||
if (category.empty()) {
|
||||
pkgInfoFuncs.forEach([&](const std::string& key, const Variant& value){
|
||||
retval[key] = value;
|
||||
}, pkg, category);
|
||||
|
||||
// We want a single info category
|
||||
} else {
|
||||
retval = pkgInfoFuncs.call(category, pkg, category);
|
||||
if (!path.empty()) {
|
||||
if (retval.HasPath(path)) {
|
||||
retval = retval.GetPath(path);
|
||||
} else {
|
||||
throw webserver::webresource::WebResourceHandlerException((boost::format("Unknown path \"%1%\" for rule package info category \"%2%\".") % path % category).str(),
|
||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Variant RuleEngineHandlerFactory::getRuleInfo( rules::Rule* rule, const std::string& category, const std::string& path ) {
|
||||
Variant retval;
|
||||
// We want all info categories
|
||||
if (category.empty()) {
|
||||
ruleInfoFuncs.forEach([&](const std::string& key, const Variant& value){
|
||||
retval[key] = value;
|
||||
}, rule, category);
|
||||
|
||||
// We want a single info category
|
||||
} else {
|
||||
retval = ruleInfoFuncs.call(category, rule, category);
|
||||
if (!path.empty()) {
|
||||
if (retval.HasPath(path)) {
|
||||
retval = retval.GetPath(path);
|
||||
} else {
|
||||
throw webserver::webresource::WebResourceHandlerException((boost::format("Unknown path \"%1%\" for rule info category \"%2%\".") % path % category).str(),
|
||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RuleEngineHandler::_handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
||||
if(req.find("Upgrade") != req.end() && Poco::icompare(req["Upgrade"], "websocket") == 0) {
|
||||
//__handleEvent(req, resp, true);
|
||||
/*throw webserver::webresource::WebResourceHandlerException("ToDo",
|
||||
Net::HTTPResponse::HTTP_NOT_IMPLEMENTED);*/
|
||||
} else {
|
||||
if (req.getMethod() == Net::HTTPRequest::HTTP_PUT) {
|
||||
// Put Command
|
||||
throw webserver::webresource::WebResourceHandlerException("Still a ToDo.",
|
||||
Net::HTTPResponse::HTTP_NOT_IMPLEMENTED);
|
||||
} else if (req.getMethod() == Net::HTTPRequest::HTTP_GET || req.getMethod() == Net::HTTPRequest::HTTP_POST) {
|
||||
RuleEngineAPIMethod method = getRuleEngineAPIMethod(req);
|
||||
if (method == RuleEngineAPIMethod::GET) {
|
||||
__handleInfo(req, resp);
|
||||
} else if (method == RuleEngineAPIMethod::SET) {
|
||||
//__handleCommand(req, resp, method);
|
||||
} else if (method == RuleEngineAPIMethod::EVENT) {
|
||||
//__handleEvent(req, resp, false);
|
||||
} else {
|
||||
throw webserver::webresource::WebResourceHandlerException("Could not understood request",
|
||||
Net::HTTPResponse::HTTP_BAD_REQUEST);
|
||||
}
|
||||
} else {
|
||||
throw webserver::webresource::WebResourceHandlerException("Could not understood request",
|
||||
Net::HTTPResponse::HTTP_BAD_REQUEST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RuleEngineHandler::__handleInfo(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
||||
|
||||
std::vector<std::string> pathPieces, matchPieces;
|
||||
matchUri.getPathSegments(matchPieces);
|
||||
Poco::URI uri(req.getURI());
|
||||
uri.getPathSegments(pathPieces);
|
||||
std::unique_ptr<Net::HTMLForm> form;
|
||||
if (req.getMethod() == Net::HTTPRequest::HTTP_POST) {
|
||||
form.reset(new Net::HTMLForm(req, req.stream()));
|
||||
} else {
|
||||
form.reset(new Net::HTMLForm(req));
|
||||
}
|
||||
|
||||
// Nothing given, query mode (there is no real query functionality implemented yet though)
|
||||
if (pathPieces.size() <= matchPieces.size()) {
|
||||
auto pkgs = ruleService->getRulePackages();
|
||||
|
||||
// Parse HTTP header "Range" parameter (to support dojo/store)
|
||||
size_t rangeStart = 0;
|
||||
size_t rangeStop = pkgs.size() - 1;
|
||||
std::string rangeRaw;
|
||||
if (req.has("Range")) {
|
||||
rangeRaw = req.get("Range");
|
||||
} else if (req.has("X-Range")) {
|
||||
rangeRaw = req.get("X-Range");
|
||||
}
|
||||
if (!rangeRaw.empty()) {
|
||||
if (boost::algorithm::starts_with(rangeRaw, "items=")) {
|
||||
auto range = rangeRaw.substr(6);
|
||||
std::vector<std::string> splitParts;
|
||||
boost::algorithm::split(splitParts, range, boost::algorithm::is_any_of("-"));
|
||||
if (splitParts.size() == 2) {
|
||||
try {
|
||||
size_t r1 = std::stol(splitParts[0]);
|
||||
size_t r2 = std::stol(splitParts[1]);
|
||||
if (r1 <= r2) {
|
||||
rangeStart = r1;
|
||||
rangeStop = std::min(r2, rangeStop);
|
||||
}
|
||||
} catch (...) {
|
||||
ROS_ERROR_STREAM("Could not parse Range parameter \"" << rangeRaw << "\".");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate over packages
|
||||
Variant result = Variant::List();
|
||||
if (pkgs.size() > 0) {
|
||||
for (size_t t = rangeStart; t <= rangeStop; t++) {
|
||||
auto pkg = pkgs[t].lock();
|
||||
result.Append(parent->getRulePkgInfo(pkg.get()));
|
||||
}
|
||||
}
|
||||
|
||||
// There are no devices and a range was given, probably out of range
|
||||
if (result.Size() == 0 && rangeStart > 0) {
|
||||
if (rangeStart > 0) {
|
||||
handleErrorResponse(req, resp, "Out of range", Poco::Net::HTTPResponse::HTTP_NOT_FOUND);
|
||||
} else {
|
||||
handleResponse(req, resp, result);
|
||||
}
|
||||
|
||||
// Return devices array
|
||||
} else {
|
||||
std::string rangeOut = (boost::format("items %1%-%2%/%3%") % rangeStart % rangeStop % pkgs.size()).str();
|
||||
resp.set("Content-Range", rangeOut);
|
||||
resp.set("X-Content-Range", rangeOut);
|
||||
handleResponse(req, resp, result);
|
||||
}
|
||||
|
||||
// rule package given
|
||||
} else if (pathPieces.size() == matchPieces.size() + 1) {
|
||||
|
||||
// rule given
|
||||
} else if (pathPieces.size() == matchPieces.size() + 2) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
RuleEngineAPIMethod RuleEngineHandler::getRuleEngineAPIMethod(Net::HTTPServerRequest &req) noexcept {
|
||||
std::unique_ptr<Net::HTMLForm> form;
|
||||
RuleEngineAPIMethod retval = RuleEngineAPIMethod::GET; // default
|
||||
if (req.getMethod() == Net::HTTPRequest::HTTP_POST && req.has("Content-type")
|
||||
&& req.get("Content-type") == Net::HTMLForm::ENCODING_URL) {
|
||||
form.reset(new Net::HTMLForm(req, req.stream()));
|
||||
} else {
|
||||
form.reset(new Net::HTMLForm(req));
|
||||
}
|
||||
std::string methodRaw;
|
||||
if (form->has("method")) {
|
||||
methodRaw = form->get("method");
|
||||
} else if (req.has("API-Method")) {
|
||||
methodRaw = req.get("API-Method");
|
||||
} else if (req.has("X-API-Method")) {
|
||||
methodRaw = req.get("X-API-Method");
|
||||
}
|
||||
if (!methodRaw.empty()) {
|
||||
if (methodRaw == "get") {
|
||||
retval = RuleEngineAPIMethod::GET;
|
||||
} else if (methodRaw == "set") {
|
||||
retval = RuleEngineAPIMethod::SET;
|
||||
} else if (methodRaw == "event") {
|
||||
retval = RuleEngineAPIMethod::EVENT;
|
||||
} else {
|
||||
throw webserver::webresource::WebResourceHandlerException(
|
||||
(boost::format("Unknown rule engine api method \"%1%\"") % methodRaw).str(),
|
||||
Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST );
|
||||
}
|
||||
} else if (form->has("onevent") || req.has("On-Event") || req.has("X-On-Event")) {
|
||||
retval = RuleEngineAPIMethod::EVENT;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace webresource
|
||||
} // namespace ruleengine
|
||||
} // namespace service
|
||||
} // namespace cosgi
|
||||
} // namespace hos
|
||||
|
||||
|
||||
+56
-16
@@ -6,6 +6,7 @@
|
||||
#include <hos/cosgi/service/webserver/WebServerService.h>
|
||||
#include <hos/cosgi/service/webserver/webresource/WebResourceHandlerImpl.h>
|
||||
#include <hos/cosgi/service/ruleengine/RuleEngineService.h>
|
||||
#include <hos/utils/FunctionTable.h>
|
||||
#include <Poco/Net/HTTPRequestHandler.h>
|
||||
#include <Variant/Variant.h>
|
||||
#include <ros/ros.h>
|
||||
@@ -42,33 +43,59 @@ enum class RuleEngineAPIMethod {
|
||||
|
||||
|
||||
|
||||
typedef webserver::webresource::WebResourceEventQueue<
|
||||
interface::Observer<RuleEngineEventType, RuleEngineEvent>,
|
||||
RuleEngineHandlerFactory,
|
||||
RuleEngineHandler
|
||||
> RuleEngineEventQueueBase;
|
||||
|
||||
class RuleEngineEventQueue
|
||||
: public RuleEngineEventQueueBase {
|
||||
public:
|
||||
RuleEngineEventType eventType = RuleEngineEventType::ALL_EVENTS;
|
||||
RuleEngineService* const ruleService;
|
||||
|
||||
RuleEngineEventQueue( const std::string& clientID,
|
||||
RuleEngineHandlerFactory* handlerFactory,
|
||||
RuleEngineService* ruleService )
|
||||
: WebResourceEventQueue(clientID, handlerFactory), ruleService(ruleService) {}
|
||||
virtual ~RuleEngineEventQueue() {
|
||||
unregisterEvents();
|
||||
}
|
||||
|
||||
/*void checkRegistration(RuleEngineEventType eventType, Device* device, const std::string& pointer);
|
||||
void registerEvents(RuleEngineEventType eventType, Device* device = nullptr);*/
|
||||
void unregisterEvents() {
|
||||
}
|
||||
|
||||
virtual void notificationReceived( interface::Observer<RuleEngineEventType, RuleEngineEvent>::observable_type* o,
|
||||
const RuleEngineEventType& key,
|
||||
const RuleEngineEvent* e) noexcept override {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class RuleEngineHandlerFactory
|
||||
: public virtual webserver::WebResourceHandlerFactory,
|
||||
public implementation::Service<RuleEngineHandlerFactory> {
|
||||
: public webserver::webresource::WebResourceHandlerFactoryImpl<RuleEngineHandlerFactory, false, RuleEngineEventQueue> {
|
||||
public:
|
||||
typedef std::function<libvariant::Variant( rules::RulePackage* pkg, const std::string& category )> pkgInfoFunc_t;
|
||||
typedef std::function<libvariant::Variant( rules::Rule* pkg, const std::string& category )> ruleInfoFuncFunc_t;
|
||||
private:
|
||||
webserver::WebServerService* service = nullptr;
|
||||
typedef utils::FunctionTable<std::string, libvariant::Variant, rules::RulePackage*, const std::string&> pkgInfoFuncs_t;
|
||||
typedef utils::FunctionTable<std::string, libvariant::Variant, rules::Rule*, const std::string&> ruleInfoFuncs_t;
|
||||
RuleEngineService* ruleService;
|
||||
boost::asio::io_service io_service;
|
||||
std::unique_ptr<std::thread> io_service_thread;
|
||||
pkgInfoFuncs_t pkgInfoFuncs;
|
||||
ruleInfoFuncs_t ruleInfoFuncs;
|
||||
|
||||
public:
|
||||
RuleEngineHandlerFactory(RuleEngineService* ruleService);
|
||||
~RuleEngineHandlerFactory();
|
||||
|
||||
virtual Poco::Net::HTTPRequestHandler* createRequestHandler(Poco::URI matchUri, const Poco::Net::HTTPServerRequest& request, bool ssl ) noexcept override;
|
||||
|
||||
virtual void setWebServerService(webserver::WebServerService* service) noexcept override {
|
||||
this->service = service;
|
||||
}
|
||||
libvariant::Variant getRulePkgInfo( rules::RulePackage* pkg, const std::string& category = "", const std::string& path = "" );
|
||||
|
||||
virtual bool excludeFromAuthentication() noexcept override {
|
||||
return false;
|
||||
}
|
||||
|
||||
boost::asio::io_service& getIOService() {
|
||||
return io_service;
|
||||
}
|
||||
libvariant::Variant getRuleInfo( rules::Rule* pkg, const std::string& category = "", const std::string& path = "" );
|
||||
|
||||
};
|
||||
|
||||
@@ -82,6 +109,7 @@ protected:
|
||||
RuleEngineService* ruleService;
|
||||
bool ssl;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
RuleEngineHandler( RuleEngineHandlerFactory* parent,
|
||||
@@ -92,11 +120,23 @@ public:
|
||||
|
||||
virtual void _handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override;
|
||||
|
||||
void __handleInfo(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp);
|
||||
|
||||
void __handleSet(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, RuleEngineAPIMethod method);
|
||||
|
||||
void __handleEvent(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, bool websocket);
|
||||
|
||||
static RuleEngineAPIMethod getRuleEngineAPIMethod(Poco::Net::HTTPServerRequest &req) noexcept;
|
||||
|
||||
/*void sendDeviceCommand( devicerepository::Device* device,
|
||||
Poco::Net::HTTPServerRequest &req,
|
||||
const std::string& cmd,
|
||||
const std::vector<std::string>& path = std::vector<std::string>() );*/
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace webresource
|
||||
} // namespace ruleengine
|
||||
} // namespace service
|
||||
|
||||
Reference in New Issue
Block a user