.
This commit is contained in:
+40
-91
@@ -88,9 +88,9 @@ Net::HTTPRequestHandler* DeviceRepoHandlerFactory::createRequestHandler( Poco::U
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DeviceRepoHandler::_handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
void DeviceRepoHandler::_handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Net::HTMLForm& form) {
|
||||||
if(req.find("Upgrade") != req.end() && Poco::icompare(req["Upgrade"], "websocket") == 0) {
|
if(req.find("Upgrade") != req.end() && Poco::icompare(req["Upgrade"], "websocket") == 0) {
|
||||||
__handleEvent(req, resp, true);
|
__handleEvent(req, resp, form, true);
|
||||||
/*throw webserver::webresource::WebResourceHandlerException("ToDo",
|
/*throw webserver::webresource::WebResourceHandlerException("ToDo",
|
||||||
Net::HTTPResponse::HTTP_NOT_IMPLEMENTED);*/
|
Net::HTTPResponse::HTTP_NOT_IMPLEMENTED);*/
|
||||||
} else {
|
} else {
|
||||||
@@ -99,13 +99,13 @@ void DeviceRepoHandler::_handleRequest(Poco::Net::HTTPServerRequest &req, Poco::
|
|||||||
throw webserver::webresource::WebResourceHandlerException("Still a ToDo.",
|
throw webserver::webresource::WebResourceHandlerException("Still a ToDo.",
|
||||||
Net::HTTPResponse::HTTP_NOT_IMPLEMENTED);
|
Net::HTTPResponse::HTTP_NOT_IMPLEMENTED);
|
||||||
} else if (req.getMethod() == Net::HTTPRequest::HTTP_GET || req.getMethod() == Net::HTTPRequest::HTTP_POST) {
|
} else if (req.getMethod() == Net::HTTPRequest::HTTP_GET || req.getMethod() == Net::HTTPRequest::HTTP_POST) {
|
||||||
DeviceAPIMethod method = getDeviceAPIMethod(req);
|
DeviceAPIMethod method = getDeviceAPIMethod(req, form);
|
||||||
if (method == DeviceAPIMethod::GET) {
|
if (method == DeviceAPIMethod::GET) {
|
||||||
__handleInfo(req, resp);
|
__handleInfo(req, resp, form);
|
||||||
} else if (method == DeviceAPIMethod::COMMAND || method == DeviceAPIMethod::STATUSUPDATE) {
|
} else if (method == DeviceAPIMethod::COMMAND || method == DeviceAPIMethod::STATUSUPDATE) {
|
||||||
__handleCommand(req, resp, method);
|
__handleCommand(req, resp, method, form);
|
||||||
} else if (method == DeviceAPIMethod::EVENT) {
|
} else if (method == DeviceAPIMethod::EVENT) {
|
||||||
__handleEvent(req, resp, false);
|
__handleEvent(req, resp, form, false);
|
||||||
} else {
|
} else {
|
||||||
throw webserver::webresource::WebResourceHandlerException("Could not understood request",
|
throw webserver::webresource::WebResourceHandlerException("Could not understood request",
|
||||||
Net::HTTPResponse::HTTP_BAD_REQUEST);
|
Net::HTTPResponse::HTTP_BAD_REQUEST);
|
||||||
@@ -119,51 +119,20 @@ void DeviceRepoHandler::_handleRequest(Poco::Net::HTTPServerRequest &req, Poco::
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void DeviceRepoHandler::__handleInfo(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
void DeviceRepoHandler::__handleInfo(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Net::HTMLForm& form) {
|
||||||
|
|
||||||
std::vector<std::string> pathPieces, matchPieces;
|
std::vector<std::string> pathPieces, matchPieces;
|
||||||
matchUri.getPathSegments(matchPieces);
|
matchUri.getPathSegments(matchPieces);
|
||||||
Poco::URI uri(req.getURI());
|
Poco::URI uri(req.getURI());
|
||||||
uri.getPathSegments(pathPieces);
|
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
// No device given, query mode (there is no real query functionality implemented yet though)
|
// No device given, query mode (there is no real query functionality implemented yet though)
|
||||||
if (pathPieces.size() <= matchPieces.size()) {
|
if (pathPieces.size() <= matchPieces.size()) {
|
||||||
auto devices = repoService->getDevices();
|
auto devices = repoService->getDevices();
|
||||||
|
|
||||||
// Parse HTTP header "Range" parameter (to support dojo/store)
|
// Range header parameter
|
||||||
size_t rangeStart = 0;
|
size_t rangeStart = 0;
|
||||||
size_t rangeStop = devices.size() - 1;
|
size_t rangeStop = devices.size() - 1;
|
||||||
std::string rangeRaw;
|
getRangeHeaderParameter(req, rangeStart, rangeStop, rangeStop);
|
||||||
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 devices
|
// Iterate over devices
|
||||||
Variant result = Variant::List();
|
Variant result = Variant::List();
|
||||||
@@ -177,17 +146,15 @@ void DeviceRepoHandler::__handleInfo(Poco::Net::HTTPServerRequest &req, Poco::Ne
|
|||||||
// There are no devices and a range was given, probably out of range
|
// There are no devices and a range was given, probably out of range
|
||||||
if (result.Size() == 0 && rangeStart > 0) {
|
if (result.Size() == 0 && rangeStart > 0) {
|
||||||
if (rangeStart > 0) {
|
if (rangeStart > 0) {
|
||||||
handleErrorResponse(req, resp, "Out of range", Poco::Net::HTTPResponse::HTTP_NOT_FOUND);
|
handleErrorResponse(req, resp, form, "Out of range", Poco::Net::HTTPResponse::HTTP_NOT_FOUND);
|
||||||
} else {
|
} else {
|
||||||
handleResponse(req, resp, result);
|
handleResponse(req, resp, form, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return devices array
|
// Return devices array
|
||||||
} else {
|
} else {
|
||||||
std::string rangeOut = (boost::format("items %1%-%2%/%3%") % rangeStart % rangeStop % devices.size()).str();
|
setRangeHeaderParameter(resp, rangeStart, rangeStop, devices.size());
|
||||||
resp.set("Content-Range", rangeOut);
|
handleResponse(req, resp, form, result);
|
||||||
resp.set("X-Content-Range", rangeOut);
|
|
||||||
handleResponse(req, resp, result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Single device mode
|
// Single device mode
|
||||||
@@ -206,17 +173,17 @@ void DeviceRepoHandler::__handleInfo(Poco::Net::HTTPServerRequest &req, Poco::Ne
|
|||||||
for (int i = matchPieces.size() + 2; i < pathPieces.size(); i++) {
|
for (int i = matchPieces.size() + 2; i < pathPieces.size(); i++) {
|
||||||
path << "/" << pathPieces[i];
|
path << "/" << pathPieces[i];
|
||||||
}
|
}
|
||||||
if (form->has("pointer")) {
|
std::string pointer;
|
||||||
auto tmp = form->get("pointer");
|
if (getPointerParameter(pointer, form)) {
|
||||||
if (tmp.size() > 0 && tmp[0] != '/') {
|
if (pointer.size() > 0 && pointer[0] != '/') {
|
||||||
path << "/";
|
path << "/";
|
||||||
}
|
}
|
||||||
path << tmp;
|
path << pointer;
|
||||||
}
|
}
|
||||||
// Get device info
|
// Get device info
|
||||||
Variant result = parent->getDeviceInfo(device.lock().get(), category, path.str());
|
Variant result = parent->getDeviceInfo(device.lock().get(), category, path.str());
|
||||||
// Return device info
|
// Return device info
|
||||||
handleResponse(req, resp, result);
|
handleResponse(req, resp, form, result);
|
||||||
} else {
|
} else {
|
||||||
throw webserver::webresource::WebResourceHandlerException((boost::format("Could not find device \"%1%\"") % devid).str(),
|
throw webserver::webresource::WebResourceHandlerException((boost::format("Could not find device \"%1%\"") % devid).str(),
|
||||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
||||||
@@ -225,17 +192,11 @@ void DeviceRepoHandler::__handleInfo(Poco::Net::HTTPServerRequest &req, Poco::Ne
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DeviceRepoHandler::__handleCommand(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, DeviceAPIMethod method) {
|
void DeviceRepoHandler::__handleCommand(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, DeviceAPIMethod method, Net::HTMLForm& form) {
|
||||||
std::vector<std::string> pathPieces, matchPieces;
|
std::vector<std::string> pathPieces, matchPieces;
|
||||||
matchUri.getPathSegments(matchPieces);
|
matchUri.getPathSegments(matchPieces);
|
||||||
Poco::URI uri(req.getURI());
|
Poco::URI uri(req.getURI());
|
||||||
uri.getPathSegments(pathPieces);
|
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
// No device given
|
// No device given
|
||||||
if (pathPieces.size() <= matchPieces.size()) {
|
if (pathPieces.size() <= matchPieces.size()) {
|
||||||
@@ -245,8 +206,8 @@ void DeviceRepoHandler::__handleCommand(Poco::Net::HTTPServerRequest &req, Poco:
|
|||||||
|
|
||||||
// Get message
|
// Get message
|
||||||
std::string msg;
|
std::string msg;
|
||||||
if (form->has("value")) {
|
if (form.has("value")) {
|
||||||
msg = form->get("value");
|
msg = form.get("value");
|
||||||
} else {
|
} else {
|
||||||
throw webserver::webresource::WebResourceHandlerException("API method requires a value.",
|
throw webserver::webresource::WebResourceHandlerException("API method requires a value.",
|
||||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
||||||
@@ -257,8 +218,9 @@ void DeviceRepoHandler::__handleCommand(Poco::Net::HTTPServerRequest &req, Poco:
|
|||||||
for (int i = matchPieces.size()+1; i < pathPieces.size(); i++) {
|
for (int i = matchPieces.size()+1; i < pathPieces.size(); i++) {
|
||||||
path.push_back(pathPieces[i]);
|
path.push_back(pathPieces[i]);
|
||||||
}
|
}
|
||||||
if (form->has("pointer")) {
|
std::string pointer;
|
||||||
URI pointer(form->get("pointer"));
|
if (getPointerParameter(pointer, form)) {
|
||||||
|
URI pointer(pointer);
|
||||||
pointer.getPathSegments(path);
|
pointer.getPathSegments(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,7 +231,7 @@ void DeviceRepoHandler::__handleCommand(Poco::Net::HTTPServerRequest &req, Poco:
|
|||||||
switch (method) {
|
switch (method) {
|
||||||
case DeviceAPIMethod::COMMAND:
|
case DeviceAPIMethod::COMMAND:
|
||||||
sendDeviceCommand(device.lock().get(), req, msg, path);
|
sendDeviceCommand(device.lock().get(), req, msg, path);
|
||||||
handleResponse(req, resp, std::string("OK: Command send"));
|
handleResponse(req, resp, form, std::string("OK: Command send"));
|
||||||
break;
|
break;
|
||||||
case DeviceAPIMethod::STATUSUPDATE:
|
case DeviceAPIMethod::STATUSUPDATE:
|
||||||
throw webserver::webresource::WebResourceHandlerException("ToDo: Implement method.");
|
throw webserver::webresource::WebResourceHandlerException("ToDo: Implement method.");
|
||||||
@@ -285,17 +247,11 @@ void DeviceRepoHandler::__handleCommand(Poco::Net::HTTPServerRequest &req, Poco:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void DeviceRepoHandler::__handleEvent(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, bool websocket) {
|
void DeviceRepoHandler::__handleEvent(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Net::HTMLForm& form, bool websocket) {
|
||||||
std::vector<std::string> pathPieces, matchPieces;
|
std::vector<std::string> pathPieces, matchPieces;
|
||||||
matchUri.getPathSegments(matchPieces);
|
matchUri.getPathSegments(matchPieces);
|
||||||
Poco::URI uri(req.getURI());
|
Poco::URI uri(req.getURI());
|
||||||
uri.getPathSegments(pathPieces);
|
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));
|
|
||||||
}
|
|
||||||
bool singleDeviceMode = true;
|
bool singleDeviceMode = true;
|
||||||
|
|
||||||
// No device given
|
// No device given
|
||||||
@@ -314,8 +270,8 @@ void DeviceRepoHandler::__handleEvent(Poco::Net::HTTPServerRequest &req, Poco::N
|
|||||||
// Get event type
|
// Get event type
|
||||||
std::string eventRaw;
|
std::string eventRaw;
|
||||||
DeviceEventType event = DeviceEventType::STATE_CHANGED;
|
DeviceEventType event = DeviceEventType::STATE_CHANGED;
|
||||||
if (form->has("onevent")) {
|
if (form.has("onevent")) {
|
||||||
eventRaw = form->get("onevent");
|
eventRaw = form.get("onevent");
|
||||||
} else if (req.has("On-Event")) {
|
} else if (req.has("On-Event")) {
|
||||||
eventRaw = req.get("On-Event");
|
eventRaw = req.get("On-Event");
|
||||||
} else if (req.has("X-On-Event")) {
|
} else if (req.has("X-On-Event")) {
|
||||||
@@ -343,8 +299,8 @@ void DeviceRepoHandler::__handleEvent(Poco::Net::HTTPServerRequest &req, Poco::N
|
|||||||
}
|
}
|
||||||
// Get client ID
|
// Get client ID
|
||||||
std::string clientID;
|
std::string clientID;
|
||||||
if (form->has("clientid")) {
|
if (form.has("clientid")) {
|
||||||
clientID = form->get("clientid");
|
clientID = form.get("clientid");
|
||||||
} else if (req.has("Client-Id")) {
|
} else if (req.has("Client-Id")) {
|
||||||
clientID = req.get("Client-Id");
|
clientID = req.get("Client-Id");
|
||||||
} else if (req.has("X-Client-Id")) {
|
} else if (req.has("X-Client-Id")) {
|
||||||
@@ -355,12 +311,12 @@ void DeviceRepoHandler::__handleEvent(Poco::Net::HTTPServerRequest &req, Poco::N
|
|||||||
for (int i = matchPieces.size() + 2; i < pathPieces.size(); i++) {
|
for (int i = matchPieces.size() + 2; i < pathPieces.size(); i++) {
|
||||||
path << "/" << pathPieces[i];
|
path << "/" << pathPieces[i];
|
||||||
}
|
}
|
||||||
if (form->has("pointer")) {
|
std::string pointer;
|
||||||
auto tmp = form->get("pointer");
|
if (getPointerParameter(pointer, form)) {
|
||||||
if (tmp.size() > 0 && tmp[0] != '/') {
|
if (pointer.size() > 0 && pointer[0] != '/') {
|
||||||
path << "/";
|
path << "/";
|
||||||
}
|
}
|
||||||
path << tmp;
|
path << pointer;
|
||||||
}
|
}
|
||||||
// Get event queue
|
// Get event queue
|
||||||
auto eventQueue = parent->getEventQueue(clientID, repoService);
|
auto eventQueue = parent->getEventQueue(clientID, repoService);
|
||||||
@@ -375,9 +331,9 @@ void DeviceRepoHandler::__handleEvent(Poco::Net::HTTPServerRequest &req, Poco::N
|
|||||||
}
|
}
|
||||||
eventQueue->checkRegistration(event, devptr, path.str());
|
eventQueue->checkRegistration(event, devptr, path.str());
|
||||||
if (websocket) {
|
if (websocket) {
|
||||||
__handleEventWebSocket(req, resp, eventQueue.get(), parent);
|
__handleEventWebSocket(req, resp, form, eventQueue.get(), parent);
|
||||||
} else {
|
} else {
|
||||||
__handleEventLongPolling(req, resp, eventQueue.get(), parent);
|
__handleEventLongPolling(req, resp, form, eventQueue.get(), parent);
|
||||||
}
|
}
|
||||||
eventQueue->unsetHandler();
|
eventQueue->unsetHandler();
|
||||||
} else {
|
} else {
|
||||||
@@ -534,18 +490,11 @@ void DeviceRepoHandler::sendDeviceCommand(devicerepository::Device* device, Net:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DeviceAPIMethod DeviceRepoHandler::getDeviceAPIMethod(Net::HTTPServerRequest &req) noexcept {
|
DeviceAPIMethod DeviceRepoHandler::getDeviceAPIMethod(Net::HTTPServerRequest &req, Net::HTMLForm& form) noexcept {
|
||||||
std::unique_ptr<Net::HTMLForm> form;
|
|
||||||
DeviceAPIMethod retval = DeviceAPIMethod::GET; // default
|
DeviceAPIMethod retval = DeviceAPIMethod::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;
|
std::string methodRaw;
|
||||||
if (form->has("method")) {
|
if (form.has("method")) {
|
||||||
methodRaw = form->get("method");
|
methodRaw = form.get("method");
|
||||||
} else if (req.has("API-Method")) {
|
} else if (req.has("API-Method")) {
|
||||||
methodRaw = req.get("API-Method");
|
methodRaw = req.get("API-Method");
|
||||||
} else if (req.has("X-API-Method")) {
|
} else if (req.has("X-API-Method")) {
|
||||||
@@ -565,7 +514,7 @@ DeviceAPIMethod DeviceRepoHandler::getDeviceAPIMethod(Net::HTTPServerRequest &re
|
|||||||
(boost::format("Unknown device api method \"%1%\"") % methodRaw).str(),
|
(boost::format("Unknown device api method \"%1%\"") % methodRaw).str(),
|
||||||
Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST );
|
Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST );
|
||||||
}
|
}
|
||||||
} else if (form->has("onevent") || req.has("On-Event") || req.has("X-On-Event")) {
|
} else if (form.has("onevent") || req.has("On-Event") || req.has("X-On-Event")) {
|
||||||
retval = DeviceAPIMethod::EVENT;
|
retval = DeviceAPIMethod::EVENT;
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
|
|||||||
+5
-5
@@ -115,20 +115,20 @@ public:
|
|||||||
bool ssl = false )
|
bool ssl = false )
|
||||||
: parent(parent), matchUri(matchUri), repoService(repoService), ssl(ssl) {}
|
: parent(parent), matchUri(matchUri), repoService(repoService), ssl(ssl) {}
|
||||||
|
|
||||||
virtual void _handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override;
|
virtual void _handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Poco::Net::HTMLForm& form) override;
|
||||||
|
|
||||||
void __handleInfo(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp);
|
void __handleInfo(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Poco::Net::HTMLForm& form);
|
||||||
|
|
||||||
void __handleCommand(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, DeviceAPIMethod method);
|
void __handleCommand(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, DeviceAPIMethod method, Poco::Net::HTMLForm& form);
|
||||||
|
|
||||||
void __handleEvent(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, bool websocket);
|
void __handleEvent(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Poco::Net::HTMLForm& form, bool websocket);
|
||||||
|
|
||||||
void sendDeviceCommand( devicerepository::Device* device,
|
void sendDeviceCommand( devicerepository::Device* device,
|
||||||
Poco::Net::HTTPServerRequest &req,
|
Poco::Net::HTTPServerRequest &req,
|
||||||
const std::string& cmd,
|
const std::string& cmd,
|
||||||
const std::vector<std::string>& path = std::vector<std::string>() );
|
const std::vector<std::string>& path = std::vector<std::string>() );
|
||||||
|
|
||||||
static DeviceAPIMethod getDeviceAPIMethod(Poco::Net::HTTPServerRequest &req) noexcept;
|
static DeviceAPIMethod getDeviceAPIMethod(Poco::Net::HTTPServerRequest &req, Poco::Net::HTMLForm& form) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
-306
@@ -1,306 +0,0 @@
|
|||||||
|
|
||||||
#include "DeviceRepoHandler.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>
|
|
||||||
|
|
||||||
|
|
||||||
// Service Namespace
|
|
||||||
namespace hos {
|
|
||||||
namespace cosgi {
|
|
||||||
namespace service {
|
|
||||||
namespace devicerepository {
|
|
||||||
namespace webresource {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
using namespace Poco;
|
|
||||||
using namespace libvariant;
|
|
||||||
|
|
||||||
|
|
||||||
HOS_SERVICE_IMPL_INFO( DeviceRepoHandlerFactory, // Implementation
|
|
||||||
service::webserver::WebResourceHandlerFactory::SERVICE_NAME, // Service Name
|
|
||||||
1, 0 ) // Version
|
|
||||||
|
|
||||||
|
|
||||||
DeviceRepoHandlerFactory::DeviceRepoHandlerFactory(devicerepository::DeviceRepositoryService* repoService)
|
|
||||||
: repoService(repoService) {
|
|
||||||
infoCategoryFuncs.insert({"id", [](Poco::URI& matchUri, devicerepository::Device* device, Poco::Net::HTTPServerRequest &req, const std::string& category, bool ssl)->Variant {
|
|
||||||
return device->getDeviceID();
|
|
||||||
} });
|
|
||||||
|
|
||||||
infoCategoryFuncs.insert({"type", [](Poco::URI& matchUri, devicerepository::Device* device, Poco::Net::HTTPServerRequest &req, const std::string& category, bool ssl)->Variant {
|
|
||||||
return device->getDeviceType();
|
|
||||||
} });
|
|
||||||
|
|
||||||
infoCategoryFuncs.insert({"status_topic", [](Poco::URI& matchUri, devicerepository::Device* device, Poco::Net::HTTPServerRequest &req, const std::string& category, bool ssl)->Variant {
|
|
||||||
return device->getStatusTopic();
|
|
||||||
} });
|
|
||||||
|
|
||||||
infoCategoryFuncs.insert({"command_topic", [](Poco::URI& matchUri, devicerepository::Device* device, Poco::Net::HTTPServerRequest &req, const std::string& category, bool ssl)->Variant {
|
|
||||||
return device->getCmdTopic();
|
|
||||||
} });
|
|
||||||
|
|
||||||
infoCategoryFuncs.insert({"current_state", [](Poco::URI& matchUri, devicerepository::Device* device, Poco::Net::HTTPServerRequest &req, const std::string& category, bool ssl)->Variant {
|
|
||||||
auto retval = device->getCurrentState();
|
|
||||||
if (retval.IsMap()) {
|
|
||||||
retval["timestamp"] = utils::timestamp_to_ISO8601(device->getCurrentStateTimestamp());
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
} });
|
|
||||||
|
|
||||||
infoCategoryFuncs.insert({"last_state", [](Poco::URI& matchUri, devicerepository::Device* device, Poco::Net::HTTPServerRequest &req, const std::string& category, bool ssl)->Variant {
|
|
||||||
auto retval = device->getLastState();
|
|
||||||
if (retval.IsMap()) {
|
|
||||||
retval["timestamp"] = utils::timestamp_to_ISO8601(device->getLastStateTimestamp());
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
} });
|
|
||||||
|
|
||||||
infoCategoryFuncs.insert({"uri", [=](Poco::URI& matchUri, devicerepository::Device* device, Poco::Net::HTTPServerRequest &req, const std::string& category, bool ssl)->Variant {
|
|
||||||
std::stringstream ss;
|
|
||||||
if (ssl) {
|
|
||||||
ss << "https://";
|
|
||||||
} else {
|
|
||||||
ss << "http://";
|
|
||||||
}
|
|
||||||
ss << req.getHost() << matchUri.toString() << device->getDeviceID();
|
|
||||||
return ss.str();
|
|
||||||
} });
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DeviceAPIMethod DeviceRepoHandlerFactory::getDeviceAPIMethod() noexcept {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*std::shared_ptr<DeviceEventQueue> DeviceRepoHandlerFactory::getDeviceEventQueue(std::string clientID) {
|
|
||||||
if (clientID.empty()) {
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
|
|
||||||
Net::HTTPRequestHandler* DeviceRepoHandlerFactory::createRequestHandler( Poco::URI matchUri, const Net::HTTPServerRequest& request, bool ssl ) noexcept {
|
|
||||||
if(request.find("Upgrade") != request.end() && Poco::icompare(request["Upgrade"], "websocket") == 0)
|
|
||||||
return new DeviceRepoEventWebSocketHandler(matchUri, repoService, infoCategoryFuncs, ssl);
|
|
||||||
else {
|
|
||||||
DeviceAPIMethod method = getDeviceAPIMethod();
|
|
||||||
if (method == DeviceAPIMethod::EVENT) {
|
|
||||||
return new DeviceRepoEventLongPollingHandler(matchUri, repoService, infoCategoryFuncs, ssl);
|
|
||||||
} else {
|
|
||||||
return new DeviceRepoInfoHandler(matchUri, method, repoService, infoCategoryFuncs, ssl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Variant DeviceRepoHandlerBase::getDeviceInfo(devicerepository::Device* device, Net::HTTPServerRequest &req, const std::string& category, const std::vector<std::string>& path) {
|
|
||||||
Variant retval;
|
|
||||||
|
|
||||||
// We want all info categories
|
|
||||||
if (category.empty()) {
|
|
||||||
for (auto c : infoCategoryFuncs) {
|
|
||||||
retval[c.first] = c.second(matchUri, device, req, category, ssl);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We want a single info category
|
|
||||||
} else {
|
|
||||||
auto c = infoCategoryFuncs.find(category);
|
|
||||||
if (c != infoCategoryFuncs.end()) {
|
|
||||||
retval = c->second(matchUri, device, req, category, ssl);
|
|
||||||
if (path.size() > 0) {
|
|
||||||
std::stringstream ss;
|
|
||||||
for (auto p : path) {
|
|
||||||
ss << "/" << p;
|
|
||||||
}
|
|
||||||
std::string pathstr = ss.str();
|
|
||||||
if (retval.HasPath(pathstr)) {
|
|
||||||
retval = retval.GetPath(pathstr);
|
|
||||||
} else {
|
|
||||||
throw webserver::webresource::WebResourceHandlerException((boost::format("Unknown path \"%1%\" for device info category \"%2%\".") % pathstr % category).str(),
|
|
||||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw webserver::webresource::WebResourceHandlerException((boost::format("Unknown device info category \"%1%\"") % category).str(),
|
|
||||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void DeviceRepoHandlerBase::sendDeviceCommand(devicerepository::Device* device, Net::HTTPServerRequest &req, const std::string& cmd, const std::vector<std::string>& path) {
|
|
||||||
Variant cmdMsg;
|
|
||||||
VariantRef mPart = cmdMsg.Ref();
|
|
||||||
if (path.size() > 0) {
|
|
||||||
for (int i = 0; i < path.size(); i++) {
|
|
||||||
mPart[path[i]] = Variant();
|
|
||||||
mPart.ReassignRef(mPart[path[i]]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* The libvariant json deserializer knows nothing about RFC 7159, therefore non-object or non-array values are rejected.
|
|
||||||
* As a workaround we use the yaml deserializer (yaml can be considered a super-set of json).
|
|
||||||
* Fun fact: the json serializer accepts non-object or non-array values.
|
|
||||||
*/
|
|
||||||
//mPart = DeserializeJSON(cmd);
|
|
||||||
mPart = DeserializeYAML(cmd);
|
|
||||||
device->sendCommand(cmdMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void DeviceRepoInfoHandler::__handle(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Net::HTMLForm& form) {
|
|
||||||
|
|
||||||
std::string methodValue;
|
|
||||||
if (method == DeviceAPIMethod::COMMAND || method == DeviceAPIMethod::STATUSUPDATE) {
|
|
||||||
if (form.has("value")) {
|
|
||||||
methodValue = form.get("value");
|
|
||||||
} else {
|
|
||||||
throw webserver::webresource::WebResourceHandlerException("API method requires a value parameter.",
|
|
||||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> pathPieces, matchPieces;
|
|
||||||
matchUri.getPathSegments(matchPieces);
|
|
||||||
Poco::URI uri(req.getURI());
|
|
||||||
uri.getPathSegments(pathPieces);
|
|
||||||
|
|
||||||
// No device given
|
|
||||||
if (pathPieces.size() <= matchPieces.size()) {
|
|
||||||
if (method != DeviceAPIMethod::GET) {
|
|
||||||
throw webserver::webresource::WebResourceHandlerException("Requested API method requires a device",
|
|
||||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto devices = repoService->getDevices();
|
|
||||||
|
|
||||||
// Range header parameter
|
|
||||||
std::string rangeRaw;
|
|
||||||
size_t rangeStart = 0;
|
|
||||||
size_t rangeStop = devices.size() - 1;
|
|
||||||
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 << "\".");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
Variant result = Variant::List();
|
|
||||||
for (size_t t = rangeStart; t <= rangeStop; t++) {
|
|
||||||
auto dev = devices[t].lock();
|
|
||||||
result.Append(getDeviceInfo(dev.get(), req));
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
std::string rangeOut = (boost::format("items %1%-%2%/%3%") % rangeStart % rangeStop % devices.size()).str();
|
|
||||||
resp.set("Content-Range", rangeOut);
|
|
||||||
resp.set("X-Content-Range", rangeOut);
|
|
||||||
handleResponse(req, resp, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Device given
|
|
||||||
} else {
|
|
||||||
std::string devid = pathPieces[matchPieces.size()];
|
|
||||||
auto device = repoService->getDevice(devid);
|
|
||||||
if (!device.expired()) {
|
|
||||||
switch (method) {
|
|
||||||
case DeviceAPIMethod::GET:
|
|
||||||
{
|
|
||||||
std::string category;
|
|
||||||
if (pathPieces.size() > matchPieces.size() + 1) {
|
|
||||||
category = pathPieces[matchPieces.size() + 1];
|
|
||||||
}
|
|
||||||
std::vector<std::string> path;
|
|
||||||
for (int i = matchPieces.size() + 2; i < pathPieces.size(); i++) {
|
|
||||||
path.push_back(pathPieces[i]);
|
|
||||||
}
|
|
||||||
Variant result = getDeviceInfo(device.lock().get(), req, category, path);
|
|
||||||
handleResponse(req, resp, result);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DeviceAPIMethod::COMMAND:
|
|
||||||
{
|
|
||||||
std::vector<std::string> path;
|
|
||||||
for (int i = matchPieces.size()+1; i < pathPieces.size(); i++) {
|
|
||||||
path.push_back(pathPieces[i]);
|
|
||||||
}
|
|
||||||
sendDeviceCommand(device.lock().get(), req, methodValue, path);
|
|
||||||
handleResponse(req, resp, std::string("OK: Command send"));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DeviceAPIMethod::STATUSUPDATE:
|
|
||||||
throw webserver::webresource::WebResourceHandlerException("ToDo: Implement method.");
|
|
||||||
default:
|
|
||||||
throw webserver::webresource::WebResourceHandlerException("Internal Server Error");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw webserver::webresource::WebResourceHandlerException((boost::format("Could not find device \"%1%\"") % devid).str(),
|
|
||||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void DeviceRepoInfoHandler::_handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
|
||||||
Net::HTMLForm form(req);
|
|
||||||
__handle(req, resp, form);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeviceRepoInfoHandler::_handlePOST(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
|
||||||
Net::HTMLForm form(req, req.stream());
|
|
||||||
__handle(req, resp, form);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace resources
|
|
||||||
} // namespace webserver
|
|
||||||
} // namespace service
|
|
||||||
} // namespace cosgi
|
|
||||||
} // namespace hos
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-250
@@ -1,250 +0,0 @@
|
|||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
#include <hos/cosgi/service/Implementation.h>
|
|
||||||
#include <hos/cosgi/service/webserver/WebServerService.h>
|
|
||||||
#include <hos/cosgi/service/webserver/webresource/WebResourceHandlerImpl.h>
|
|
||||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
|
||||||
#include <Poco/Net/HTTPRequestHandler.h>
|
|
||||||
#include <Variant/Variant.h>
|
|
||||||
#include <ros/ros.h>
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <queue>
|
|
||||||
#include <memory>
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Service Namespace
|
|
||||||
namespace hos {
|
|
||||||
namespace cosgi {
|
|
||||||
namespace service {
|
|
||||||
namespace devicerepository {
|
|
||||||
namespace webresource {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enum class DeviceAPIMethod {
|
|
||||||
GET,
|
|
||||||
COMMAND,
|
|
||||||
STATUSUPDATE,
|
|
||||||
EVENT
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class DeviceEventQueue
|
|
||||||
: public virtual interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent> {
|
|
||||||
public:
|
|
||||||
const std::string clientID;
|
|
||||||
DeviceRepositoryService* const repoService;
|
|
||||||
DeviceEventType eventType;
|
|
||||||
Device* device;
|
|
||||||
std::string pointer;
|
|
||||||
std::queue<libvariant::Variant> eventQueue;
|
|
||||||
size_t openConnectionCount = 0;
|
|
||||||
|
|
||||||
DeviceEventQueue( const std::string& clientID,
|
|
||||||
const DeviceEventType eventType,
|
|
||||||
DeviceRepositoryService* repoService,
|
|
||||||
Device* device,
|
|
||||||
std::string pointer )
|
|
||||||
: clientID(clientID), eventType(eventType), repoService(repoService), device(device), pointer(pointer) {}
|
|
||||||
|
|
||||||
virtual void notificationReceived( interface::Observer<devicerepository::DeviceEventType,
|
|
||||||
devicerepository::DeviceEvent>::observable_type* o,
|
|
||||||
const devicerepository::DeviceEventType& key,
|
|
||||||
const devicerepository::DeviceEvent* e) noexcept override {
|
|
||||||
if (eventType == DeviceEventType::ALL_EVENTS || eventType == key) {
|
|
||||||
switch (key) {
|
|
||||||
case devicerepository::DeviceEventType::COMMAND_RECEIVED:
|
|
||||||
break;
|
|
||||||
case devicerepository::DeviceEventType::STATUS_UPDATE_RECEIVED:
|
|
||||||
break;
|
|
||||||
case devicerepository::DeviceEventType::STATE_CHANGED:
|
|
||||||
break;
|
|
||||||
case devicerepository::DeviceEventType::DEVICE_ADDED:
|
|
||||||
break;
|
|
||||||
case devicerepository::DeviceEventType::DEVICE_REMOVED:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DeviceRepoHandlerFactory
|
|
||||||
: public virtual webserver::WebResourceHandlerFactory,
|
|
||||||
public implementation::Service<DeviceRepoHandlerFactory> {
|
|
||||||
public:
|
|
||||||
typedef std::function<libvariant::Variant( Poco::URI& matchUri,
|
|
||||||
devicerepository::Device* device,
|
|
||||||
Poco::Net::HTTPServerRequest &req,
|
|
||||||
const std::string& category,
|
|
||||||
bool ssl )> infoCategoryFunc_t;
|
|
||||||
private:
|
|
||||||
webserver::WebServerService* service = nullptr;
|
|
||||||
DeviceRepositoryService* repoService;
|
|
||||||
std::map<std::string, infoCategoryFunc_t> infoCategoryFuncs;
|
|
||||||
std::map<std::string, std::shared_ptr<DeviceEventQueue>> deviceEventQueues;
|
|
||||||
|
|
||||||
public:
|
|
||||||
DeviceRepoHandlerFactory(devicerepository::DeviceRepositoryService* repoService);
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool excludeFromAuthentication() noexcept override {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static DeviceAPIMethod getDeviceAPIMethod() noexcept;
|
|
||||||
|
|
||||||
std::shared_ptr<DeviceEventQueue> getDeviceEventQueue( const std::string& clientID,
|
|
||||||
const DeviceEventType eventType,
|
|
||||||
DeviceRepositoryService* repoService,
|
|
||||||
Device* device,
|
|
||||||
std::string pointer );
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements a REST API for accessing the device repository and getting info about a device.
|
|
||||||
*
|
|
||||||
* HTTP GET REQUESTS:
|
|
||||||
* 1. http://[prefixPath]/devices - Returns all known devices
|
|
||||||
* 2. http://[prefixPath]/devices/[deviceID] - Returns complete info about the given device as JSON object.
|
|
||||||
* 3. http://[prefixPath]/devices/[deviceID]/[infoCategory]/[infoPath] - Returns selected info about the given device as JSON object ([infoCategory]/[infoPath] is treated as JSON Path selecting parts of the complete JSON info object from 1).
|
|
||||||
* 4. http://[prefixPath]/devices/[deviceID]/[cmdPath]?method=command&value=[cmdValue] - Sends the command [cmdPath]/[cmdValue] to the given device.
|
|
||||||
* 5. http://[prefixPath]/devices/[deviceID]/[statusPath]?method=statusupdate&value=[statusValue] - Sends the status update [statusPath]/[statusValue] to the given device (Only useful for virtual devices).
|
|
||||||
*
|
|
||||||
* HTTP POST REQUESTS (content-type: application/x-www-form-urlencoded):
|
|
||||||
* - Basically the same as 4 and 5 from the HTTP GET REQUESTS list, but parameters are transmitted in the request body instead of the URL.
|
|
||||||
*
|
|
||||||
* HTTP POST REQUESTS (content-type: application/json):
|
|
||||||
* - http://[prefixPath]/devices/[deviceID]/[method]/[methodPath] - Semantically the same as 4 and 5 from the HTTP GET REQUESTS list, but the method parameter is part of the URL and the request body only contains a single JSON text.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* A note about JSON object returned by the above URLs: According to RFC 4627 a JSON text is a serialized object or array.
|
|
||||||
* This was later relaxed by RFC 7159 which defines that a JSON text is a serialized value. Our API adheres to RFC 7159 and may return
|
|
||||||
* JSON texts (namely single strings, numbers or boolean values) that are not valid JSON texts according to RFC 4627.
|
|
||||||
* Keep in mind that there are still a lot of JSON libraries and validators out there which still no nothing about RFC 7159.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class DeviceRepoHandlerBase
|
|
||||||
: public webserver::webresource::WebResourceHandlerImpl {
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Poco::URI matchUri;
|
|
||||||
devicerepository::DeviceRepositoryService* repoService;
|
|
||||||
const std::map<std::string, DeviceRepoHandlerFactory::infoCategoryFunc_t>& infoCategoryFuncs;
|
|
||||||
bool ssl;
|
|
||||||
|
|
||||||
libvariant::Variant getDeviceInfo( devicerepository::Device* device,
|
|
||||||
Poco::Net::HTTPServerRequest &req,
|
|
||||||
const std::string& category = std::string(),
|
|
||||||
const std::vector<std::string>& path = std::vector<std::string>() );
|
|
||||||
|
|
||||||
void sendDeviceCommand( devicerepository::Device* device,
|
|
||||||
Poco::Net::HTTPServerRequest &req,
|
|
||||||
const std::string& cmd,
|
|
||||||
const std::vector<std::string>& path = std::vector<std::string>() );
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
DeviceRepoHandlerBase( Poco::URI matchUri,
|
|
||||||
devicerepository::DeviceRepositoryService* repoService,
|
|
||||||
const std::map<std::string, DeviceRepoHandlerFactory::infoCategoryFunc_t>& infoCategoryFuncs,
|
|
||||||
bool ssl = false )
|
|
||||||
: matchUri(matchUri), repoService(repoService), infoCategoryFuncs(infoCategoryFuncs), ssl(ssl) {}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DeviceRepoInfoHandler
|
|
||||||
: public DeviceRepoHandlerBase {
|
|
||||||
|
|
||||||
protected:
|
|
||||||
DeviceAPIMethod method;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
DeviceRepoInfoHandler( Poco::URI matchUri,
|
|
||||||
DeviceAPIMethod method,
|
|
||||||
devicerepository::DeviceRepositoryService* repoService,
|
|
||||||
const std::map<std::string, DeviceRepoHandlerFactory::infoCategoryFunc_t>& infoCategoryFuncs,
|
|
||||||
bool ssl = false )
|
|
||||||
: DeviceRepoHandlerBase(matchUri, repoService, infoCategoryFuncs, ssl), method(method) {}
|
|
||||||
|
|
||||||
virtual void _handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override;
|
|
||||||
|
|
||||||
virtual void _handlePOST(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override;
|
|
||||||
|
|
||||||
virtual void __handle(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Poco::Net::HTMLForm& form);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DeviceRepoEventLongPollingHandler
|
|
||||||
: public DeviceRepoHandlerBase {
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
DeviceRepoEventLongPollingHandler( Poco::URI matchUri,
|
|
||||||
devicerepository::DeviceRepositoryService* repoService,
|
|
||||||
const std::map<std::string, DeviceRepoHandlerFactory::infoCategoryFunc_t>& infoCategoryFuncs,
|
|
||||||
bool ssl = false )
|
|
||||||
: DeviceRepoHandlerBase(matchUri, repoService, infoCategoryFuncs, ssl) {}
|
|
||||||
|
|
||||||
virtual void _handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override;
|
|
||||||
|
|
||||||
virtual void _handlePOST(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DeviceRepoEventWebSocketHandler
|
|
||||||
: public DeviceRepoHandlerBase {
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
DeviceRepoEventWebSocketHandler( Poco::URI matchUri,
|
|
||||||
devicerepository::DeviceRepositoryService* repoService,
|
|
||||||
const std::map<std::string, DeviceRepoHandlerFactory::infoCategoryFunc_t>& infoCategoryFuncs,
|
|
||||||
bool ssl = false )
|
|
||||||
: DeviceRepoHandlerBase(matchUri, repoService, infoCategoryFuncs, ssl) {}
|
|
||||||
|
|
||||||
virtual void _handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override;
|
|
||||||
|
|
||||||
virtual void _handlePOST(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace webresource
|
|
||||||
} // namespace devicerepository
|
|
||||||
} // namespace service
|
|
||||||
} // namespace cosgi
|
|
||||||
} // namespace hos
|
|
||||||
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
x) Rule engine infos:
|
||||||
|
======================
|
||||||
|
http[s]://hos/api/<rule-engine-name>/
|
||||||
|
|
||||||
|
x) Rule package infos:
|
||||||
|
======================
|
||||||
|
http[s]://hos/api/<rule-engine-name>/packages
|
||||||
|
http[s]://hos/api/<rule-engine-name>/packages/<package-name>
|
||||||
|
|
||||||
|
x) Rule infos:
|
||||||
|
======================
|
||||||
|
http[s]://hos/api/<rule-engine-name>/packages/<package-name>/rules
|
||||||
|
http[s]://hos/api/<rule-engine-name>/packages/<package-name>/rules/<rule-name>
|
||||||
|
|
||||||
|
|
||||||
+2
@@ -129,6 +129,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual size_t getRulePackageCount() noexcept = 0;
|
virtual size_t getRulePackageCount() noexcept = 0;
|
||||||
|
|
||||||
|
virtual std::string getName() noexcept = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a rule condition factory under the given type identifier.
|
* Registers a rule condition factory under the given type identifier.
|
||||||
*
|
*
|
||||||
|
|||||||
+2
@@ -132,6 +132,8 @@ public:
|
|||||||
virtual void conditionStateChanged(bool newState, const conditions::ConditionTriggerType& trigger,
|
virtual void conditionStateChanged(bool newState, const conditions::ConditionTriggerType& trigger,
|
||||||
const libvariant::Variant& lcontext = libvariant::Variant()) noexcept = 0;
|
const libvariant::Variant& lcontext = libvariant::Variant()) noexcept = 0;
|
||||||
|
|
||||||
|
virtual libvariant::Variant getConditionJSONRepresentation() = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
@@ -116,6 +116,8 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual void setCompositeParent(RuleCompositeCondition* compositeParent) noexcept = 0;
|
virtual void setCompositeParent(RuleCompositeCondition* compositeParent) noexcept = 0;
|
||||||
|
|
||||||
|
virtual libvariant::Variant getJSONRepresentation() = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+21
-4
@@ -55,12 +55,14 @@ protected:
|
|||||||
RuleCompositeCondition* compositeParent = nullptr;
|
RuleCompositeCondition* compositeParent = nullptr;
|
||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
|
|
||||||
|
libvariant::Variant jsonRepresentation;
|
||||||
|
|
||||||
void notifyStateChangeToParent(bool newState, ConditionTriggerType category, const libvariant::Variant& lcontext = libvariant::Variant());
|
void notifyStateChangeToParent(bool newState, ConditionTriggerType category, const libvariant::Variant& lcontext = libvariant::Variant());
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RuleConditionImpl(rules::Rule* parent, ConditionTriggerType triggerType, const std::string& type) :
|
RuleConditionImpl(rules::Rule* parent, ConditionTriggerType triggerType, const std::string& type, const libvariant::Variant& jsonRepresentation) :
|
||||||
parent(parent), triggerType(triggerType), type(type) {}
|
parent(parent), triggerType(triggerType), type(type), jsonRepresentation(jsonRepresentation) {}
|
||||||
|
|
||||||
virtual rules::Rule* getParent() noexcept override {
|
virtual rules::Rule* getParent() noexcept override {
|
||||||
return parent;
|
return parent;
|
||||||
@@ -94,6 +96,10 @@ public:
|
|||||||
this->enabled;
|
this->enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual libvariant::Variant getJSONRepresentation() override {
|
||||||
|
return jsonRepresentation;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -110,8 +116,10 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
RuleCompositeConditionImpl(Rule* parent, ConditionTriggerType category, std::string type) :
|
RuleCompositeConditionImpl(Rule* parent, ConditionTriggerType category, std::string type, const libvariant::Variant& jsonRepresentation) :
|
||||||
RuleConditionImpl(parent, category, type) {}
|
RuleConditionImpl(parent, category, type, jsonRepresentation) {
|
||||||
|
this->jsonRepresentation.Erase("conditions");
|
||||||
|
}
|
||||||
|
|
||||||
virtual void childStateChanged( RuleCondition* child,
|
virtual void childStateChanged( RuleCondition* child,
|
||||||
bool newState,
|
bool newState,
|
||||||
@@ -133,6 +141,15 @@ public:
|
|||||||
this->enabled = enabled;
|
this->enabled = enabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual libvariant::Variant getJSONRepresentation() override {
|
||||||
|
libvariant::Variant tmp = jsonRepresentation.Copy();
|
||||||
|
tmp["conditions"] = libvariant::Variant::List();
|
||||||
|
for (auto c : children) {
|
||||||
|
tmp["conditions"].Append(c->getJSONRepresentation());
|
||||||
|
}
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,8 @@ void RuleEngineServiceImpl::setRepoService(devicerepository::DeviceRepositorySer
|
|||||||
|
|
||||||
void RuleEngineServiceImpl::init() noexcept {
|
void RuleEngineServiceImpl::init() noexcept {
|
||||||
// Get public parameters
|
// Get public parameters
|
||||||
nodehandle->getParam("ruleengine_prefix", ruleEnginePrefix);
|
nodehandle->getParam("hos_param_prefix", hosParamPrefix);
|
||||||
|
nodehandle->getParam("ruleengine_name", engineName);
|
||||||
|
|
||||||
// Register condition factories
|
// Register condition factories
|
||||||
registerRuleConditionFactory("logical_or", std::make_shared<rules::conditions::LogicalOrConditionFactory>());
|
registerRuleConditionFactory("logical_or", std::make_shared<rules::conditions::LogicalOrConditionFactory>());
|
||||||
@@ -77,7 +78,9 @@ void RuleEngineServiceImpl::init() noexcept {
|
|||||||
|
|
||||||
// Create rule packages
|
// Create rule packages
|
||||||
XmlRpc::XmlRpcValue rawValue;
|
XmlRpc::XmlRpcValue rawValue;
|
||||||
nodehandle->getParam(ruleEnginePrefix, rawValue);
|
std::stringstream ss;
|
||||||
|
ss << hosParamPrefix << "/" << engineName;
|
||||||
|
nodehandle->getParam(ss.str(), rawValue);
|
||||||
if (rawValue.getType() == XmlRpc::XmlRpcValue::TypeStruct) {
|
if (rawValue.getType() == XmlRpc::XmlRpcValue::TypeStruct) {
|
||||||
for (auto pkg : rawValue) {
|
for (auto pkg : rawValue) {
|
||||||
std::string pname = pkg.first;
|
std::string pname = pkg.first;
|
||||||
@@ -98,7 +101,7 @@ void RuleEngineServiceImpl::init() noexcept {
|
|||||||
|
|
||||||
void RuleEngineServiceImpl::addRulePkg(const std::string& name) {
|
void RuleEngineServiceImpl::addRulePkg(const std::string& name) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << ruleEnginePrefix << "/" << name;
|
ss << hosParamPrefix << "/" << engineName << "/" << name;
|
||||||
XmlRpc::XmlRpcValue rawValue;
|
XmlRpc::XmlRpcValue rawValue;
|
||||||
nodehandle->getParam(ss.str(), rawValue);
|
nodehandle->getParam(ss.str(), rawValue);
|
||||||
addRulePkg(name, static_cast<std::string>(rawValue));
|
addRulePkg(name, static_cast<std::string>(rawValue));
|
||||||
|
|||||||
@@ -74,7 +74,8 @@ private:
|
|||||||
devicerepository::DeviceRepositoryService* repoService = nullptr;
|
devicerepository::DeviceRepositoryService* repoService = nullptr;
|
||||||
ros::NodeHandle* nodehandle = nullptr;
|
ros::NodeHandle* nodehandle = nullptr;
|
||||||
|
|
||||||
std::string ruleEnginePrefix = "/hos/rules/ruleengine0";
|
std::string hosParamPrefix = "/hos/rules";
|
||||||
|
std::string engineName = "ruleengine0";
|
||||||
|
|
||||||
rulePkgMap_t rulePkgs;
|
rulePkgMap_t rulePkgs;
|
||||||
rulePkgMap_t noExecRulePkgs;
|
rulePkgMap_t noExecRulePkgs;
|
||||||
@@ -110,6 +111,10 @@ public:
|
|||||||
|
|
||||||
virtual size_t getRulePackageCount() noexcept override;
|
virtual size_t getRulePackageCount() noexcept override;
|
||||||
|
|
||||||
|
virtual std::string getName() noexcept override {
|
||||||
|
return engineName;
|
||||||
|
}
|
||||||
|
|
||||||
virtual devicerepository::DeviceRepositoryService* getDeviceRepository() noexcept override {
|
virtual devicerepository::DeviceRepositoryService* getDeviceRepository() noexcept override {
|
||||||
return repoService;
|
return repoService;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,6 +93,10 @@ public:
|
|||||||
|
|
||||||
std::shared_ptr<conditions::RuleCondition> createRuleCondition(const Variant& raw) override;
|
std::shared_ptr<conditions::RuleCondition> createRuleCondition(const Variant& raw) override;
|
||||||
|
|
||||||
|
virtual Variant getConditionJSONRepresentation() override {
|
||||||
|
return condition->getJSONRepresentation();
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+6
-3
@@ -95,7 +95,8 @@ std::shared_ptr<RuleCondition> DeviceStatusMsgConditionFactory::createCondition(
|
|||||||
if (raw.HasPath("msgvalue")) {
|
if (raw.HasPath("msgvalue")) {
|
||||||
msgValue = raw["msgvalue"];
|
msgValue = raw["msgvalue"];
|
||||||
}
|
}
|
||||||
retval = std::make_shared<DeviceStatusMsgCondition>(parent, deviceID, msgPointer, msgValue);
|
Variant rep = raw.Copy();
|
||||||
|
retval = std::make_shared<DeviceStatusMsgCondition>(parent, deviceID, msgPointer, msgValue, rep);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +155,8 @@ std::shared_ptr<RuleCondition> DeviceCommandMsgConditionFactory::createCondition
|
|||||||
if (raw.HasPath("msgvalue")) {
|
if (raw.HasPath("msgvalue")) {
|
||||||
msgValue = raw["msgvalue"];
|
msgValue = raw["msgvalue"];
|
||||||
}
|
}
|
||||||
retval = std::make_shared<DeviceCommandMsgCondition>(parent, deviceID, msgPointer, msgValue);
|
Variant rep = raw.Copy();
|
||||||
|
retval = std::make_shared<DeviceCommandMsgCondition>(parent, deviceID, msgPointer, msgValue, rep);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,7 +219,8 @@ std::shared_ptr<RuleCondition> DeviceStateChangeConditionFactory::createConditio
|
|||||||
if (raw.HasPath("tovalue")) {
|
if (raw.HasPath("tovalue")) {
|
||||||
toValue = raw["tovalue"];
|
toValue = raw["tovalue"];
|
||||||
}
|
}
|
||||||
retval = std::make_shared<DeviceStateChangeCondition>(parent, deviceID, statePointer, fromValue, toValue);
|
Variant rep = raw.Copy();
|
||||||
|
retval = std::make_shared<DeviceStateChangeCondition>(parent, deviceID, statePointer, fromValue, toValue, rep);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-8
@@ -41,8 +41,9 @@ public:
|
|||||||
const std::string& deviceID,
|
const std::string& deviceID,
|
||||||
const std::string& msgPointer,
|
const std::string& msgPointer,
|
||||||
const Variant& msgValue,
|
const Variant& msgValue,
|
||||||
const std::set<devicerepository::DeviceEventType> _listenerKeys )
|
const std::set<devicerepository::DeviceEventType> _listenerKeys,
|
||||||
: RuleConditionImpl(parent, category, type), deviceID(deviceID),
|
const libvariant::Variant& jsonRepresentation)
|
||||||
|
: RuleConditionImpl(parent, category, type, jsonRepresentation), deviceID(deviceID),
|
||||||
msgPointer(msgPointer), msgValue(msgValue), _listenerKeys(_listenerKeys) {}
|
msgPointer(msgPointer), msgValue(msgValue), _listenerKeys(_listenerKeys) {}
|
||||||
|
|
||||||
virtual void notificationReceived( interface::Observer<devicerepository::DeviceEventType,
|
virtual void notificationReceived( interface::Observer<devicerepository::DeviceEventType,
|
||||||
@@ -62,9 +63,10 @@ public:
|
|||||||
DeviceStatusMsgCondition( Rule* parent,
|
DeviceStatusMsgCondition( Rule* parent,
|
||||||
const std::string& deviceID,
|
const std::string& deviceID,
|
||||||
const std::string& msgPointer,
|
const std::string& msgPointer,
|
||||||
const Variant& msgValue)
|
const Variant& msgValue,
|
||||||
|
const libvariant::Variant& jsonRepresentation)
|
||||||
: DeviceMsgCondition(parent, ConditionTriggerType::Event, "devicestatusmsg", deviceID,
|
: DeviceMsgCondition(parent, ConditionTriggerType::Event, "devicestatusmsg", deviceID,
|
||||||
msgPointer, msgValue, {devicerepository::DeviceEventType::STATUS_UPDATE_RECEIVED}) {}
|
msgPointer, msgValue, {devicerepository::DeviceEventType::STATUS_UPDATE_RECEIVED}, jsonRepresentation) {}
|
||||||
|
|
||||||
virtual void notificationReceived( interface::Observer<devicerepository::DeviceEventType,
|
virtual void notificationReceived( interface::Observer<devicerepository::DeviceEventType,
|
||||||
devicerepository::DeviceEvent>::observable_type* o,
|
devicerepository::DeviceEvent>::observable_type* o,
|
||||||
@@ -86,9 +88,9 @@ class DeviceCommandMsgCondition
|
|||||||
: public DeviceMsgCondition {
|
: public DeviceMsgCondition {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DeviceCommandMsgCondition(Rule* parent, const std::string deviceID, const std::string msgPointer, const Variant msgValue)
|
DeviceCommandMsgCondition(Rule* parent, const std::string deviceID, const std::string msgPointer, const Variant msgValue, const libvariant::Variant& jsonRepresentation)
|
||||||
: DeviceMsgCondition(parent, ConditionTriggerType::Event, "devicecommandmsg", deviceID,
|
: DeviceMsgCondition(parent, ConditionTriggerType::Event, "devicecommandmsg", deviceID,
|
||||||
msgPointer, msgValue, {devicerepository::DeviceEventType::COMMAND_RECEIVED}) {}
|
msgPointer, msgValue, {devicerepository::DeviceEventType::COMMAND_RECEIVED}, jsonRepresentation) {}
|
||||||
|
|
||||||
virtual void notificationReceived( interface::Observer<devicerepository::DeviceEventType,
|
virtual void notificationReceived( interface::Observer<devicerepository::DeviceEventType,
|
||||||
devicerepository::DeviceEvent>::observable_type* o,
|
devicerepository::DeviceEvent>::observable_type* o,
|
||||||
@@ -116,9 +118,10 @@ public:
|
|||||||
const std::string deviceID,
|
const std::string deviceID,
|
||||||
const std::string statePointer,
|
const std::string statePointer,
|
||||||
const Variant fromValue,
|
const Variant fromValue,
|
||||||
const Variant toValue )
|
const Variant toValue,
|
||||||
|
const libvariant::Variant& jsonRepresentation )
|
||||||
: DeviceMsgCondition(parent, ConditionTriggerType::Event, "devicestatechange", deviceID, statePointer,
|
: DeviceMsgCondition(parent, ConditionTriggerType::Event, "devicestatechange", deviceID, statePointer,
|
||||||
toValue, {devicerepository::DeviceEventType::STATE_CHANGED}), fromValue(fromValue) {}
|
toValue, {devicerepository::DeviceEventType::STATE_CHANGED}, jsonRepresentation), fromValue(fromValue) {}
|
||||||
|
|
||||||
virtual void notificationReceived(interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEventType& key, const devicerepository::DeviceEvent* e) noexcept override;
|
virtual void notificationReceived(interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEventType& key, const devicerepository::DeviceEvent* e) noexcept override;
|
||||||
};
|
};
|
||||||
|
|||||||
+2
-1
@@ -16,7 +16,8 @@ namespace conditions {
|
|||||||
std::shared_ptr<RuleCondition> LogicalAndConditionFactory::createCondition(rules::Rule* parent, const Variant& raw) {
|
std::shared_ptr<RuleCondition> LogicalAndConditionFactory::createCondition(rules::Rule* parent, const Variant& raw) {
|
||||||
std::shared_ptr<LogicalAndCondition> retval;
|
std::shared_ptr<LogicalAndCondition> retval;
|
||||||
if (raw.HasPath("conditions") && raw["conditions"].IsList() && raw["conditions"].Size() > 0) {
|
if (raw.HasPath("conditions") && raw["conditions"].IsList() && raw["conditions"].Size() > 0) {
|
||||||
retval = std::make_shared<LogicalAndCondition>(parent);
|
Variant rep = raw.Copy();
|
||||||
|
retval = std::make_shared<LogicalAndCondition>(parent, rep);
|
||||||
for (auto c : raw["conditions"].AsList()) {
|
for (auto c : raw["conditions"].AsList()) {
|
||||||
auto cond = parent->createRuleCondition(c);
|
auto cond = parent->createRuleCondition(c);
|
||||||
if (cond) {
|
if (cond) {
|
||||||
|
|||||||
+2
-2
@@ -28,8 +28,8 @@ protected:
|
|||||||
unsigned trueChildrenCount = 0;
|
unsigned trueChildrenCount = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LogicalAndCondition(Rule* parent) :
|
LogicalAndCondition(Rule* parent, const libvariant::Variant& jsonRepresentation) :
|
||||||
RuleCompositeConditionImpl(parent, ConditionTriggerType::Both, "logical_and") {}
|
RuleCompositeConditionImpl(parent, ConditionTriggerType::Both, "logical_and", jsonRepresentation) {}
|
||||||
|
|
||||||
virtual void addChild(std::shared_ptr<RuleCondition> child) override;
|
virtual void addChild(std::shared_ptr<RuleCondition> child) override;
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -15,7 +15,8 @@ namespace conditions {
|
|||||||
std::shared_ptr<RuleCondition> LogicalOrConditionFactory::createCondition(rules::Rule* parent, const Variant& raw) {
|
std::shared_ptr<RuleCondition> LogicalOrConditionFactory::createCondition(rules::Rule* parent, const Variant& raw) {
|
||||||
std::shared_ptr<LogicalOrCondition> retval;
|
std::shared_ptr<LogicalOrCondition> retval;
|
||||||
if (raw.HasPath("conditions") && raw["conditions"].IsList() && raw["conditions"].Size() > 0) {
|
if (raw.HasPath("conditions") && raw["conditions"].IsList() && raw["conditions"].Size() > 0) {
|
||||||
retval = std::make_shared<LogicalOrCondition>(parent);
|
Variant rep = raw.Copy();
|
||||||
|
retval = std::make_shared<LogicalOrCondition>(parent, rep);
|
||||||
for (auto c : raw["conditions"].AsList()) {
|
for (auto c : raw["conditions"].AsList()) {
|
||||||
auto cond = parent->createRuleCondition(c);
|
auto cond = parent->createRuleCondition(c);
|
||||||
if (cond) {
|
if (cond) {
|
||||||
|
|||||||
+2
-2
@@ -28,8 +28,8 @@ protected:
|
|||||||
unsigned trueChildrenCount = 0;
|
unsigned trueChildrenCount = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LogicalOrCondition(Rule* parent) :
|
LogicalOrCondition(Rule* parent, const libvariant::Variant& jsonRepresentation) :
|
||||||
RuleCompositeConditionImpl(parent, ConditionTriggerType::Both, "logical_or") {}
|
RuleCompositeConditionImpl(parent, ConditionTriggerType::Both, "logical_or", jsonRepresentation) {}
|
||||||
|
|
||||||
virtual void addChild(std::shared_ptr<RuleCondition> child) override;
|
virtual void addChild(std::shared_ptr<RuleCondition> child) override;
|
||||||
virtual void childStateChanged(RuleCondition* child, bool newState, ConditionTriggerType category,
|
virtual void childStateChanged(RuleCondition* child, bool newState, ConditionTriggerType category,
|
||||||
|
|||||||
+26
-83
@@ -52,6 +52,10 @@ RuleEngineHandlerFactory::RuleEngineHandlerFactory(RuleEngineService* ruleServic
|
|||||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
||||||
}) {
|
}) {
|
||||||
|
|
||||||
|
engineInfoFuncs.add("id", [](RuleEngineService* engine, const std::string& category)->Variant {
|
||||||
|
return engine->getName();
|
||||||
|
});
|
||||||
|
|
||||||
engineInfoFuncs.add("languages", [](RuleEngineService* engine, const std::string& category)->Variant {
|
engineInfoFuncs.add("languages", [](RuleEngineService* engine, const std::string& category)->Variant {
|
||||||
Variant retval = libvariant::Variant::List();
|
Variant retval = libvariant::Variant::List();
|
||||||
for (auto e : engine->getExecutionBackends()) {
|
for (auto e : engine->getExecutionBackends()) {
|
||||||
@@ -74,6 +78,10 @@ RuleEngineHandlerFactory::RuleEngineHandlerFactory(RuleEngineService* ruleServic
|
|||||||
return pkg->getName();
|
return pkg->getName();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
pkgInfoFuncs.add("parent", [](rules::RulePackage* pkg, const std::string& category)->Variant {
|
||||||
|
return pkg->getParent()->getName();
|
||||||
|
});
|
||||||
|
|
||||||
pkgInfoFuncs.add("language", [](rules::RulePackage* pkg, const std::string& category)->Variant {
|
pkgInfoFuncs.add("language", [](rules::RulePackage* pkg, const std::string& category)->Variant {
|
||||||
return pkg->getLanguage();
|
return pkg->getLanguage();
|
||||||
});
|
});
|
||||||
@@ -106,6 +114,10 @@ RuleEngineHandlerFactory::RuleEngineHandlerFactory(RuleEngineService* ruleServic
|
|||||||
return rule->getName();
|
return rule->getName();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ruleInfoFuncs.add("parent", [](rules::Rule* rule, const std::string& category)->Variant {
|
||||||
|
return rule->getParent()->getName();
|
||||||
|
});
|
||||||
|
|
||||||
ruleInfoFuncs.add("enabled", [](rules::Rule* rule, const std::string& category)->Variant {
|
ruleInfoFuncs.add("enabled", [](rules::Rule* rule, const std::string& category)->Variant {
|
||||||
return rule->isEnabled();
|
return rule->isEnabled();
|
||||||
});
|
});
|
||||||
@@ -129,7 +141,7 @@ RuleEngineHandlerFactory::RuleEngineHandlerFactory(RuleEngineService* ruleServic
|
|||||||
});
|
});
|
||||||
|
|
||||||
ruleInfoFuncs.add("condition", [](rules::Rule* rule, const std::string& category)->Variant {
|
ruleInfoFuncs.add("condition", [](rules::Rule* rule, const std::string& category)->Variant {
|
||||||
return "ToDo";
|
return rule->getConditionJSONRepresentation();
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -215,24 +227,24 @@ Variant RuleEngineHandlerFactory::getRuleInfo( rules::Rule* rule, const std::str
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void RuleEngineHandler::_handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
void RuleEngineHandler::_handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Net::HTMLForm& form) {
|
||||||
if(req.find("Upgrade") != req.end() && Poco::icompare(req["Upgrade"], "websocket") == 0) {
|
if(req.find("Upgrade") != req.end() && Poco::icompare(req["Upgrade"], "websocket") == 0) {
|
||||||
//__handleEvent(req, resp, true);
|
//__handleEvent(req, resp, true);
|
||||||
/*throw webserver::webresource::WebResourceHandlerException("ToDo",
|
throw webserver::webresource::WebResourceHandlerException("ToDo",
|
||||||
Net::HTTPResponse::HTTP_NOT_IMPLEMENTED);*/
|
Net::HTTPResponse::HTTP_NOT_IMPLEMENTED);
|
||||||
} else {
|
} else {
|
||||||
if (req.getMethod() == Net::HTTPRequest::HTTP_PUT) {
|
if (req.getMethod() == Net::HTTPRequest::HTTP_PUT) {
|
||||||
// Put Command
|
// Put Command
|
||||||
throw webserver::webresource::WebResourceHandlerException("Still a ToDo.",
|
throw webserver::webresource::WebResourceHandlerException("Still a ToDo.",
|
||||||
Net::HTTPResponse::HTTP_NOT_IMPLEMENTED);
|
Net::HTTPResponse::HTTP_NOT_IMPLEMENTED);
|
||||||
} else if (req.getMethod() == Net::HTTPRequest::HTTP_GET || req.getMethod() == Net::HTTPRequest::HTTP_POST) {
|
} else if (req.getMethod() == Net::HTTPRequest::HTTP_GET || req.getMethod() == Net::HTTPRequest::HTTP_POST) {
|
||||||
RuleEngineAPIMethod method = getRuleEngineAPIMethod(req);
|
RuleEngineAPIMethod method = getRuleEngineAPIMethod(req, form);
|
||||||
if (method == RuleEngineAPIMethod::GET) {
|
if (method == RuleEngineAPIMethod::GET) {
|
||||||
__handleInfo(req, resp);
|
__handleInfo(req, resp, form);
|
||||||
} else if (method == RuleEngineAPIMethod::SET) {
|
} else if (method == RuleEngineAPIMethod::SET) {
|
||||||
//__handleCommand(req, resp, method);
|
//__handleCommand(req, resp, method, form.get());
|
||||||
} else if (method == RuleEngineAPIMethod::EVENT) {
|
} else if (method == RuleEngineAPIMethod::EVENT) {
|
||||||
//__handleEvent(req, resp, false);
|
//__handleEvent(req, resp, false, form.get());
|
||||||
} else {
|
} else {
|
||||||
throw webserver::webresource::WebResourceHandlerException("Could not understood request",
|
throw webserver::webresource::WebResourceHandlerException("Could not understood request",
|
||||||
Net::HTTPResponse::HTTP_BAD_REQUEST);
|
Net::HTTPResponse::HTTP_BAD_REQUEST);
|
||||||
@@ -246,78 +258,16 @@ void RuleEngineHandler::_handleRequest(Poco::Net::HTTPServerRequest &req, Poco::
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void RuleEngineHandler::__handleInfo(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
void RuleEngineHandler::__handleInfo(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Net::HTMLForm& form) {
|
||||||
|
|
||||||
std::vector<std::string> pathPieces, matchPieces;
|
std::vector<std::string> pathPieces, matchPieces;
|
||||||
matchUri.getPathSegments(matchPieces);
|
matchUri.getPathSegments(matchPieces);
|
||||||
Poco::URI uri(req.getURI());
|
Poco::URI uri(req.getURI());
|
||||||
uri.getPathSegments(pathPieces);
|
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, return engine info
|
// Nothing given, return engine info
|
||||||
if (pathPieces.size() <= matchPieces.size()) {
|
if (pathPieces.size() <= matchPieces.size()) {
|
||||||
handleResponse(req, resp, parent->getEngineInfo(ruleService, "", ""));
|
handleResponse(req, resp, form, parent->getEngineInfo(ruleService, "", ""));
|
||||||
|
|
||||||
/*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
|
// rule package given
|
||||||
} else if (pathPieces.size() == matchPieces.size() + 1) {
|
} else if (pathPieces.size() == matchPieces.size() + 1) {
|
||||||
@@ -330,18 +280,11 @@ void RuleEngineHandler::__handleInfo(Poco::Net::HTTPServerRequest &req, Poco::Ne
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
RuleEngineAPIMethod RuleEngineHandler::getRuleEngineAPIMethod(Net::HTTPServerRequest &req) noexcept {
|
RuleEngineAPIMethod RuleEngineHandler::getRuleEngineAPIMethod(Net::HTTPServerRequest &req, Net::HTMLForm& form) noexcept {
|
||||||
std::unique_ptr<Net::HTMLForm> form;
|
|
||||||
RuleEngineAPIMethod retval = RuleEngineAPIMethod::GET; // default
|
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;
|
std::string methodRaw;
|
||||||
if (form->has("method")) {
|
if (form.has("method")) {
|
||||||
methodRaw = form->get("method");
|
methodRaw = form.get("method");
|
||||||
} else if (req.has("API-Method")) {
|
} else if (req.has("API-Method")) {
|
||||||
methodRaw = req.get("API-Method");
|
methodRaw = req.get("API-Method");
|
||||||
} else if (req.has("X-API-Method")) {
|
} else if (req.has("X-API-Method")) {
|
||||||
@@ -359,7 +302,7 @@ RuleEngineAPIMethod RuleEngineHandler::getRuleEngineAPIMethod(Net::HTTPServerReq
|
|||||||
(boost::format("Unknown rule engine api method \"%1%\"") % methodRaw).str(),
|
(boost::format("Unknown rule engine api method \"%1%\"") % methodRaw).str(),
|
||||||
Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST );
|
Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST );
|
||||||
}
|
}
|
||||||
} else if (form->has("onevent") || req.has("On-Event") || req.has("X-On-Event")) {
|
} else if (form.has("onevent") || req.has("On-Event") || req.has("X-On-Event")) {
|
||||||
retval = RuleEngineAPIMethod::EVENT;
|
retval = RuleEngineAPIMethod::EVENT;
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
|
|||||||
+5
-5
@@ -119,15 +119,15 @@ public:
|
|||||||
bool ssl = false )
|
bool ssl = false )
|
||||||
: parent(parent), matchUri(matchUri), ruleService(ruleService), ssl(ssl) {}
|
: parent(parent), matchUri(matchUri), ruleService(ruleService), ssl(ssl) {}
|
||||||
|
|
||||||
virtual void _handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override;
|
virtual void _handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Poco::Net::HTMLForm& form) override;
|
||||||
|
|
||||||
void __handleInfo(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp);
|
void __handleInfo(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Poco::Net::HTMLForm& form);
|
||||||
|
|
||||||
void __handleSet(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, RuleEngineAPIMethod method);
|
void __handleSet(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, RuleEngineAPIMethod method, Poco::Net::HTMLForm& form);
|
||||||
|
|
||||||
void __handleEvent(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, bool websocket);
|
void __handleEvent(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Poco::Net::HTMLForm& form, bool websocket);
|
||||||
|
|
||||||
static RuleEngineAPIMethod getRuleEngineAPIMethod(Poco::Net::HTTPServerRequest &req) noexcept;
|
static RuleEngineAPIMethod getRuleEngineAPIMethod(Poco::Net::HTTPServerRequest &req, Poco::Net::HTMLForm& form) noexcept;
|
||||||
|
|
||||||
/*void sendDeviceCommand( devicerepository::Device* device,
|
/*void sendDeviceCommand( devicerepository::Device* device,
|
||||||
Poco::Net::HTTPServerRequest &req,
|
Poco::Net::HTTPServerRequest &req,
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[Dolphin]
|
||||||
|
Timestamp=2015,6,9,18,8,49
|
||||||
|
Version=3
|
||||||
|
ViewMode=1
|
||||||
@@ -5,8 +5,8 @@ define([
|
|||||||
'dstore/RequestMemory',
|
'dstore/RequestMemory',
|
||||||
'dstore/SimpleQuery',
|
'dstore/SimpleQuery',
|
||||||
'dstore/Trackable',
|
'dstore/Trackable',
|
||||||
"dojox/socket",
|
"hos/Socket",
|
||||||
"dojo/_base/xhr",
|
"dojo/request/xhr",
|
||||||
"dojox/uuid/generateRandomUuid"
|
"dojox/uuid/generateRandomUuid"
|
||||||
], function(config, declare, Rest, RequestMemory, SimpleQuery, Trackable, Socket, xhr, generateRandomUuid){
|
], function(config, declare, Rest, RequestMemory, SimpleQuery, Trackable, Socket, xhr, generateRandomUuid){
|
||||||
|
|
||||||
@@ -51,8 +51,9 @@ define([
|
|||||||
});
|
});
|
||||||
_store.sendCommand = function(id, cmd) {
|
_store.sendCommand = function(id, cmd) {
|
||||||
console.log("ToDo: send command", cmd ,"to " + id);
|
console.log("ToDo: send command", cmd ,"to " + id);
|
||||||
var devurl = config.hos.deviceRepoUrl + "/" + id + "?method=command&value=" + encodeURIComponent(JSON.stringify(cmd));
|
//var devurl = config.hos.deviceRepoUrl + "/" + id + "?method=command&value=" + encodeURIComponent(JSON.stringify(cmd));
|
||||||
xhr.get({url: devurl}).then(function(data){
|
var devurl = config.hos.deviceRepoUrl + "/" + id;
|
||||||
|
xhr.post(devurl, {handleAs: 'json', data: {method: 'command', value: JSON.stringify(cmd)}}).then(function(data){
|
||||||
// Do something with the handled data
|
// Do something with the handled data
|
||||||
}, function(err){
|
}, function(err){
|
||||||
// Handle the error condition
|
// Handle the error condition
|
||||||
|
|||||||
@@ -0,0 +1,228 @@
|
|||||||
|
define([
|
||||||
|
"dojo/_base/array",
|
||||||
|
"dojo/_base/lang",
|
||||||
|
"dojo/request/xhr",
|
||||||
|
"dojo/aspect",
|
||||||
|
"dojo/on",
|
||||||
|
"dojo/Evented",
|
||||||
|
"dojo/_base/url"
|
||||||
|
], function(array, lang, xhr, aspect, on, Evented, dBaseUrl) {
|
||||||
|
|
||||||
|
var WebSocket = window.WebSocket;
|
||||||
|
|
||||||
|
var Socket = function(/*dojo.__XhrArgs*/ argsOrUrl){
|
||||||
|
// summary:
|
||||||
|
// Provides a simple socket connection using WebSocket, or alternate
|
||||||
|
// communication mechanisms in legacy browsers for comet-style communication. This is based
|
||||||
|
// on the WebSocket API and returns an object that implements the WebSocket interface:
|
||||||
|
// http://dev.w3.org/html5/websockets/#websocket
|
||||||
|
// description:
|
||||||
|
// Provides socket connections. This can be used with virtually any Comet protocol.
|
||||||
|
// argsOrUrl:
|
||||||
|
// This uses the same arguments as the other I/O functions in Dojo, or a
|
||||||
|
// URL to connect to. The URL should be a relative URL in order to properly
|
||||||
|
// work with WebSockets (it can still be host relative, like //other-site.org/endpoint)
|
||||||
|
// returns:
|
||||||
|
// An object that implements the WebSocket API
|
||||||
|
// example:
|
||||||
|
// | require(["dojox/socket", "dojo/aspect"], function(socket, aspect) {
|
||||||
|
// | var sock = socket({"url://comet-server/comet");
|
||||||
|
// | // we could also add auto-reconnect support
|
||||||
|
// | // now we can connect to standard HTML5 WebSocket-style events
|
||||||
|
// | aspect.after(socket, "onmessage", function(event){
|
||||||
|
// | var message = event.data;
|
||||||
|
// | // do something with the message
|
||||||
|
// | });
|
||||||
|
// | // send something
|
||||||
|
// | sock.send("hi there");
|
||||||
|
// | ...
|
||||||
|
// | });
|
||||||
|
// You can also use the Reconnect module:
|
||||||
|
// | require["dojox/socket", "dojox/socket/Reconnect"], function(dxSocket, reconnect){
|
||||||
|
// | var socket = dxSocket({url:"/comet"});
|
||||||
|
// | // add auto-reconnect support
|
||||||
|
// | socket = reconnect(socket);
|
||||||
|
if(typeof argsOrUrl == "string"){
|
||||||
|
argsOrUrl = {url: argsOrUrl};
|
||||||
|
}
|
||||||
|
return WebSocket ? Socket.WebSocket(argsOrUrl, true) : Socket.LongPoll(argsOrUrl);
|
||||||
|
};
|
||||||
|
|
||||||
|
Socket.WebSocket = function(args, fallback){
|
||||||
|
// summary:
|
||||||
|
// A wrapper for WebSocket, than handles standard args and relative URLs
|
||||||
|
var baseURI = document.baseURI || window.location.href;
|
||||||
|
var ws = new WebSocket(new dBaseUrl(baseURI.replace(/^http/i,'ws'), args.url));
|
||||||
|
ws.on = function(type, listener){
|
||||||
|
ws.addEventListener(type, listener, true);
|
||||||
|
};
|
||||||
|
var opened;
|
||||||
|
aspect.after(ws, "onopen", function(event){
|
||||||
|
opened = true;
|
||||||
|
}, true);
|
||||||
|
aspect.after(ws, "onclose", function(event){
|
||||||
|
if(opened){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(fallback){
|
||||||
|
Socket.replace(ws, Socket.LongPoll(args), true);
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
return ws;
|
||||||
|
};
|
||||||
|
|
||||||
|
Socket.replace = function(socket, newSocket, listenForOpen){
|
||||||
|
// make the original socket a proxy for the new socket
|
||||||
|
socket.send = lang.hitch(newSocket, "send");
|
||||||
|
socket.close = lang.hitch(newSocket, "close");
|
||||||
|
var proxyEvent = function(type){
|
||||||
|
(newSocket.addEventListener || newSocket.on).call(newSocket, type, function(event){
|
||||||
|
on.emit(socket, event.type, event);
|
||||||
|
}, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
if(listenForOpen){
|
||||||
|
proxyEvent("open");
|
||||||
|
}
|
||||||
|
// redirect the events as well
|
||||||
|
array.forEach(["message", "close", "error"], proxyEvent);
|
||||||
|
};
|
||||||
|
|
||||||
|
Socket.LongPoll = function(/*dojo.__XhrArgs*/ args){
|
||||||
|
// summary:
|
||||||
|
// Provides a simple long-poll based comet-style socket/connection to a server and returns an
|
||||||
|
// object implementing the WebSocket interface:
|
||||||
|
// http://dev.w3.org/html5/websockets/#websocket
|
||||||
|
// args:
|
||||||
|
// This uses the same arguments as the other I/O functions in Dojo, with this addition:
|
||||||
|
// args.interval:
|
||||||
|
// Indicates the amount of time (in milliseconds) after a response was received
|
||||||
|
// before another request is made. By default, a request is made immediately
|
||||||
|
// after getting a response. The interval can be increased to reduce load on the
|
||||||
|
// server or to do simple time-based polling where the server always responds
|
||||||
|
// immediately.
|
||||||
|
// args.transport:
|
||||||
|
// Provide an alternate transport like dojo.io.script.get
|
||||||
|
// returns:
|
||||||
|
// An object that implements the WebSocket API
|
||||||
|
// example:
|
||||||
|
// | dojo.require("dojox.socket.LongPoll");
|
||||||
|
// | var socket = dojox.socket.LongPoll({url:"/comet"});
|
||||||
|
// or:
|
||||||
|
// | dojo.require("dojox.socket.LongPoll");
|
||||||
|
// | dojox.socket.LongPoll.add();
|
||||||
|
// | var socket = dojox.socket({url:"/comet"});
|
||||||
|
|
||||||
|
var cancelled = false,
|
||||||
|
first = true,
|
||||||
|
timeoutId,
|
||||||
|
connections = [];
|
||||||
|
|
||||||
|
// create the socket object
|
||||||
|
var fire, connect;
|
||||||
|
var socket = {
|
||||||
|
send: function(data){
|
||||||
|
// summary:
|
||||||
|
// Send some data using XHR or provided transport
|
||||||
|
var sendArgs = lang.delegate(args);
|
||||||
|
sendArgs.rawBody = data;
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
var deferred = first ? (first = false) || socket.firstRequest(sendArgs) :
|
||||||
|
socket.transport(sendArgs.url, sendArgs);
|
||||||
|
connections.push(deferred);
|
||||||
|
deferred.then(function(response){
|
||||||
|
// got a response
|
||||||
|
socket.readyState = 1;
|
||||||
|
// remove the current connection
|
||||||
|
connections.splice(array.indexOf(connections, deferred), 1);
|
||||||
|
// reconnect to listen for the next message if there are no active connections,
|
||||||
|
// we queue it up in case one of the onmessage handlers has a message to send
|
||||||
|
if(!connections.length){
|
||||||
|
timeoutId = setTimeout(connect, args.interval);
|
||||||
|
}
|
||||||
|
if(response){
|
||||||
|
// now send the message along to listeners
|
||||||
|
fire("message", {data: response}, deferred);
|
||||||
|
}
|
||||||
|
}, function(error){
|
||||||
|
connections.splice(array.indexOf(connections, deferred), 1);
|
||||||
|
// an error occurred, fire the appropriate event listeners
|
||||||
|
if(!cancelled){
|
||||||
|
fire("error", {error:error}, deferred);
|
||||||
|
if(!connections.length){
|
||||||
|
socket.readyState = 3;
|
||||||
|
fire("close", {wasClean:false}, deferred);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return deferred;
|
||||||
|
},
|
||||||
|
close: function(){
|
||||||
|
// summary:
|
||||||
|
// Close the connection
|
||||||
|
socket.readyState = 2;
|
||||||
|
cancelled = true;
|
||||||
|
var i;
|
||||||
|
for(i = 0; i < connections.length; i++){
|
||||||
|
connections[i].cancel();
|
||||||
|
}
|
||||||
|
socket.readyState = 3;
|
||||||
|
fire("close", {wasClean:true});
|
||||||
|
},
|
||||||
|
transport: args.transport || xhr.post,
|
||||||
|
args: args,
|
||||||
|
url: args.url,
|
||||||
|
readyState: 0,
|
||||||
|
CONNECTING: 0,
|
||||||
|
OPEN: 1,
|
||||||
|
CLOSING: 2,
|
||||||
|
CLOSED: 3,
|
||||||
|
on: Evented.prototype.on,
|
||||||
|
firstRequest: function(args){
|
||||||
|
// summary:
|
||||||
|
// This allows for special handling for the first request. This is useful for
|
||||||
|
// providing information to disambiguate between the first request and
|
||||||
|
// subsequent long-poll requests so the server can properly setup a
|
||||||
|
// connection on the first connection or reject a request for an expired
|
||||||
|
// connection if the request is not expecting to be the first for a connection.
|
||||||
|
// This method can be overriden. The default behavior is to include a Pragma
|
||||||
|
// header with a value of "start-long-poll"
|
||||||
|
var headers = (args.headers || (args.headers = {}));
|
||||||
|
headers.Pragma = "start-long-poll";
|
||||||
|
try{
|
||||||
|
return this.transport(args.url, args);
|
||||||
|
}finally{
|
||||||
|
// cleanup the header so it is not used on subsequent requests
|
||||||
|
delete headers.Pragma;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fire = function(type, object, deferred){
|
||||||
|
if(socket["on" + type]){
|
||||||
|
object.ioArgs = deferred && deferred.ioArgs;
|
||||||
|
object.type = type;
|
||||||
|
on.emit(socket, type, object);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
connect = function(){
|
||||||
|
if(socket.readyState == 0){
|
||||||
|
// we fire the open event now because we really don't know when the "socket"
|
||||||
|
// is truly open, and this gives us a to do a send() and get it included in the
|
||||||
|
// HTTP request
|
||||||
|
fire("open",{});
|
||||||
|
}
|
||||||
|
// make the long-poll connection, to wait for response from the server
|
||||||
|
if(!connections.length){
|
||||||
|
socket.send();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// provide an alias for Dojo's connect method
|
||||||
|
socket.connect = socket.on;
|
||||||
|
// do the initial connection
|
||||||
|
setTimeout(connect);
|
||||||
|
return socket;
|
||||||
|
};
|
||||||
|
|
||||||
|
return Socket;
|
||||||
|
|
||||||
|
});
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
define([
|
||||||
|
'dojo/_base/declare',
|
||||||
|
'dstore/Rest',
|
||||||
|
'dstore/RequestMemory',
|
||||||
|
'dstore/SimpleQuery',
|
||||||
|
'dstore/Trackable',
|
||||||
|
'hos/Socket',
|
||||||
|
'dojo/_base/xhr',
|
||||||
|
'dojox/uuid/generateRandomUuid'
|
||||||
|
], function(declare, Rest, RequestMemory, SimpleQuery, Trackable, Socket, xhr, generateRandomUuid){
|
||||||
|
|
||||||
|
return declare([Rest, RequestMemory, SimpleQuery, Trackable], {
|
||||||
|
|
||||||
|
sendDeviceCommand: function(id, cmd) {
|
||||||
|
console.log("ToDo: send command", cmd ,"to " + id);
|
||||||
|
var devurl = config.hos.deviceRepoUrl + "/" + id + "?method=command&value=" + encodeURIComponent(JSON.stringify(cmd));
|
||||||
|
xhr.get({url: devurl}).then(function(data){
|
||||||
|
// Do something with the handled data
|
||||||
|
}, function(err){
|
||||||
|
// Handle the error condition
|
||||||
|
}, function(evt){
|
||||||
|
// Handle a progress event from the request if the
|
||||||
|
// browser supports XHR2
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
+92
-23
@@ -14,6 +14,7 @@
|
|||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
@@ -308,9 +309,8 @@ protected:
|
|||||||
class NotImplementedException
|
class NotImplementedException
|
||||||
: public std::exception {};
|
: public std::exception {};
|
||||||
|
|
||||||
DataFormat getDataFormat(const Poco::Net::HTTPServerRequest& request, bool incoming = false) {
|
DataFormat getDataFormat(const Poco::Net::HTTPServerRequest& request, Poco::Net::HTMLForm& form, bool incoming = false) {
|
||||||
DataFormat retval = DataFormat::JSON; // defaults to json
|
DataFormat retval = DataFormat::JSON; // defaults to json
|
||||||
Poco::Net::HTMLForm form(request);
|
|
||||||
if (form.has("format")) {
|
if (form.has("format")) {
|
||||||
std::string formatRaw = form.get("format");
|
std::string formatRaw = form.get("format");
|
||||||
if (formatRaw.compare("json") == 0) {
|
if (formatRaw.compare("json") == 0) {
|
||||||
@@ -375,16 +375,16 @@ protected:
|
|||||||
|
|
||||||
std::string encodeVariant( const libvariant::Variant& msg,
|
std::string encodeVariant( const libvariant::Variant& msg,
|
||||||
const Poco::Net::HTTPServerRequest& request,
|
const Poco::Net::HTTPServerRequest& request,
|
||||||
|
Poco::Net::HTMLForm& form,
|
||||||
DataFormat format = DataFormat::AUTO_GUESS ) {
|
DataFormat format = DataFormat::AUTO_GUESS ) {
|
||||||
if (format == DataFormat::AUTO_GUESS) {
|
if (format == DataFormat::AUTO_GUESS) {
|
||||||
format = getDataFormat(request);
|
format = getDataFormat(request, form);
|
||||||
}
|
}
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case DataFormat::JSON:
|
case DataFormat::JSON:
|
||||||
return libvariant::SerializeJSON(msg, true);
|
return libvariant::SerializeJSON(msg, true);
|
||||||
case DataFormat::JSONP:
|
case DataFormat::JSONP:
|
||||||
{
|
{
|
||||||
Poco::Net::HTMLForm form(request);
|
|
||||||
std::string padding("callback");
|
std::string padding("callback");
|
||||||
if (form.has("callback")) {
|
if (form.has("callback")) {
|
||||||
padding = form.get("callback");
|
padding = form.get("callback");
|
||||||
@@ -436,24 +436,26 @@ protected:
|
|||||||
|
|
||||||
void handleResponse( Poco::Net::HTTPServerRequest& request,
|
void handleResponse( Poco::Net::HTTPServerRequest& request,
|
||||||
Poco::Net::HTTPServerResponse &resp,
|
Poco::Net::HTTPServerResponse &resp,
|
||||||
|
Poco::Net::HTMLForm& form,
|
||||||
const libvariant::Variant& msg,
|
const libvariant::Variant& msg,
|
||||||
Poco::Net::HTTPResponse::HTTPStatus status = Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK,
|
Poco::Net::HTTPResponse::HTTPStatus status = Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK,
|
||||||
const std::string& mime = "" ) {
|
const std::string& mime = "" ) {
|
||||||
resp.setStatusAndReason(status);
|
resp.setStatusAndReason(status);
|
||||||
auto format = getDataFormat(request);
|
auto format = getDataFormat(request, form);
|
||||||
if (mime.empty()) {
|
if (mime.empty()) {
|
||||||
setContentType(resp, format);
|
setContentType(resp, format);
|
||||||
} else {
|
} else {
|
||||||
resp.setContentType(mime);
|
resp.setContentType(mime);
|
||||||
}
|
}
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << encodeVariant(msg, request, format);
|
ss << encodeVariant(msg, request, form, format);
|
||||||
std::string buffer = ss.str();
|
std::string buffer = ss.str();
|
||||||
resp.sendBuffer(buffer.c_str(), buffer.size());
|
resp.sendBuffer(buffer.c_str(), buffer.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleResponse( Poco::Net::HTTPServerRequest& request,
|
void handleResponse( Poco::Net::HTTPServerRequest& request,
|
||||||
Poco::Net::HTTPServerResponse &resp,
|
Poco::Net::HTTPServerResponse &resp,
|
||||||
|
Poco::Net::HTMLForm& form,
|
||||||
const std::string& msg,
|
const std::string& msg,
|
||||||
Poco::Net::HTTPResponse::HTTPStatus status = Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK,
|
Poco::Net::HTTPResponse::HTTPStatus status = Poco::Net::HTTPResponse::HTTPStatus::HTTP_OK,
|
||||||
const std::string& mime = "text/plain" ) {
|
const std::string& mime = "text/plain" ) {
|
||||||
@@ -464,6 +466,7 @@ protected:
|
|||||||
|
|
||||||
void handleErrorResponse( Poco::Net::HTTPServerRequest& request,
|
void handleErrorResponse( Poco::Net::HTTPServerRequest& request,
|
||||||
Poco::Net::HTTPServerResponse &resp,
|
Poco::Net::HTTPServerResponse &resp,
|
||||||
|
Poco::Net::HTMLForm& form,
|
||||||
const std::string& msg,
|
const std::string& msg,
|
||||||
Poco::Net::HTTPResponse::HTTPStatus status = Poco::Net::HTTPResponse::HTTPStatus::HTTP_INTERNAL_SERVER_ERROR,
|
Poco::Net::HTTPResponse::HTTPStatus status = Poco::Net::HTTPResponse::HTTPStatus::HTTP_INTERNAL_SERVER_ERROR,
|
||||||
const std::string& mime = "text/plain" ) {
|
const std::string& mime = "text/plain" ) {
|
||||||
@@ -478,6 +481,7 @@ protected:
|
|||||||
|
|
||||||
void handleErrorResponse( Poco::Net::HTTPServerRequest& request,
|
void handleErrorResponse( Poco::Net::HTTPServerRequest& request,
|
||||||
Poco::Net::HTTPServerResponse &resp,
|
Poco::Net::HTTPServerResponse &resp,
|
||||||
|
Poco::Net::HTMLForm& form,
|
||||||
Poco::Net::HTTPResponse::HTTPStatus status = Poco::Net::HTTPResponse::HTTPStatus::HTTP_INTERNAL_SERVER_ERROR ) {
|
Poco::Net::HTTPResponse::HTTPStatus status = Poco::Net::HTTPResponse::HTTPStatus::HTTP_INTERNAL_SERVER_ERROR ) {
|
||||||
resp.setStatusAndReason(status);
|
resp.setStatusAndReason(status);
|
||||||
resp.setContentType("text/plain");
|
resp.setContentType("text/plain");
|
||||||
@@ -490,6 +494,7 @@ protected:
|
|||||||
|
|
||||||
void handleErrorResponse( Poco::Net::HTTPServerRequest& request,
|
void handleErrorResponse( Poco::Net::HTTPServerRequest& request,
|
||||||
Poco::Net::HTTPServerResponse &resp,
|
Poco::Net::HTTPServerResponse &resp,
|
||||||
|
Poco::Net::HTMLForm& form,
|
||||||
const WebResourceHandlerException& e ) {
|
const WebResourceHandlerException& e ) {
|
||||||
resp.setStatusAndReason(e.getStatusCode());
|
resp.setStatusAndReason(e.getStatusCode());
|
||||||
resp.setContentType("text/plain");
|
resp.setContentType("text/plain");
|
||||||
@@ -502,6 +507,7 @@ protected:
|
|||||||
|
|
||||||
void handleErrorResponse( Poco::Net::HTTPServerRequest& request,
|
void handleErrorResponse( Poco::Net::HTTPServerRequest& request,
|
||||||
Poco::Net::HTTPServerResponse &resp,
|
Poco::Net::HTTPServerResponse &resp,
|
||||||
|
Poco::Net::HTMLForm& form,
|
||||||
const std::exception& e,
|
const std::exception& e,
|
||||||
Poco::Net::HTTPResponse::HTTPStatus status = Poco::Net::HTTPResponse::HTTPStatus::HTTP_INTERNAL_SERVER_ERROR ) {
|
Poco::Net::HTTPResponse::HTTPStatus status = Poco::Net::HTTPResponse::HTTPStatus::HTTP_INTERNAL_SERVER_ERROR ) {
|
||||||
resp.setStatusAndReason(status);
|
resp.setStatusAndReason(status);
|
||||||
@@ -515,6 +521,7 @@ protected:
|
|||||||
|
|
||||||
void handleRequireAuthenticationResponse( Poco::Net::HTTPServerRequest& request,
|
void handleRequireAuthenticationResponse( Poco::Net::HTTPServerRequest& request,
|
||||||
Poco::Net::HTTPServerResponse &resp,
|
Poco::Net::HTTPServerResponse &resp,
|
||||||
|
Poco::Net::HTMLForm& form,
|
||||||
const std::string& realm,
|
const std::string& realm,
|
||||||
const std::string& body = "",
|
const std::string& body = "",
|
||||||
Poco::Net::HTTPResponse::HTTPStatus status = Poco::Net::HTTPResponse::HTTPStatus::HTTP_UNAUTHORIZED,
|
Poco::Net::HTTPResponse::HTTPStatus status = Poco::Net::HTTPResponse::HTTPStatus::HTTP_UNAUTHORIZED,
|
||||||
@@ -544,56 +551,67 @@ protected:
|
|||||||
<< "======== DEBUG END ========" << std::endl ;
|
<< "======== DEBUG END ========" << std::endl ;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void _handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
virtual void _handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Poco::Net::HTMLForm& form) {
|
||||||
throw NotImplementedException();
|
throw NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void _handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
virtual void _handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Poco::Net::HTMLForm& form) {
|
||||||
throw NotImplementedException();
|
throw NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void _handlePOST(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
virtual void _handlePOST(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Poco::Net::HTMLForm& form) {
|
||||||
throw NotImplementedException();
|
throw NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void _handlePUT(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
virtual void _handlePUT(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Poco::Net::HTMLForm& form) {
|
||||||
throw NotImplementedException();
|
throw NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override {
|
virtual void handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override {
|
||||||
|
std::unique_ptr<Poco::Net::HTMLForm> form;
|
||||||
|
if (req.getMethod() == Poco::Net::HTTPRequest::HTTP_POST && req.has("Content-type")
|
||||||
|
&& boost::starts_with(req.get("Content-type"), Poco::Net::HTMLForm::ENCODING_URL)) {
|
||||||
|
form.reset(new Poco::Net::HTMLForm(req, req.stream()));
|
||||||
|
} else {
|
||||||
|
form.reset(new Poco::Net::HTMLForm(req));
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
_handleRequest(req, resp);
|
_handleRequest(req, resp, *form.get());
|
||||||
} catch (NotImplementedException& e) {
|
} catch (NotImplementedException& e) {
|
||||||
try {
|
try {
|
||||||
if (req.getMethod() == Poco::Net::HTTPRequest::HTTP_GET) {
|
if (req.getMethod() == Poco::Net::HTTPRequest::HTTP_GET) {
|
||||||
_handleGET(req, resp);
|
_handleGET(req, resp, *form.get());
|
||||||
} else if (req.getMethod() == Poco::Net::HTTPRequest::HTTP_POST) {
|
} else if (req.getMethod() == Poco::Net::HTTPRequest::HTTP_POST) {
|
||||||
_handlePOST(req, resp);
|
_handlePOST(req, resp, *form.get());
|
||||||
} else if (req.getMethod() == Poco::Net::HTTPRequest::HTTP_PUT) {
|
} else if (req.getMethod() == Poco::Net::HTTPRequest::HTTP_PUT) {
|
||||||
_handlePUT(req, resp);
|
_handlePUT(req, resp, *form.get());
|
||||||
} else {
|
} else {
|
||||||
std::cout << "Unsupported HTTP Request Method" << std::endl;
|
std::cout << "Unsupported HTTP Request Method" << std::endl;
|
||||||
handleErrorResponse(req, resp, (boost::format("HTTP method %1% not supported") % req.getMethod()).str(),
|
handleErrorResponse(req, resp, *form.get(), (boost::format("HTTP method %1% not supported") % req.getMethod()).str(),
|
||||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_IMPLEMENTED);
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_IMPLEMENTED);
|
||||||
}
|
}
|
||||||
} catch (NotImplementedException& e) {
|
} catch (NotImplementedException& e) {
|
||||||
std::cout << "Unsupported HTTP Request Method" << std::endl;
|
std::cout << "Unsupported HTTP Request Method" << std::endl;
|
||||||
handleErrorResponse(req, resp, (boost::format("HTTP method %1% not supported") % req.getMethod()).str(),
|
handleErrorResponse(req, resp, *form.get(), (boost::format("HTTP method %1% not supported") % req.getMethod()).str(),
|
||||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_IMPLEMENTED);
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_IMPLEMENTED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (WebResourceHandlerException& e) {
|
} catch (WebResourceHandlerException& e) {
|
||||||
handleErrorResponse(req, resp, e);
|
handleErrorResponse(req, resp, *form.get(), e);
|
||||||
} catch (std::exception& e) {
|
} catch (std::exception& e) {
|
||||||
handleErrorResponse(req, resp, e);
|
handleErrorResponse(req, resp, *form.get(), e);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
handleErrorResponse(req, resp, "Unknown exception");
|
handleErrorResponse(req, resp, *form.get(), "Unknown exception");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class EventQueue, class HandlerFactory>
|
template<class EventQueue, class HandlerFactory>
|
||||||
void __handleEventWebSocket(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, EventQueue* eventQueue, HandlerFactory* factory) {
|
void __handleEventWebSocket( Poco::Net::HTTPServerRequest &req,
|
||||||
|
Poco::Net::HTTPServerResponse &resp,
|
||||||
|
Poco::Net::HTMLForm& form,
|
||||||
|
EventQueue* eventQueue,
|
||||||
|
HandlerFactory* factory ) {
|
||||||
try {
|
try {
|
||||||
Poco::Net::WebSocket ws(req, resp);
|
Poco::Net::WebSocket ws(req, resp);
|
||||||
std::cout << "WebSocket connection established." << std::endl;
|
std::cout << "WebSocket connection established." << std::endl;
|
||||||
@@ -627,7 +645,7 @@ protected:
|
|||||||
while (!breakLoop) {
|
while (!breakLoop) {
|
||||||
libvariant::Variant msg;
|
libvariant::Variant msg;
|
||||||
msg = eventQueue->popEvent();
|
msg = eventQueue->popEvent();
|
||||||
std::string encoded = encodeVariant(msg, req);
|
std::string encoded = encodeVariant(msg, req, form);
|
||||||
ws.sendFrame(encoded.c_str(), encoded.size(), Poco::Net::WebSocket::FRAME_FLAG_FIN | Poco::Net::WebSocket::FRAME_OP_TEXT);
|
ws.sendFrame(encoded.c_str(), encoded.size(), Poco::Net::WebSocket::FRAME_FLAG_FIN | Poco::Net::WebSocket::FRAME_OP_TEXT);
|
||||||
}
|
}
|
||||||
std::cout << "WebSocket connection closed." << std::endl;
|
std::cout << "WebSocket connection closed." << std::endl;
|
||||||
@@ -651,7 +669,11 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class EventQueue, class HandlerFactory>
|
template<class EventQueue, class HandlerFactory>
|
||||||
void __handleEventLongPolling(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, EventQueue* eventQueue, HandlerFactory* factory) {
|
void __handleEventLongPolling( Poco::Net::HTTPServerRequest &req,
|
||||||
|
Poco::Net::HTTPServerResponse &resp,
|
||||||
|
Poco::Net::HTMLForm& form,
|
||||||
|
EventQueue* eventQueue,
|
||||||
|
HandlerFactory* factory ) {
|
||||||
libvariant::Variant msg;
|
libvariant::Variant msg;
|
||||||
bool breakLoop = false;
|
bool breakLoop = false;
|
||||||
boost::asio::deadline_timer connCheckTimer(factory->getIOService());
|
boost::asio::deadline_timer connCheckTimer(factory->getIOService());
|
||||||
@@ -690,8 +712,55 @@ protected:
|
|||||||
breakLoop = true;
|
breakLoop = true;
|
||||||
connCheckTimer.cancel();
|
connCheckTimer.cancel();
|
||||||
}
|
}
|
||||||
handleResponse(req, resp, msg);
|
handleResponse(req, resp, form, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool getRangeHeaderParameter(Poco::Net::HTTPServerRequest &req, size_t& start, size_t& end, size_t end_max) {
|
||||||
|
std::string rangeRaw;
|
||||||
|
if (req.has("Range")) {
|
||||||
|
rangeRaw = req.get("Range");
|
||||||
|
} else if (req.has("X-Range")) {
|
||||||
|
rangeRaw = req.get("X-Range");
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
start = r1;
|
||||||
|
end = std::min(r2, end_max);
|
||||||
|
}
|
||||||
|
} catch (...) {
|
||||||
|
ROS_ERROR_STREAM("Could not parse Range parameter \"" << rangeRaw << "\".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setRangeHeaderParameter(Poco::Net::HTTPServerResponse &resp, size_t start, size_t end, size_t max) {
|
||||||
|
std::string rangeOut = (boost::format("items %1%-%2%/%3%") % start % end % max).str();
|
||||||
|
resp.set("Content-Range", rangeOut);
|
||||||
|
resp.set("X-Content-Range", rangeOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getPointerParameter(std::string& pointer, Poco::Net::HTMLForm& form) {
|
||||||
|
if (form.has("pointer")) {
|
||||||
|
pointer = form.get("pointer");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -97,9 +97,17 @@ void WebServerServiceImpl::init() noexcept {
|
|||||||
webServerParams->setSoftwareVersion("Home Operating System alpha");
|
webServerParams->setSoftwareVersion("Home Operating System alpha");
|
||||||
webServerParams->setMaxThreads(10);
|
webServerParams->setMaxThreads(10);
|
||||||
|
|
||||||
Net::ServerSocket webServerSocket(8080);
|
try {
|
||||||
webServer.reset(new Poco::Net::HTTPServer(&handlerFactory, webServerSocket, webServerParams));
|
Net::ServerSocket webServerSocket(8080);
|
||||||
webServer->start();
|
webServer.reset(new Poco::Net::HTTPServer(&handlerFactory, webServerSocket, webServerParams));
|
||||||
|
webServer->start();
|
||||||
|
} catch(Poco::Net::NetException& e) {
|
||||||
|
ROS_ERROR_STREAM("Could not start HTTP server: " << e.displayText());
|
||||||
|
webServer.reset();
|
||||||
|
} catch(...) {
|
||||||
|
ROS_ERROR("Unknown exception while starting HTTP Server");
|
||||||
|
webServer.reset();
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
@@ -143,6 +151,9 @@ void WebServerServiceImpl::init() noexcept {
|
|||||||
} catch(Poco::Net::SSLException& e) {
|
} catch(Poco::Net::SSLException& e) {
|
||||||
ROS_ERROR_STREAM("Could not start HTTPS server: " << e.displayText());
|
ROS_ERROR_STREAM("Could not start HTTPS server: " << e.displayText());
|
||||||
webServerSSL.reset();
|
webServerSSL.reset();
|
||||||
|
} catch(Poco::Net::NetException& e) {
|
||||||
|
ROS_ERROR_STREAM("Could not start HTTPS server: " << e.displayText());
|
||||||
|
webServerSSL.reset();
|
||||||
} catch(...) {
|
} catch(...) {
|
||||||
ROS_ERROR("Unknown exception while starting HTTPS Server");
|
ROS_ERROR("Unknown exception while starting HTTPS Server");
|
||||||
webServerSSL.reset();
|
webServerSSL.reset();
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
#include <Poco/Net/HTTPServerRequest.h>
|
#include <Poco/Net/HTTPServerRequest.h>
|
||||||
#include <Poco/Net/HTTPServerResponse.h>
|
#include <Poco/Net/HTTPServerResponse.h>
|
||||||
#include <Poco/URI.h>
|
#include <Poco/URI.h>
|
||||||
#include <Poco/Net/HTMLForm.h>
|
|
||||||
#include <Poco/Net/SecureServerSocket.h>
|
#include <Poco/Net/SecureServerSocket.h>
|
||||||
#include <Poco/Net/SSLManager.h>
|
#include <Poco/Net/SSLManager.h>
|
||||||
|
|
||||||
@@ -54,15 +53,15 @@ private:
|
|||||||
class DefaultRequestHandler
|
class DefaultRequestHandler
|
||||||
: public webresource::WebResourceHandlerImpl {
|
: public webresource::WebResourceHandlerImpl {
|
||||||
public:
|
public:
|
||||||
virtual void _handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override {
|
virtual void _handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Poco::Net::HTMLForm& form) override {
|
||||||
handleErrorResponse(req, resp, Poco::Net::HTTPResponse::HTTPStatus::HTTP_FORBIDDEN);
|
handleErrorResponse(req, resp, form, Poco::Net::HTTPResponse::HTTPStatus::HTTP_FORBIDDEN);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
class RequireAuthenticationRequestHandler
|
class RequireAuthenticationRequestHandler
|
||||||
: public webresource::WebResourceHandlerImpl {
|
: public webresource::WebResourceHandlerImpl {
|
||||||
public:
|
public:
|
||||||
virtual void _handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override {
|
virtual void _handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Poco::Net::HTMLForm& form) override {
|
||||||
handleRequireAuthenticationResponse(req, resp, "Home Operating System Login");
|
handleRequireAuthenticationResponse(req, resp, form, "Home Operating System Login");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
class ErrorRequestHandler
|
class ErrorRequestHandler
|
||||||
@@ -72,8 +71,8 @@ private:
|
|||||||
Poco::Net::HTTPResponse::HTTPStatus status;
|
Poco::Net::HTTPResponse::HTTPStatus status;
|
||||||
ErrorRequestHandler(const std::string& msg, Poco::Net::HTTPResponse::HTTPStatus status)
|
ErrorRequestHandler(const std::string& msg, Poco::Net::HTTPResponse::HTTPStatus status)
|
||||||
: msg(msg), status(status) {}
|
: msg(msg), status(status) {}
|
||||||
virtual void _handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override {
|
virtual void _handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Poco::Net::HTMLForm& form) override {
|
||||||
handleErrorResponse(req, resp, msg, status);
|
handleErrorResponse(req, resp, form, msg, status);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
public:
|
public:
|
||||||
|
|||||||
+13
-12
@@ -79,7 +79,7 @@ Poco::Net::HTTPRequestHandler* DirectoryResourceHandlerFactory::createRequestHan
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void DirectoryResourceHandler::_handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
void DirectoryResourceHandler::_handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Net::HTMLForm& form) {
|
||||||
|
|
||||||
// Get "absolute" file path
|
// Get "absolute" file path
|
||||||
std::vector<std::string> matchPieces, pathPieces;
|
std::vector<std::string> matchPieces, pathPieces;
|
||||||
@@ -95,45 +95,46 @@ void DirectoryResourceHandler::_handleGET(Poco::Net::HTTPServerRequest &req, Poc
|
|||||||
if (filesystem::exists(resourcePath)) {
|
if (filesystem::exists(resourcePath)) {
|
||||||
// Directory
|
// Directory
|
||||||
if (filesystem::is_directory(resourcePath)) {
|
if (filesystem::is_directory(resourcePath)) {
|
||||||
serveDirectoy(req, resp, resourcePath);
|
serveDirectoy(req, resp, form, resourcePath);
|
||||||
// Regular file
|
// Regular file
|
||||||
} else if (filesystem::is_regular_file(resourcePath)) {
|
} else if (filesystem::is_regular_file(resourcePath)) {
|
||||||
// php script
|
// php script
|
||||||
if (hasFileExtension(resourcePath, parent->phpExtensions)) {
|
if (hasFileExtension(resourcePath, parent->phpExtensions)) {
|
||||||
servePhpFile(req, resp, resourcePath);
|
servePhpFile(req, resp, form, resourcePath);
|
||||||
// other
|
// other
|
||||||
} else {
|
} else {
|
||||||
serveRegularFile(req, resp, resourcePath);
|
serveRegularFile(req, resp, form, resourcePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
handleErrorResponse(req, resp, (boost::format("\"%1%\" has unknown type") % resourcePath).str(),
|
handleErrorResponse(req, resp, form, (boost::format("\"%1%\" has unknown type") % resourcePath).str(),
|
||||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_INTERNAL_SERVER_ERROR);
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_INTERNAL_SERVER_ERROR);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
handleErrorResponse(req, resp, (boost::format("Could not find \"%1%\"") % resourcePath).str(), Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
handleErrorResponse(req, resp, form, (boost::format("Could not find \"%1%\"") % resourcePath).str(),
|
||||||
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void DirectoryResourceHandler::serveDirectoy(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, const boost::filesystem::path& dir) {
|
void DirectoryResourceHandler::serveDirectoy(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Net::HTMLForm& form, const boost::filesystem::path& dir) {
|
||||||
auto index = dirGetFile(dir, parent->dirIndices);
|
auto index = dirGetFile(dir, parent->dirIndices);
|
||||||
if (!index.empty()) {
|
if (!index.empty()) {
|
||||||
if (hasFileExtension(index, parent->phpExtensions)) {
|
if (hasFileExtension(index, parent->phpExtensions)) {
|
||||||
servePhpFile(req, resp, index);
|
servePhpFile(req, resp, form, index);
|
||||||
} else {
|
} else {
|
||||||
serveRegularFile(req, resp, index);
|
serveRegularFile(req, resp, form, index);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
handleErrorResponse(req, resp, (boost::format("Listing of directory \"%1%\" not supported") % dir).str(),
|
handleErrorResponse(req, resp, form, (boost::format("Listing of directory \"%1%\" not supported") % dir).str(),
|
||||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void DirectoryResourceHandler::serveRegularFile(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, const boost::filesystem::path& file) {
|
void DirectoryResourceHandler::serveRegularFile(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Net::HTMLForm& form, const boost::filesystem::path& file) {
|
||||||
auto type = parent->contentTypes.find(file.extension().string());
|
auto type = parent->contentTypes.find(file.extension().string());
|
||||||
if (type != parent->contentTypes.end()) {
|
if (type != parent->contentTypes.end()) {
|
||||||
resp.setContentType(type->second);
|
resp.setContentType(type->second);
|
||||||
@@ -148,7 +149,7 @@ void DirectoryResourceHandler::serveRegularFile(Poco::Net::HTTPServerRequest &re
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void DirectoryResourceHandler::servePhpFile(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, const boost::filesystem::path& file) {
|
void DirectoryResourceHandler::servePhpFile(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Net::HTMLForm& form, const boost::filesystem::path& file) {
|
||||||
// Compile file (ToDo: implement a cache)
|
// Compile file (ToDo: implement a cache)
|
||||||
ph7_vm* pVm;
|
ph7_vm* pVm;
|
||||||
int rc = ph7_compile_file(parent->getPH7Engine(), file.string().c_str(), &pVm, 0);
|
int rc = ph7_compile_file(parent->getPH7Engine(), file.string().c_str(), &pVm, 0);
|
||||||
|
|||||||
+4
-4
@@ -95,7 +95,7 @@ public:
|
|||||||
DirectoryResourceHandler(Poco::URI matchUri, DirectoryResourceHandlerFactory* parent, webserver::WebServerService* service, const DirectoryResourceEntry& resource, bool ssl)
|
DirectoryResourceHandler(Poco::URI matchUri, DirectoryResourceHandlerFactory* parent, webserver::WebServerService* service, const DirectoryResourceEntry& resource, bool ssl)
|
||||||
: matchUri(matchUri), parent(parent), service(service), resource(resource), ssl(ssl) {}
|
: matchUri(matchUri), parent(parent), service(service), resource(resource), ssl(ssl) {}
|
||||||
|
|
||||||
virtual void _handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override;
|
virtual void _handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Poco::Net::HTMLForm& form) override;
|
||||||
|
|
||||||
static int ph7OutputConsumer(const void *pOutput, unsigned int nOutputLen, void *pUserData) {
|
static int ph7OutputConsumer(const void *pOutput, unsigned int nOutputLen, void *pUserData) {
|
||||||
std::ostream& out = *(std::ostream*)pUserData;
|
std::ostream& out = *(std::ostream*)pUserData;
|
||||||
@@ -106,11 +106,11 @@ public:
|
|||||||
return PH7_OK;
|
return PH7_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void serveDirectoy(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, const boost::filesystem::path& dir);
|
void serveDirectoy(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Poco::Net::HTMLForm& form, const boost::filesystem::path& dir);
|
||||||
|
|
||||||
void serveRegularFile(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, const boost::filesystem::path& file);
|
void serveRegularFile(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Poco::Net::HTMLForm& form, const boost::filesystem::path& file);
|
||||||
|
|
||||||
void servePhpFile(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, const boost::filesystem::path& file);
|
void servePhpFile(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Poco::Net::HTMLForm& form, const boost::filesystem::path& file);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+37
-33
@@ -27,44 +27,48 @@ HOS_SERVICE_IMPL_INFO( GenericWebResourceHandlerFactory, // Implementation
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SchemaResourceHandler::_handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
void SchemaResourceHandler::_handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Net::HTMLForm& form) {
|
||||||
Poco::URI uri(req.getURI());
|
if (req.getMethod() == Net::HTTPRequest::HTTP_GET || req.getMethod() == Net::HTTPRequest::HTTP_POST) {
|
||||||
std::vector<std::string> pathPieces, matchPieces;
|
Poco::URI uri(req.getURI());
|
||||||
uri.getPathSegments(pathPieces);
|
std::vector<std::string> pathPieces, matchPieces;
|
||||||
matchUri.getPathSegments(matchPieces);
|
uri.getPathSegments(pathPieces);
|
||||||
|
matchUri.getPathSegments(matchPieces);
|
||||||
|
|
||||||
// Requested URL is too short to contain any schema
|
// Requested URL is too short to contain any schema
|
||||||
if (pathPieces.size() <= matchPieces.size()) {
|
if (pathPieces.size() <= matchPieces.size()) {
|
||||||
throw WebResourceHandlerException("No schema given.", Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
throw WebResourceHandlerException("No schema given.", Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
||||||
|
|
||||||
// Requested URL may contain a valid schema
|
// Requested URL may contain a valid schema
|
||||||
} else {
|
} else {
|
||||||
// Get requested schema
|
// Get requested schema
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
for (int i = matchPieces.size(); i < pathPieces.size(); i++) {
|
for (int i = matchPieces.size(); i < pathPieces.size(); i++) {
|
||||||
ss << "/" << pathPieces[i];
|
ss << "/" << pathPieces[i];
|
||||||
}
|
}
|
||||||
auto schemaPath = (boost::format("hos:schema:/%1%") % ss.str()).str();
|
auto schemaPath = (boost::format("hos:schema:/%1%") % ss.str()).str();
|
||||||
// Try to retrieve schema
|
// Try to retrieve schema
|
||||||
try {
|
try {
|
||||||
auto schema = schemaLoader->GetSchema(schemaPath);
|
auto schema = schemaLoader->GetSchema(schemaPath);
|
||||||
Net::HTMLForm form(req);
|
std::string pointer;
|
||||||
if (form.has("pointer")) {
|
if (getPointerParameter(pointer, form)) {
|
||||||
std::string pointer = form.get("pointer");
|
if (schema.HasPath(pointer)) {
|
||||||
if (schema.HasPath(pointer)) {
|
schema = schema.GetPath(pointer);
|
||||||
schema = schema.GetPath(pointer);
|
} else {
|
||||||
} else {
|
throw WebResourceHandlerException((boost::format("Could not resolve pointer \"%1%\"") % pointer ).str(),
|
||||||
throw WebResourceHandlerException((boost::format("Could not resolve pointer \"%1%\"") % pointer ).str(),
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
||||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
}
|
||||||
}
|
}
|
||||||
|
handleResponse(req, resp, form, schema);
|
||||||
|
} catch(WebResourceHandlerException& e) {
|
||||||
|
throw e;
|
||||||
|
} catch(std::exception& e) {
|
||||||
|
throw WebResourceHandlerException((boost::format("Could not find schema \"%1%\": %2%") % schemaPath % e.what()).str(),
|
||||||
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
||||||
}
|
}
|
||||||
handleResponse(req, resp, schema);
|
|
||||||
} catch(WebResourceHandlerException& e) {
|
|
||||||
throw e;
|
|
||||||
} catch(std::exception& e) {
|
|
||||||
throw WebResourceHandlerException((boost::format("Could not find schema \"%1%\": %2%") % schemaPath % e.what()).str(),
|
|
||||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
handleErrorResponse(req, resp, form, (boost::format("HTTP method %1% not supported") % req.getMethod()).str(),
|
||||||
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_IMPLEMENTED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@ public:
|
|||||||
SchemaResourceHandler(Poco::URI matchUri, ros::NodeHandle* nodehandle, utils::SchemaLoader* schemaLoader, webserver::WebServerService* service)
|
SchemaResourceHandler(Poco::URI matchUri, ros::NodeHandle* nodehandle, utils::SchemaLoader* schemaLoader, webserver::WebServerService* service)
|
||||||
: matchUri(matchUri), nodehandle(nodehandle), schemaLoader(schemaLoader), service(service) {}
|
: matchUri(matchUri), nodehandle(nodehandle), schemaLoader(schemaLoader), service(service) {}
|
||||||
|
|
||||||
virtual void _handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override;
|
virtual void _handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Poco::Net::HTMLForm& form) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -44,7 +44,7 @@ Poco::Net::HTTPRequestHandler* WebSocketTestFactory::createRequestHandler(Poco::
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void WebSocketTestHandler::_handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
void WebSocketTestHandler::_handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Net::HTMLForm& form) {
|
||||||
try {
|
try {
|
||||||
Net::WebSocket ws(req, resp);
|
Net::WebSocket ws(req, resp);
|
||||||
std::cout << "WebSocket connection established." << std::endl;
|
std::cout << "WebSocket connection established." << std::endl;
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ public:
|
|||||||
WebSocketTestHandler(Poco::URI matchUri, WebSocketTestFactory* parent, webserver::WebServerService* service, bool ssl)
|
WebSocketTestHandler(Poco::URI matchUri, WebSocketTestFactory* parent, webserver::WebServerService* service, bool ssl)
|
||||||
: matchUri(matchUri), parent(parent), service(service), ssl(ssl) {}
|
: matchUri(matchUri), parent(parent), service(service), ssl(ssl) {}
|
||||||
|
|
||||||
virtual void _handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override;
|
virtual void _handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Poco::Net::HTMLForm& form) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user