.
This commit is contained in:
@@ -34,6 +34,16 @@ struct ServiceInfo {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Macro to instantiate the ServiceInfo struct.
|
||||||
|
*/
|
||||||
|
#define HOS_SERVICE_IMPL_INFO(ImplClass, ServiceName, ServiceMajor, ServiceMinor) \
|
||||||
|
template<> const char* ::hos::cosgi::service::implementation::ServiceInfo<ImplClass>::name = ServiceName; \
|
||||||
|
template<> const int ::hos::cosgi::service::implementation::ServiceInfo<ImplClass>::major = ServiceMajor; \
|
||||||
|
template<> const int ::hos::cosgi::service::implementation::ServiceInfo<ImplClass>::minor = ServiceMinor;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of interface::Object.
|
* Implementation of interface::Object.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -113,7 +113,8 @@ int main(int argc, char **argv) {
|
|||||||
// Create and register hos-core-service
|
// Create and register hos-core-service
|
||||||
CoreServiceImpl hosCoreService(rosPublicNodeHandle, rosPrivateNodeHandle);
|
CoreServiceImpl hosCoreService(rosPublicNodeHandle, rosPrivateNodeHandle);
|
||||||
service_registration_pt reg = nullptr;
|
service_registration_pt reg = nullptr;
|
||||||
bundleContext_registerService(context, (char*)CoreService::SERVICE_NAME, &hosCoreService, nullptr, ®);
|
CoreService* coreInterface = dynamic_cast<CoreService*>(&hosCoreService);
|
||||||
|
bundleContext_registerService(context, (char*)CoreService::SERVICE_NAME, coreInterface, nullptr, ®);
|
||||||
ROS_INFO("HOS core service registered");
|
ROS_INFO("HOS core service registered");
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ find_package(catkin REQUIRED COMPONENTS
|
|||||||
hos_core_msgs
|
hos_core_msgs
|
||||||
hos_cosgi_core
|
hos_cosgi_core
|
||||||
hos_deps
|
hos_deps
|
||||||
|
hos_cosgi_webserver
|
||||||
hos_cpp_utils
|
hos_cpp_utils
|
||||||
roscpp
|
roscpp
|
||||||
)
|
)
|
||||||
@@ -16,6 +17,7 @@ find_package(APR REQUIRED)
|
|||||||
find_package(CELIX REQUIRED)
|
find_package(CELIX REQUIRED)
|
||||||
find_package(Boost REQUIRED)
|
find_package(Boost REQUIRED)
|
||||||
find_package(libvariant REQUIRED)
|
find_package(libvariant REQUIRED)
|
||||||
|
find_package(Poco REQUIRED COMPONENTS Net NetSSL)
|
||||||
|
|
||||||
|
|
||||||
###################################
|
###################################
|
||||||
@@ -42,6 +44,7 @@ include_directories(
|
|||||||
${APR_INCLUDE_DIR}
|
${APR_INCLUDE_DIR}
|
||||||
${APR_INCLUDE_DIR}/apr-1.0
|
${APR_INCLUDE_DIR}/apr-1.0
|
||||||
${libvariant_INCLUDE_DIR}
|
${libvariant_INCLUDE_DIR}
|
||||||
|
${Poco_INCLUDE_DIRS}
|
||||||
)
|
)
|
||||||
|
|
||||||
set(BUNDLE_SYMBOLICNAME "hos.hos_devicerepository")
|
set(BUNDLE_SYMBOLICNAME "hos.hos_devicerepository")
|
||||||
@@ -52,12 +55,14 @@ bundle(hos_cosgi_devicerepository
|
|||||||
SOURCES
|
SOURCES
|
||||||
${PROJECT_SOURCE_DIR}/src/BundleActivator
|
${PROJECT_SOURCE_DIR}/src/BundleActivator
|
||||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/devicerepository/DeviceRepositoryServiceImpl
|
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/devicerepository/DeviceRepositoryServiceImpl
|
||||||
|
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/webresource/DeviceRepoHandler
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(hos_cosgi_devicerepository
|
target_link_libraries(hos_cosgi_devicerepository
|
||||||
${catkin_LIBRARIES}
|
${catkin_LIBRARIES}
|
||||||
${APR_LIBRARIES}
|
${APR_LIBRARIES}
|
||||||
${libvariant_LIBRARY}
|
${libvariant_LIBRARY}
|
||||||
|
${Poco_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,7 @@
|
|||||||
<build_depend>roscpp</build_depend>
|
<build_depend>roscpp</build_depend>
|
||||||
<build_depend>hos_deps</build_depend>
|
<build_depend>hos_deps</build_depend>
|
||||||
<build_depend>hos_cpp_utils</build_depend>
|
<build_depend>hos_cpp_utils</build_depend>
|
||||||
|
<build_depend>hos_cosgi_webserver</build_depend>
|
||||||
<run_depend>hos_celix</run_depend>
|
<run_depend>hos_celix</run_depend>
|
||||||
<run_depend>hos_core_msgs</run_depend>
|
<run_depend>hos_core_msgs</run_depend>
|
||||||
<run_depend>hos_cosgi_core</run_depend>
|
<run_depend>hos_cosgi_core</run_depend>
|
||||||
|
|||||||
@@ -11,18 +11,25 @@
|
|||||||
#include <hos/cosgi/celix.h>
|
#include <hos/cosgi/celix.h>
|
||||||
// CoreService
|
// CoreService
|
||||||
#include <hos/cosgi/service/core/CoreService.h>
|
#include <hos/cosgi/service/core/CoreService.h>
|
||||||
|
// Services
|
||||||
#include "hos/cosgi/service/devicerepository/DeviceRepositoryServiceImpl.h"
|
#include "hos/cosgi/service/devicerepository/DeviceRepositoryServiceImpl.h"
|
||||||
|
#include "hos/cosgi/service/webresource/DeviceRepoHandler.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace hos::cosgi;
|
using namespace hos::cosgi;
|
||||||
using namespace hos::cosgi::service::devicerepository;
|
using namespace hos::cosgi::service::devicerepository;
|
||||||
|
using namespace hos::cosgi::service::webserver;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct UserData {
|
struct UserData {
|
||||||
apr_pool_t* memoryPool = nullptr;
|
apr_pool_t* memoryPool = nullptr;
|
||||||
std::unique_ptr<DeviceRepositoryServiceImpl> serviceImpl;
|
std::unique_ptr<DeviceRepositoryServiceImpl> serviceImpl;
|
||||||
|
std::unique_ptr<webresource::DeviceRepoHandlerFactory> webResourceImpl;
|
||||||
service_registration_pt serviceReg = nullptr;
|
service_registration_pt serviceReg = nullptr;
|
||||||
|
service_registration_pt webResourceReg = nullptr;
|
||||||
|
service_registration_pt webResourceReg2 = nullptr;
|
||||||
|
service_registration_pt webResourceReg3 = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -65,6 +72,12 @@ celix_status_t bundleActivator_start(void * userData, bundle_context_pt context)
|
|||||||
}
|
}
|
||||||
myUserData->serviceImpl.reset(new DeviceRepositoryServiceImpl());
|
myUserData->serviceImpl.reset(new DeviceRepositoryServiceImpl());
|
||||||
|
|
||||||
|
// Create device repository webresource
|
||||||
|
if (myUserData->webResourceReg != nullptr) {
|
||||||
|
serviceRegistration_unregister(myUserData->webResourceReg);
|
||||||
|
}
|
||||||
|
myUserData->webResourceImpl.reset(new webresource::DeviceRepoHandlerFactory(myUserData->serviceImpl.get()));
|
||||||
|
|
||||||
// Get core service
|
// Get core service
|
||||||
service_reference_pt ref = nullptr;
|
service_reference_pt ref = nullptr;
|
||||||
bundleContext_getServiceReference(context, (char*)service::core::CoreService::SERVICE_NAME, &ref);
|
bundleContext_getServiceReference(context, (char*)service::core::CoreService::SERVICE_NAME, &ref);
|
||||||
@@ -76,9 +89,29 @@ celix_status_t bundleActivator_start(void * userData, bundle_context_pt context)
|
|||||||
myUserData->serviceImpl->setCoreService(coreService);
|
myUserData->serviceImpl->setCoreService(coreService);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register device repository service
|
// Register device repository service and webresource
|
||||||
if (myUserData->serviceImpl->isInitialized()) {
|
if (myUserData->serviceImpl->isInitialized()) {
|
||||||
bundleContext_registerService(context, (char*)DeviceRepositoryService::SERVICE_NAME, myUserData->serviceImpl.get(), nullptr, &myUserData->serviceReg);
|
// repository service
|
||||||
|
DeviceRepositoryService* repoInterface = dynamic_cast<DeviceRepositoryService*>(myUserData->serviceImpl.get());
|
||||||
|
bundleContext_registerService(context, (char*)DeviceRepositoryService::SERVICE_NAME, repoInterface, nullptr, &myUserData->serviceReg);
|
||||||
|
// web resource
|
||||||
|
WebResourceHandlerFactory* webInterface = dynamic_cast<WebResourceHandlerFactory*>(myUserData->webResourceImpl.get());
|
||||||
|
// ToDo: Properly delete properties
|
||||||
|
properties_pt webResourceProps = properties_create();
|
||||||
|
properties_set(webResourceProps, (char*)"path", (char*)"/devices");
|
||||||
|
bundleContext_registerService(context, (char*)WebResourceHandlerFactory::SERVICE_NAME, webInterface, webResourceProps, &myUserData->webResourceReg);
|
||||||
|
|
||||||
|
// web resource
|
||||||
|
// ToDo: Properly delete properties
|
||||||
|
properties_pt webResourceProps2 = properties_create();
|
||||||
|
properties_set(webResourceProps2, (char*)"path", (char*)"/blabla");
|
||||||
|
bundleContext_registerService(context, (char*)WebResourceHandlerFactory::SERVICE_NAME, webInterface, webResourceProps2, &myUserData->webResourceReg2);
|
||||||
|
|
||||||
|
// web resource
|
||||||
|
// ToDo: Properly delete properties
|
||||||
|
properties_pt webResourceProps3 = properties_create();
|
||||||
|
properties_set(webResourceProps3, (char*)"path", (char*)"/blabla");
|
||||||
|
bundleContext_registerService(context, (char*)WebResourceHandlerFactory::SERVICE_NAME, webInterface, webResourceProps3, &myUserData->webResourceReg3);
|
||||||
}
|
}
|
||||||
|
|
||||||
ROS_INFO("DeviceRepositoryService: Bundle successfully started");
|
ROS_INFO("DeviceRepositoryService: Bundle successfully started");
|
||||||
|
|||||||
+3
-3
@@ -17,9 +17,9 @@ namespace devicerepository {
|
|||||||
|
|
||||||
|
|
||||||
// Service information
|
// Service information
|
||||||
template<> const char* implementation::ServiceInfo<DeviceRepositoryServiceImpl>::name = service::devicerepository::DeviceRepositoryService::SERVICE_NAME;
|
HOS_SERVICE_IMPL_INFO( DeviceRepositoryServiceImpl, // Implementation
|
||||||
template<> const int implementation::ServiceInfo<DeviceRepositoryServiceImpl>::major = 1;
|
service::devicerepository::DeviceRepositoryService::SERVICE_NAME, // Service Name
|
||||||
template<> const int implementation::ServiceInfo<DeviceRepositoryServiceImpl>::minor = 0;
|
1, 0 ) // Version
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+243
@@ -0,0 +1,243 @@
|
|||||||
|
|
||||||
|
#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>
|
||||||
|
|
||||||
|
|
||||||
|
// 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({"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();
|
||||||
|
} });
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Net::HTTPRequestHandler* DeviceRepoHandlerFactory::createRequestHandler( Poco::URI matchUri, const Net::HTTPServerRequest& request, bool ssl ) noexcept {
|
||||||
|
return new DeviceRepoHandler(matchUri, repoService, infoCategoryFuncs, ssl);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void DeviceRepoHandler::_handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
||||||
|
// Get method parameter
|
||||||
|
Net::HTMLForm form(req);
|
||||||
|
DevicesAPIMethod dataMethod = DevicesAPIMethod::GET; // Default method is get
|
||||||
|
std::string methodValue;
|
||||||
|
if (form.has("method")) {
|
||||||
|
std::string methodRaw = form.get("method");
|
||||||
|
bool requireValue = false;
|
||||||
|
if (methodRaw == "get") {
|
||||||
|
// do nothing
|
||||||
|
} else if (methodRaw == "command") {
|
||||||
|
dataMethod = DevicesAPIMethod::COMMAND;
|
||||||
|
requireValue = true;
|
||||||
|
} else if (methodRaw.compare("statusupdate") == 0) {
|
||||||
|
dataMethod = DevicesAPIMethod::STATUSUPDATE;
|
||||||
|
requireValue = true;
|
||||||
|
} else {
|
||||||
|
throw webserver::resources::WebResourceHandlerException((boost::format("Unknown API method \"%1%\"") % methodRaw).str(),
|
||||||
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
||||||
|
}
|
||||||
|
if (requireValue) {
|
||||||
|
if (form.has("value")) {
|
||||||
|
methodValue = form.get("value");
|
||||||
|
} else {
|
||||||
|
throw webserver::resources::WebResourceHandlerException((boost::format("API method \"%1%\" requires a value parameter.") % methodRaw).str(),
|
||||||
|
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 (dataMethod != DevicesAPIMethod::GET) {
|
||||||
|
throw webserver::resources::WebResourceHandlerException("Requested API method requires a device",
|
||||||
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
||||||
|
}
|
||||||
|
Variant result;
|
||||||
|
for (auto d : repoService->getDevices()) {
|
||||||
|
auto dev = d.lock();
|
||||||
|
result[dev->getDeviceID()] = getDeviceInfo(dev.get(), req);
|
||||||
|
}
|
||||||
|
handleResponse(req, resp, result);
|
||||||
|
|
||||||
|
// Device given
|
||||||
|
} else {
|
||||||
|
std::string devid = pathPieces[matchPieces.size()];
|
||||||
|
auto device = repoService->getDevice(devid);
|
||||||
|
if (!device.expired()) {
|
||||||
|
switch (dataMethod) {
|
||||||
|
case DevicesAPIMethod::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 DevicesAPIMethod::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 DevicesAPIMethod::STATUSUPDATE:
|
||||||
|
throw webserver::resources::WebResourceHandlerException("ToDo: Implement method.");
|
||||||
|
default:
|
||||||
|
throw webserver::resources::WebResourceHandlerException("Internal Server Error");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw webserver::resources::WebResourceHandlerException((boost::format("Could not find device \"%1%\"") % devid).str(),
|
||||||
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void DeviceRepoHandler::_handlePOST(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
||||||
|
throw webserver::resources::WebResourceHandlerException("ToDo: Implement POST.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Variant DeviceRepoHandler::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::resources::WebResourceHandlerException((boost::format("Unknown path \"%1%\" for device info category \"%2%\".") % pathstr % category).str(),
|
||||||
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw webserver::resources::WebResourceHandlerException((boost::format("Unknown device info category \"%1%\"") % category).str(),
|
||||||
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void DeviceRepoHandler::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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace resources
|
||||||
|
} // namespace webserver
|
||||||
|
} // namespace service
|
||||||
|
} // namespace cosgi
|
||||||
|
} // namespace hos
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#include <hos/cosgi/service/Implementation.h>
|
||||||
|
#include <hos/cosgi/service/webserver/WebServerService.h>
|
||||||
|
#include <hos/cosgi/service/webserver/resources/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 <functional>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Service Namespace
|
||||||
|
namespace hos {
|
||||||
|
namespace cosgi {
|
||||||
|
namespace service {
|
||||||
|
namespace devicerepository {
|
||||||
|
namespace webresource {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
enum class DevicesAPIMethod {
|
||||||
|
GET,
|
||||||
|
COMMAND,
|
||||||
|
STATUSUPDATE
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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:
|
||||||
|
devicerepository::DeviceRepositoryService* repoService;
|
||||||
|
std::map<std::string, infoCategoryFunc_t> infoCategoryFuncs;
|
||||||
|
public:
|
||||||
|
DeviceRepoHandlerFactory(devicerepository::DeviceRepositoryService* repoService);
|
||||||
|
virtual Poco::Net::HTTPRequestHandler* createRequestHandler(Poco::URI matchUri, const Poco::Net::HTTPServerRequest& request, bool ssl ) noexcept override;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 DeviceRepoHandler
|
||||||
|
: public virtual webserver::resources::WebResourceHandlerImpl {
|
||||||
|
|
||||||
|
private:
|
||||||
|
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:
|
||||||
|
|
||||||
|
DeviceRepoHandler( 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) {}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
@@ -58,7 +58,8 @@ celix_status_t cb_serviceChanged(void* listener, service_event_pt event) {
|
|||||||
|
|
||||||
// Register rule engine service
|
// Register rule engine service
|
||||||
if (checkReg && !myUserData->serviceReg && myUserData->serviceImpl->isInitialized()) {
|
if (checkReg && !myUserData->serviceReg && myUserData->serviceImpl->isInitialized()) {
|
||||||
bundleContext_registerService(myUserData->bundleContext, (char*)RuleEngineServiceImpl::SERVICE_NAME, myUserData->serviceImpl.get(), nullptr, &myUserData->serviceReg);
|
RuleEngineService* engineInterface = dynamic_cast<RuleEngineService*>(myUserData->serviceImpl.get());
|
||||||
|
bundleContext_registerService(myUserData->bundleContext, (char*)RuleEngineServiceImpl::SERVICE_NAME, engineInterface, nullptr, &myUserData->serviceReg);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (event->type == OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING) {
|
} else if (event->type == OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING) {
|
||||||
@@ -131,7 +132,8 @@ celix_status_t bundleActivator_start(void * userData, bundle_context_pt context)
|
|||||||
|
|
||||||
// Register rule engine service
|
// Register rule engine service
|
||||||
if (myUserData->serviceImpl->isInitialized()) {
|
if (myUserData->serviceImpl->isInitialized()) {
|
||||||
bundleContext_registerService(context, (char*)RuleEngineServiceImpl::SERVICE_NAME, myUserData->serviceImpl.get(), nullptr, &myUserData->serviceReg);
|
RuleEngineService* engineInterface = dynamic_cast<RuleEngineService*>(myUserData->serviceImpl.get());
|
||||||
|
bundleContext_registerService(context, (char*)RuleEngineServiceImpl::SERVICE_NAME, engineInterface, nullptr, &myUserData->serviceReg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register service listener
|
// Register service listener
|
||||||
|
|||||||
@@ -27,15 +27,14 @@ namespace service {
|
|||||||
namespace ruleengine {
|
namespace ruleengine {
|
||||||
|
|
||||||
|
|
||||||
using namespace ::libvariant;
|
using namespace libvariant;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Service information
|
// Service information
|
||||||
template<> const char* implementation::ServiceInfo<RuleEngineServiceImpl>::name = service::ruleengine::RuleEngineService::SERVICE_NAME;
|
HOS_SERVICE_IMPL_INFO( RuleEngineServiceImpl, // Implementation
|
||||||
template<> const int implementation::ServiceInfo<RuleEngineServiceImpl>::major = 1;
|
service::ruleengine::RuleEngineService::SERVICE_NAME, // Service Name
|
||||||
template<> const int implementation::ServiceInfo<RuleEngineServiceImpl>::minor = 0;
|
1, 0 ) // Version
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void RuleEngineServiceImpl::setCoreService(service::core::CoreService* coreService) noexcept {
|
void RuleEngineServiceImpl::setCoreService(service::core::CoreService* coreService) noexcept {
|
||||||
|
|||||||
@@ -48,7 +48,8 @@ celix_status_t cb_serviceChanged(void* listener, service_event_pt event) {
|
|||||||
}
|
}
|
||||||
// Register python scripting service
|
// Register python scripting service
|
||||||
if (checkReg && !myUserData->serviceReg && myUserData->serviceImpl->isInitialized()) {
|
if (checkReg && !myUserData->serviceReg && myUserData->serviceImpl->isInitialized()) {
|
||||||
bundleContext_registerService(myUserData->bundleContext, (char*)PyScriptingService::SERVICE_NAME, myUserData->serviceImpl.get(), nullptr, &myUserData->serviceReg);
|
ScriptingService* serviceInterface = dynamic_cast<ScriptingService*>(myUserData->serviceImpl.get());
|
||||||
|
bundleContext_registerService(myUserData->bundleContext, (char*)PyScriptingService::SERVICE_NAME, serviceInterface, nullptr, &myUserData->serviceReg);
|
||||||
}
|
}
|
||||||
} else if (event->type == OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING) {
|
} else if (event->type == OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING) {
|
||||||
}
|
}
|
||||||
@@ -111,7 +112,8 @@ celix_status_t bundleActivator_start(void * userData, bundle_context_pt context)
|
|||||||
}
|
}
|
||||||
// Register hos-ruleexecution-python-service
|
// Register hos-ruleexecution-python-service
|
||||||
if (myUserData->serviceImpl->isInitialized()) {
|
if (myUserData->serviceImpl->isInitialized()) {
|
||||||
bundleContext_registerService(context, (char*)PyScriptingService::SERVICE_NAME, myUserData->serviceImpl.get(), nullptr, &myUserData->serviceReg);
|
ScriptingService* serviceInterface = dynamic_cast<ScriptingService*>(myUserData->serviceImpl.get());
|
||||||
|
bundleContext_registerService(context, (char*)PyScriptingService::SERVICE_NAME, serviceInterface, nullptr, &myUserData->serviceReg);
|
||||||
}
|
}
|
||||||
// Register service listener
|
// Register service listener
|
||||||
myUserData->myServiceListener.handle = myUserData;
|
myUserData->myServiceListener.handle = myUserData;
|
||||||
|
|||||||
+3
-3
@@ -15,9 +15,9 @@ namespace python {
|
|||||||
|
|
||||||
|
|
||||||
// Service information
|
// Service information
|
||||||
template<> const char* implementation::ServiceInfo<PyScriptingService>::name = service::scripting::python::PyScriptingService::SERVICE_NAME;
|
HOS_SERVICE_IMPL_INFO( PyScriptingService, // Implementation
|
||||||
template<> const int implementation::ServiceInfo<PyScriptingService>::major = 1;
|
service::scripting::python::PyScriptingService::SERVICE_NAME, // Service Name
|
||||||
template<> const int implementation::ServiceInfo<PyScriptingService>::minor = 0;
|
1, 0 ) // Version
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ project(hos_cosgi_webserver)
|
|||||||
## Find catkin macros and libraries
|
## Find catkin macros and libraries
|
||||||
find_package(catkin REQUIRED COMPONENTS
|
find_package(catkin REQUIRED COMPONENTS
|
||||||
hos_celix
|
hos_celix
|
||||||
hos_cosgi_devicerepository
|
|
||||||
hos_cosgi_core
|
hos_cosgi_core
|
||||||
hos_cpp_utils
|
hos_cpp_utils
|
||||||
hos_deps
|
hos_deps
|
||||||
@@ -56,7 +55,7 @@ bundle(hos_cosgi_webserver
|
|||||||
SOURCES
|
SOURCES
|
||||||
${PROJECT_SOURCE_DIR}/src/BundleActivator
|
${PROJECT_SOURCE_DIR}/src/BundleActivator
|
||||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/webserver/WebServerServiceImpl
|
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/webserver/WebServerServiceImpl
|
||||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/webserver/resources/DevicesResource
|
# ${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/webserver/resources/DevicesResource
|
||||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/webserver/resources/SchemaResource
|
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/webserver/resources/SchemaResource
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDENZtNsygHr0t1
|
||||||
|
jgXQsaOCAYqswNxJpIsXQFPoJovvAO8cEhEaIJIzvso28eM4LOEEJN/JGRRNlXJT
|
||||||
|
8C0lFAwMULY0cO01pGBZO5rFDwY2hDNbWASkPQVq4a+oaxFfPDRpOsjGf8koj3Ev
|
||||||
|
bGjtw7UWhgSC42VpJZS3JxVvSlfZc+UKEdhcGHPZoYOVIMTaCcOky/u3ARh226Yw
|
||||||
|
bcqqbVrXkEjTjNXZIYu86W2fZdf3spDvhpbOWvzFo1HLY87cwEvUa5eDors8cW5Y
|
||||||
|
uVNWBsiPrQUxSEUT/BGjnlJqXMD5VfxvUvYYXK9gLGyjRnxwkiKgKPc+bmx/EBdx
|
||||||
|
KAZE23m1AgMBAAECggEAFcrab/vZE1lt6SWYEcDZJ0RikaNuFCPZawCzERLO8gHJ
|
||||||
|
jPWYvq0lb+fd79JX6VJav6oUzPIjJibWJuqDKR4b5HZGdnagchfKt75+BysPBpkS
|
||||||
|
Vy/kfBVm96MPboZNzKUUMSfdSubAgefEq36//MCC6XiDIcJ97frFlL4bjFvWfAlI
|
||||||
|
etnPbJapkM7o30tpTA/M1aEXHfVyJAceLztFb+8E3PaAWQ7nSlck42ESn5QGlIo9
|
||||||
|
2jlwgb+h96WgAZgBnTJFtmZTzhFVDca9hDPLe+CuF2ybyyHR3U1WEY3T4c47zUgZ
|
||||||
|
nchWhtGu+vk8Hq275RirjDmJ7xeCpn056C4g3oYGtQKBgQDhdE90LoOlLClA7Q8E
|
||||||
|
Ie+6J29+RcV12ppIx/9WQYQG0trMtAXRRC/9C8DAcE4fgF49yfEMM2oKI8H7nU6N
|
||||||
|
+0KzuRQEEwSnz0Y931D0cxpJqh1owBW812Bf4J7nbL5Q5zYIGmv5l7geHdIEqI1l
|
||||||
|
RVBrk4dVdffxeS7oWbKi9lUH0wKBgQDeyvX5vZkXtV3A8ZBgwnkstu/KHEdF2e8P
|
||||||
|
dayldtuVgUReR5OqrfgXRcmK3uILzGA7xxuwH+mtepwri/NOsgP7DPTP8/irLgLf
|
||||||
|
5w5G6YeqU90VDE8pEDeNpXV3mCZ8471OncaDjGrTbOaf1PS31HknqpNG8+q5sgEa
|
||||||
|
pM3fgMlLVwKBgERRLV5kVenwNtQAwaMb8Xu0RXm7BLnQsx3I1Nu7YJl8vWZ4Sqb+
|
||||||
|
BZilPhRSM6oiCOyqS8vJrKFD8p0fLtWhRLYXKDSP2sJK8dr/15UrZ9TYoq7CPhQK
|
||||||
|
I58J/rzb29PCLEJKV1u7mMQvfxuAQ9BjL5pZixHffHGEqi0oORRelqeXAoGBAJe+
|
||||||
|
SyzPax9Pw0xv+3M74caHzuisvAqidgXkkzObsdGxWryQKc59cVWAjdYNGo8Io57z
|
||||||
|
bTNXeRRUR1wNlSlLbBSo7XFZ7UvCKekQeZPo6SMkvZbhbGU+i2fpgwly0vwLLVwH
|
||||||
|
cDcXA4d/S9Ee/ZLbn61Zq7gO2BekWsYn66TIFdI/AoGBAJvHKSziHh8zqJQVHtxK
|
||||||
|
mBLeCnfhUTdm7enUAJ4pxWswwnRUjX8eAg87oHbCm32RP/RtnOKQUUEJS3bqwDT4
|
||||||
|
tySdE1Jo6khrx1G+8RBJ8HB6Ne1zd9PN5Pkc3+aG9Jli6pOuuNQCiRi1xO1ZDAC4
|
||||||
|
mt6CUGQbEtDuv56qXfLl8++B
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICtDCCAZygAwIBAgIJAPyF1ij7MJfbMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV
|
||||||
|
BAMTB2t1YnVudHUwHhcNMTUwMjAxMjM0MTMxWhcNMjUwMTI5MjM0MTMxWjASMRAw
|
||||||
|
DgYDVQQDEwdrdWJ1bnR1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
|
||||||
|
xDWbTbMoB69LdY4F0LGjggGKrMDcSaSLF0BT6CaL7wDvHBIRGiCSM77KNvHjOCzh
|
||||||
|
BCTfyRkUTZVyU/AtJRQMDFC2NHDtNaRgWTuaxQ8GNoQzW1gEpD0FauGvqGsRXzw0
|
||||||
|
aTrIxn/JKI9xL2xo7cO1FoYEguNlaSWUtycVb0pX2XPlChHYXBhz2aGDlSDE2gnD
|
||||||
|
pMv7twEYdtumMG3Kqm1a15BI04zV2SGLvOltn2XX97KQ74aWzlr8xaNRy2PO3MBL
|
||||||
|
1GuXg6K7PHFuWLlTVgbIj60FMUhFE/wRo55SalzA+VX8b1L2GFyvYCxso0Z8cJIi
|
||||||
|
oCj3Pm5sfxAXcSgGRNt5tQIDAQABow0wCzAJBgNVHRMEAjAAMA0GCSqGSIb3DQEB
|
||||||
|
CwUAA4IBAQAseKosUKyIpOzEChtKzBdWnvGYq7RHA8mWL+4RLhglbvjMCq/5Dt1B
|
||||||
|
1vAPexTz96Zti+erHQglTanpIsJjw8fuYVPYI0DTCw3Vp2abTrlmOR6oLLE193LN
|
||||||
|
+yE5cERaRYSTkJq49FYzYhKoAuNKRb6zR2BAYyO/pcp8l3gBgtQAp6A/cRhhvHd6
|
||||||
|
DgmzphHscK1nZXGqXgND+gfKTvOi7RZaSBrtG8hotXuh81gV3R7zIluC63/V9ho8
|
||||||
|
MyDLmaCKF5q+wofkwCh6Glx47oWfwY7CS13qRyAF3lzKxd90YNefBF7E64FS5R3y
|
||||||
|
rcTcMX167QElsdpQY/rOEjaXm/z4XbOJ
|
||||||
|
-----END CERTIFICATE-----
|
||||||
+16
-7
@@ -31,15 +31,28 @@ namespace webserver {
|
|||||||
class WebServerService;
|
class WebServerService;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class WebResourceHandlerFactory
|
class WebResourceHandlerFactory
|
||||||
: public virtual interface::Object {
|
: public virtual interface::Service {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual Poco::Net::HTTPRequestHandler* createRequestHandler( const Poco::Net::HTTPServerRequest& request, bool ssl = false ) noexcept = 0;
|
|
||||||
|
static constexpr const char* SERVICE_NAME = "hos_webresource_factory";
|
||||||
|
|
||||||
|
virtual Poco::Net::HTTPRequestHandler* createRequestHandler( Poco::URI matchUri, const Poco::Net::HTTPServerRequest& request, bool ssl ) noexcept = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class WebServerService
|
class WebServerService
|
||||||
: public virtual interface::Service {
|
: public virtual interface::Service {
|
||||||
|
|
||||||
@@ -47,11 +60,7 @@ public:
|
|||||||
|
|
||||||
static constexpr const char* SERVICE_NAME = "hos_webserver_service";
|
static constexpr const char* SERVICE_NAME = "hos_webserver_service";
|
||||||
|
|
||||||
virtual bool registerWebResource(const std::string& path, std::shared_ptr<WebResourceHandlerFactory> factory) noexcept = 0;
|
virtual bool registerWebResource(const std::string& path, WebResourceHandlerFactory* factory) noexcept = 0;
|
||||||
|
|
||||||
virtual const Poco::URI& getPrefixPath() noexcept = 0;
|
|
||||||
|
|
||||||
virtual const std::vector<std::string>& getPrefixPathPieces() noexcept = 0;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+17
-4
@@ -3,10 +3,12 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <hos/cosgi/service/webserver/WebServerService.h>
|
#include <hos/cosgi/service/webserver/WebServerService.h>
|
||||||
|
#include <hos/cosgi/service/Implementation.h>
|
||||||
#include <Poco/Net/HTTPRequestHandler.h>
|
#include <Poco/Net/HTTPRequestHandler.h>
|
||||||
#include <Poco/Net/HTTPServerRequest.h>
|
#include <Poco/Net/HTTPServerRequest.h>
|
||||||
#include <Poco/Net/HTTPServerResponse.h>
|
#include <Poco/Net/HTTPServerResponse.h>
|
||||||
#include <Poco/Net/HTMLForm.h>
|
#include <Poco/Net/HTMLForm.h>
|
||||||
|
#include <Poco/URI.h>
|
||||||
#include <Variant/Variant.h>
|
#include <Variant/Variant.h>
|
||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@@ -39,23 +41,34 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
HOS_SERVICE_IMPL_INFO( GenericWebResourceHandlerFactory, // Implementation
|
||||||
|
service::webserver::WebResourceHandlerFactory::SERVICE_NAME, // Service Name
|
||||||
|
1, 0 ) // Version
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
class GenericWebResourceHandlerFactory
|
class GenericWebResourceHandlerFactory
|
||||||
: public virtual WebResourceHandlerFactory {
|
: public virtual WebResourceHandlerFactory,
|
||||||
|
public implementation::Service<GenericWebResourceHandlerFactory> {
|
||||||
public:
|
public:
|
||||||
typedef std::function<Poco::Net::HTTPRequestHandler*(const Poco::Net::HTTPServerRequest&, bool)> factory_t;
|
typedef std::function<Poco::Net::HTTPRequestHandler*(Poco::URI matchUri, const Poco::Net::HTTPServerRequest&, bool)> factory_t;
|
||||||
private:
|
private:
|
||||||
factory_t _factory;
|
factory_t _factory;
|
||||||
public:
|
public:
|
||||||
GenericWebResourceHandlerFactory(factory_t factory)
|
GenericWebResourceHandlerFactory(factory_t factory)
|
||||||
: _factory(factory) {}
|
: _factory(factory) {}
|
||||||
virtual Poco::Net::HTTPRequestHandler* createRequestHandler( const Poco::Net::HTTPServerRequest& request, bool ssl = false ) noexcept override {
|
virtual Poco::Net::HTTPRequestHandler* createRequestHandler( Poco::URI matchUri, const Poco::Net::HTTPServerRequest& request, bool ssl ) noexcept override {
|
||||||
return _factory(request, ssl);
|
return _factory(matchUri, request, ssl);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enum class ResponseDataFormat : int {
|
enum class ResponseDataFormat : int {
|
||||||
JSON,
|
JSON,
|
||||||
JSONP,
|
JSONP,
|
||||||
|
|||||||
@@ -41,13 +41,13 @@
|
|||||||
<!-- <test_depend>gtest</test_depend> -->
|
<!-- <test_depend>gtest</test_depend> -->
|
||||||
<buildtool_depend>catkin</buildtool_depend>
|
<buildtool_depend>catkin</buildtool_depend>
|
||||||
<build_depend>hos_celix</build_depend>
|
<build_depend>hos_celix</build_depend>
|
||||||
<build_depend>hos_cosgi_devicerepository</build_depend>
|
<!-- <build_depend>hos_cosgi_devicerepository</build_depend>-->
|
||||||
<build_depend>hos_cosgi_core</build_depend>
|
<build_depend>hos_cosgi_core</build_depend>
|
||||||
<build_depend>hos_cpp_utils</build_depend>
|
<build_depend>hos_cpp_utils</build_depend>
|
||||||
<build_depend>hos_deps</build_depend>
|
<build_depend>hos_deps</build_depend>
|
||||||
<build_depend>roscpp</build_depend>
|
<build_depend>roscpp</build_depend>
|
||||||
<run_depend>hos_celix</run_depend>
|
<run_depend>hos_celix</run_depend>
|
||||||
<run_depend>hos_cosgi_devicerepository</run_depend>
|
<!-- <run_depend>hos_cosgi_devicerepository</run_depend>-->
|
||||||
<run_depend>hos_cosgi_core</run_depend>
|
<run_depend>hos_cosgi_core</run_depend>
|
||||||
<run_depend>hos_cpp_utils</run_depend>
|
<run_depend>hos_cpp_utils</run_depend>
|
||||||
<run_depend>hos_deps</run_depend>
|
<run_depend>hos_deps</run_depend>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ extern "C" {
|
|||||||
|
|
||||||
|
|
||||||
using namespace hos::cosgi::service::webserver;
|
using namespace hos::cosgi::service::webserver;
|
||||||
using namespace hos::cosgi::service::devicerepository;
|
//using namespace hos::cosgi::service::devicerepository;
|
||||||
using namespace hos::cosgi::service::core;
|
using namespace hos::cosgi::service::core;
|
||||||
using namespace hos::cosgi;
|
using namespace hos::cosgi;
|
||||||
|
|
||||||
@@ -46,15 +46,33 @@ celix_status_t cb_serviceChanged(void* listener, service_event_pt event) {
|
|||||||
char* serviceName = nullptr;
|
char* serviceName = nullptr;
|
||||||
bool checkReg = false;
|
bool checkReg = false;
|
||||||
serviceReference_getProperty(event->reference, (char*)OSGI_FRAMEWORK_OBJECTCLASS, &serviceName);
|
serviceReference_getProperty(event->reference, (char*)OSGI_FRAMEWORK_OBJECTCLASS, &serviceName);
|
||||||
if (serviceName && std::strcmp(serviceName, DeviceRepositoryService::SERVICE_NAME) == 0) {
|
if (serviceName && std::strcmp(serviceName, WebResourceHandlerFactory::SERVICE_NAME) == 0) {
|
||||||
|
ROS_INFO("WebServer: Web resource appeared ...");
|
||||||
|
WebResourceHandlerFactory *service = nullptr;
|
||||||
|
char* path = nullptr;
|
||||||
|
bundleContext_getService(myUserData->bundleContext, event->reference, (void**)&service);
|
||||||
|
serviceReference_getProperty(event->reference, (char*)"path", &path);
|
||||||
|
if (path) {
|
||||||
|
if (myUserData->serviceImpl->registerWebResource(path, service)) {
|
||||||
|
ROS_INFO("WebServer: Added web resource");
|
||||||
|
} else {
|
||||||
|
ROS_ERROR("WebServer: ERROR: Path already in use.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ROS_ERROR("WebServer: Web resource has no path");
|
||||||
|
}
|
||||||
|
checkReg = true;
|
||||||
|
}
|
||||||
|
/*if (serviceName && std::strcmp(serviceName, DeviceRepositoryService::SERVICE_NAME) == 0) {
|
||||||
DeviceRepositoryService *service = nullptr;
|
DeviceRepositoryService *service = nullptr;
|
||||||
bundleContext_getService(myUserData->bundleContext, event->reference, (void**)&service);
|
bundleContext_getService(myUserData->bundleContext, event->reference, (void**)&service);
|
||||||
myUserData->serviceImpl->setRepoService(service);
|
myUserData->serviceImpl->setRepoService(service);
|
||||||
checkReg = true;
|
checkReg = true;
|
||||||
}
|
}*/
|
||||||
// Register hos-devicerepository-service
|
// Register hos-devicerepository-service
|
||||||
if (checkReg && !myUserData->serviceReg && myUserData->serviceImpl->isInitialized()) {
|
if (checkReg && !myUserData->serviceReg && myUserData->serviceImpl->isInitialized()) {
|
||||||
bundleContext_registerService(myUserData->bundleContext, (char*)WebServerServiceImpl::SERVICE_NAME, myUserData->serviceImpl.get(), nullptr, &myUserData->serviceReg);
|
WebServerService* serviceInterface = dynamic_cast<WebServerService*>(myUserData->serviceImpl.get());
|
||||||
|
bundleContext_registerService(myUserData->bundleContext, (char*)WebServerServiceImpl::SERVICE_NAME, serviceInterface, nullptr, &myUserData->serviceReg);
|
||||||
}
|
}
|
||||||
} else if (event->type == OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING) {
|
} else if (event->type == OSGI_FRAMEWORK_SERVICE_EVENT_UNREGISTERING) {
|
||||||
}
|
}
|
||||||
@@ -106,13 +124,14 @@ celix_status_t bundleActivator_start(void * userData, bundle_context_pt context)
|
|||||||
myUserData->serviceImpl->setCoreService(coreService);
|
myUserData->serviceImpl->setCoreService(coreService);
|
||||||
}
|
}
|
||||||
// Get HOS Core Service
|
// Get HOS Core Service
|
||||||
service_reference_pt ref2 = nullptr;
|
/*service_reference_pt ref2 = nullptr;
|
||||||
bundleContext_getServiceReference(context, (char*)DeviceRepositoryService::SERVICE_NAME, &ref2);
|
bundleContext_getServiceReference(context, (char*)DeviceRepositoryService::SERVICE_NAME, &ref2);
|
||||||
DeviceRepositoryService* repoService = nullptr;
|
DeviceRepositoryService* repoService = nullptr;
|
||||||
bundleContext_getService(context, ref2, (void**)&repoService);
|
bundleContext_getService(context, ref2, (void**)&repoService);
|
||||||
if (repoService) {
|
if (repoService) {
|
||||||
myUserData->serviceImpl->setRepoService(repoService);
|
myUserData->serviceImpl->setRepoService(repoService);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
// Register hos-devicerepository-service
|
// Register hos-devicerepository-service
|
||||||
if (myUserData->serviceImpl->isInitialized()) {
|
if (myUserData->serviceImpl->isInitialized()) {
|
||||||
bundleContext_registerService(context, (char*)WebServerServiceImpl::SERVICE_NAME, myUserData->serviceImpl.get(), nullptr, &myUserData->serviceReg);
|
bundleContext_registerService(context, (char*)WebServerServiceImpl::SERVICE_NAME, myUserData->serviceImpl.get(), nullptr, &myUserData->serviceReg);
|
||||||
@@ -121,6 +140,30 @@ celix_status_t bundleActivator_start(void * userData, bundle_context_pt context)
|
|||||||
myUserData->myServiceListener.handle = myUserData;
|
myUserData->myServiceListener.handle = myUserData;
|
||||||
myUserData->myServiceListener.serviceChanged = cb_serviceChanged;
|
myUserData->myServiceListener.serviceChanged = cb_serviceChanged;
|
||||||
bundleContext_addServiceListener(context, &myUserData->myServiceListener, nullptr);
|
bundleContext_addServiceListener(context, &myUserData->myServiceListener, nullptr);
|
||||||
|
|
||||||
|
// Get web resources
|
||||||
|
array_list_pt references = NULL;
|
||||||
|
status = bundleContext_getServiceReferences(context, WebResourceHandlerFactory::SERVICE_NAME, NULL, &references);
|
||||||
|
if (status == CELIX_SUCCESS) {
|
||||||
|
for (int i = 0; i < arrayList_size(references); i++) {
|
||||||
|
ROS_INFO("WebServer: Found a web resource ...");
|
||||||
|
WebResourceHandlerFactory *service = nullptr;
|
||||||
|
char* path = nullptr;
|
||||||
|
service_reference_pt ref = (service_reference_pt)arrayList_get(references, i);
|
||||||
|
bundleContext_getService(context, ref, (void**)&service);
|
||||||
|
serviceReference_getProperty(ref, (char*)"path", &path);
|
||||||
|
if (path) {
|
||||||
|
if (myUserData->serviceImpl->registerWebResource(path, service)) {
|
||||||
|
ROS_INFO("WebServer: Added web resource");
|
||||||
|
} else {
|
||||||
|
ROS_ERROR("WebServer: ERROR: Path already in use.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ROS_ERROR("WebServer: Web resource has no path");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ROS_INFO("WebServerService: Bundle successfully started");
|
ROS_INFO("WebServerService: Bundle successfully started");
|
||||||
} else {
|
} else {
|
||||||
ROS_ERROR("WebServerService: Could not start bundle, user data struct is null");
|
ROS_ERROR("WebServerService: Could not start bundle, user data struct is null");
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
|
|
||||||
#include "WebServerServiceImpl.h"
|
#include "WebServerServiceImpl.h"
|
||||||
|
#include "resources/SchemaResource.h"
|
||||||
|
//#include "resources/DevicesResource.h"
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include <ros/ros.h>
|
#include <ros/ros.h>
|
||||||
#include "resources/SchemaResource.h"
|
#include <Poco/Net/KeyConsoleHandler.h>
|
||||||
#include "resources/DevicesResource.h"
|
#include <Poco/Net/ConsoleCertificateHandler.h>
|
||||||
|
#include <Poco/Net/SSLException.h>
|
||||||
|
|
||||||
|
|
||||||
namespace hos {
|
namespace hos {
|
||||||
@@ -19,9 +21,10 @@ using namespace Poco;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
template<> const char* implementation::ServiceInfo<WebServerServiceImpl>::name = service::webserver::WebServerServiceImpl::SERVICE_NAME;
|
// Service information
|
||||||
template<> const int implementation::ServiceInfo<WebServerServiceImpl>::major = 1;
|
HOS_SERVICE_IMPL_INFO( WebServerServiceImpl, // Implementation
|
||||||
template<> const int implementation::ServiceInfo<WebServerServiceImpl>::minor = 0;
|
service::webserver::WebServerServiceImpl::SERVICE_NAME, // Service Name
|
||||||
|
1, 0 ) // Version
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -42,14 +45,14 @@ void WebServerServiceImpl::setCoreService(service::core::CoreService* coreServic
|
|||||||
int major = 0, minor = 0;
|
int major = 0, minor = 0;
|
||||||
coreService->getServiceVersion(major, minor);
|
coreService->getServiceVersion(major, minor);
|
||||||
ROS_INFO_STREAM("WebServerService: Found HOSCoreService Version " << major << "." << minor);
|
ROS_INFO_STREAM("WebServerService: Found HOSCoreService Version " << major << "." << minor);
|
||||||
if (repoService) {
|
//if (repoService) {
|
||||||
init();
|
init();
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void WebServerServiceImpl::setRepoService(devicerepository::DeviceRepositoryService* repoService) noexcept {
|
/*void WebServerServiceImpl::setRepoService(devicerepository::DeviceRepositoryService* repoService) noexcept {
|
||||||
if (repoService && !this->repoService) {
|
if (repoService && !this->repoService) {
|
||||||
this->repoService = repoService;
|
this->repoService = repoService;
|
||||||
int major = 0, minor = 0;
|
int major = 0, minor = 0;
|
||||||
@@ -59,7 +62,7 @@ void WebServerServiceImpl::setRepoService(devicerepository::DeviceRepositoryServ
|
|||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -73,8 +76,9 @@ Poco::Net::HTTPRequestHandler* WebServerServiceImpl::RequestHandlerFactory::crea
|
|||||||
// We want a longest prefix match.
|
// We want a longest prefix match.
|
||||||
// Since we have an ordered map, we just need to iterate it in reverse order and return the first match.
|
// Since we have an ordered map, we just need to iterate it in reverse order and return the first match.
|
||||||
for (auto i = parent->webResourceFactories.rbegin(); i != parent->webResourceFactories.rend(); i++) {
|
for (auto i = parent->webResourceFactories.rbegin(); i != parent->webResourceFactories.rend(); i++) {
|
||||||
if (boost::algorithm::starts_with(request.getURI(), i->first)) {
|
if ( boost::algorithm::starts_with(request.getURI(), i->first)
|
||||||
return i->second->createRequestHandler(request, ssl);
|
&& ( request.getURI().size() == i->first.size() || request.getURI()[i->first.size()] == '/' ) ) {
|
||||||
|
return i->second->createRequestHandler(Poco::URI(i->first), request, ssl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// return default handler
|
// return default handler
|
||||||
@@ -89,48 +93,83 @@ void WebServerServiceImpl::init() noexcept {
|
|||||||
//serverParams.max_threads(5);
|
//serverParams.max_threads(5);
|
||||||
//webServer.reset(new webserver::webserver(serverParams));
|
//webServer.reset(new webserver::webserver(serverParams));
|
||||||
|
|
||||||
Net::ServerSocket webServerSocket(8080);
|
|
||||||
Net::HTTPServerParams::Ptr webServerParams = new Net::HTTPServerParams();
|
Net::HTTPServerParams::Ptr webServerParams = new Net::HTTPServerParams();
|
||||||
webServerParams->setServerName("Home Operating System");
|
webServerParams->setServerName("Home Operating System");
|
||||||
webServerParams->setSoftwareVersion("Home Operating System alpha");
|
webServerParams->setSoftwareVersion("Home Operating System alpha");
|
||||||
|
webServerParams->setMaxThreads(10);
|
||||||
|
|
||||||
|
Net::ServerSocket webServerSocket(8080);
|
||||||
webServer.reset(new Poco::Net::HTTPServer(new RequestHandlerFactory(this), webServerSocket, webServerParams));
|
webServer.reset(new Poco::Net::HTTPServer(new RequestHandlerFactory(this), webServerSocket, webServerParams));
|
||||||
webServer->start();
|
webServer->start();
|
||||||
/*auto& sslManager = Poco::Net::SSLManager::instance();
|
|
||||||
sslManager.defaultServerContext();
|
|
||||||
Poco::Net::SecureServerSocket webServerSSLSocket(8090);
|
|
||||||
webServerSSL.reset(new Poco::Net::HTTPServer(new RequestHandlerFactory(), webServerSocket, webServerParams));
|
|
||||||
webServerSSL->start();*/
|
|
||||||
|
|
||||||
// Register web resources ros::NodeHandle* nodehandle, utils::SchemaLoader* schemaLoader, webserver::WebServerService* service
|
try {
|
||||||
|
|
||||||
|
class MyPrivateKeyPassphraseHandler
|
||||||
|
: public Poco::Net::PrivateKeyPassphraseHandler {
|
||||||
|
public:
|
||||||
|
MyPrivateKeyPassphraseHandler(bool onServerSide)
|
||||||
|
: PrivateKeyPassphraseHandler(onServerSide) {}
|
||||||
|
void onPrivateKeyRequested(const void* pSender, std::string& privateKey) override {
|
||||||
|
std::cout << "onPrivateKeyRequested: " << privateKey << std::endl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class MyInvalidCertificateHandler
|
||||||
|
: public Poco::Net::InvalidCertificateHandler {
|
||||||
|
public:
|
||||||
|
MyInvalidCertificateHandler(bool handleErrorsOnServerSide)
|
||||||
|
: InvalidCertificateHandler(handleErrorsOnServerSide) {}
|
||||||
|
void onInvalidCertificate(const void* pSender, Poco::Net::VerificationErrorArgs& errorCert){
|
||||||
|
std::cout << "onInvalidCertificate: " << errorCert.errorMessage() << std::endl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto& sslManager = Poco::Net::SSLManager::instance();
|
||||||
|
//Poco::Net::SSLManager::PrivateKeyPassphraseHandlerPtr ptrConsole = new Poco::Net::KeyConsoleHandler(true);
|
||||||
|
Poco::Net::SSLManager::PrivateKeyPassphraseHandlerPtr ptrConsole = new MyPrivateKeyPassphraseHandler(true);
|
||||||
|
//Poco::Net::SSLManager::InvalidCertificateHandlerPtr ptrCert = new Poco::Net::ConsoleCertificateHandler(true);
|
||||||
|
Poco::Net::SSLManager::InvalidCertificateHandlerPtr ptrCert = new MyInvalidCertificateHandler(true);
|
||||||
|
Poco::Net::Context::Ptr ptrContext = new Poco::Net::Context( Poco::Net::Context::SERVER_USE,
|
||||||
|
"/etc/ssl/private/ssl-cert-snakeoil.key",
|
||||||
|
"/etc/ssl/certs/ssl-cert-snakeoil.pem",
|
||||||
|
"",
|
||||||
|
Poco::Net::Context::VERIFY_NONE,
|
||||||
|
9,
|
||||||
|
false,
|
||||||
|
"ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH" );
|
||||||
|
sslManager.initializeServer(ptrConsole, ptrCert, ptrContext);
|
||||||
|
|
||||||
|
Poco::Net::SecureServerSocket webServerSSLSocket(8090);
|
||||||
|
webServerSSL.reset(new Poco::Net::HTTPServer(new RequestHandlerFactory(this, true), webServerSSLSocket, webServerParams));
|
||||||
|
webServerSSL->start();
|
||||||
|
|
||||||
|
} catch(Poco::Net::SSLException& e) {
|
||||||
|
ROS_ERROR_STREAM("Could not start HTTPS server: " << e.displayText());
|
||||||
|
} catch(...) {
|
||||||
|
ROS_ERROR("Unknown exception while starting HTTPS Server");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register web resources
|
||||||
registerWebResource("/schemas",
|
registerWebResource("/schemas",
|
||||||
std::make_shared<resources::GenericWebResourceHandlerFactory>([=](const Net::HTTPServerRequest&, bool)->Net::HTTPRequestHandler* {
|
new resources::GenericWebResourceHandlerFactory([=](Poco::URI matchUri, const Net::HTTPServerRequest&, bool)->Net::HTTPRequestHandler* {
|
||||||
return new resources::SchemaResourceHandler(nodehandle, &coreService->getSchemaLoader(), this);
|
return new resources::SchemaResourceHandler(matchUri, nodehandle, &coreService->getSchemaLoader(), this);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
registerWebResource("/devices",
|
/*registerWebResource("/devices",
|
||||||
std::make_shared<resources::DevicesResourceHandlerFactory>(this, repoService)
|
std::make_shared<resources::DevicesResourceHandlerFactory>(this, repoService)
|
||||||
);
|
);*/
|
||||||
registerWebResource("/default",
|
registerWebResource("/default",
|
||||||
std::make_shared<resources::GenericWebResourceHandlerFactory>([=](const Net::HTTPServerRequest&, bool)->Net::HTTPRequestHandler* {
|
new resources::GenericWebResourceHandlerFactory([=](Poco::URI matchUri, const Net::HTTPServerRequest&, bool)->Net::HTTPRequestHandler* {
|
||||||
return new resources::WebResourceHandlerImpl();
|
return new resources::WebResourceHandlerImpl();
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
/*registerWebResource( "/schemas",
|
|
||||||
std::make_shared<resources::SchemaHTTPResource>(nodehandle, &coreService->getSchemaLoader())
|
|
||||||
);
|
|
||||||
registerWebResource( "/devices",
|
|
||||||
std::make_shared<resources::DevicesHTTPResource>(repoService)
|
|
||||||
);*/
|
|
||||||
|
|
||||||
//webServer->start(false);
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
ROS_INFO_STREAM("WebServerService: Initialized and Ready.");
|
ROS_INFO_STREAM("WebServerService: Initialized and Ready.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool WebServerServiceImpl::registerWebResource(const std::string& path, std::shared_ptr<WebResourceHandlerFactory> factory) noexcept {
|
bool WebServerServiceImpl::registerWebResource(const std::string& path, WebResourceHandlerFactory* factory) noexcept {
|
||||||
auto uri = getAbsoluteURI(path);
|
auto uri = getAbsoluteURI(path);
|
||||||
if (webResourceFactories.find(uri.getPath()) == webResourceFactories.end()) {
|
if (webResourceFactories.find(uri.getPath()) == webResourceFactories.end()) {
|
||||||
webResourceFactories[uri.getPath()] = factory;
|
webResourceFactories[uri.getPath()] = factory;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#include <hos/cosgi/service/webserver/resources/WebResourceHandlerImpl.h>
|
#include <hos/cosgi/service/webserver/resources/WebResourceHandlerImpl.h>
|
||||||
#include <hos/cosgi/service/Implementation.h>
|
#include <hos/cosgi/service/Implementation.h>
|
||||||
#include <hos/cosgi/service/core/CoreService.h>
|
#include <hos/cosgi/service/core/CoreService.h>
|
||||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
//#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -63,25 +63,19 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
service::core::CoreService* coreService = nullptr;
|
service::core::CoreService* coreService = nullptr;
|
||||||
devicerepository::DeviceRepositoryService* repoService = nullptr;
|
//devicerepository::DeviceRepositoryService* repoService = nullptr;
|
||||||
ros::NodeHandle* nodehandle = nullptr;
|
ros::NodeHandle* nodehandle = nullptr;
|
||||||
|
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
|
|
||||||
Poco::URI prefixPath = Poco::URI("/hos");
|
Poco::URI prefixPath = Poco::URI("/hos/api");
|
||||||
std::vector<std::string> prefixPathPieces;
|
|
||||||
std::unique_ptr<Poco::Net::HTTPServer> webServer;
|
std::unique_ptr<Poco::Net::HTTPServer> webServer;
|
||||||
std::unique_ptr<Poco::Net::HTTPServer> webServerSSL;
|
std::unique_ptr<Poco::Net::HTTPServer> webServerSSL;
|
||||||
std::map<std::string, std::shared_ptr<WebResourceHandlerFactory>> webResourceFactories;
|
std::map<std::string, WebResourceHandlerFactory*> webResourceFactories;
|
||||||
|
|
||||||
void init() noexcept;
|
void init() noexcept;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
WebServerServiceImpl() {
|
|
||||||
prefixPath.getPathSegments(prefixPathPieces);
|
|
||||||
}
|
|
||||||
|
|
||||||
~WebServerServiceImpl();
|
~WebServerServiceImpl();
|
||||||
|
|
||||||
|
|
||||||
@@ -89,20 +83,20 @@ public:
|
|||||||
|
|
||||||
void setCoreService(service::core::CoreService* coreService) noexcept;
|
void setCoreService(service::core::CoreService* coreService) noexcept;
|
||||||
|
|
||||||
void setRepoService(devicerepository::DeviceRepositoryService* repoService) noexcept;
|
//void setRepoService(devicerepository::DeviceRepositoryService* repoService) noexcept;
|
||||||
|
|
||||||
|
|
||||||
/* Public Service Implementations */
|
/* Public Service Implementations */
|
||||||
|
|
||||||
virtual bool registerWebResource(const std::string& path, std::shared_ptr<WebResourceHandlerFactory> factory) noexcept override;
|
virtual bool registerWebResource(const std::string& path, WebResourceHandlerFactory* factory) noexcept override;
|
||||||
|
|
||||||
virtual const Poco::URI& getPrefixPath() noexcept override {
|
/* virtual const Poco::URI& getPrefixPath() noexcept override {
|
||||||
return prefixPath;
|
return prefixPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual const std::vector<std::string>& getPrefixPathPieces() noexcept override {
|
virtual const std::vector<std::string>& getPrefixPathPieces() noexcept override {
|
||||||
return prefixPathPieces;
|
return prefixPathPieces;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
|
||||||
/* Internal */
|
/* Internal */
|
||||||
|
|||||||
+20
-22
@@ -11,7 +11,7 @@
|
|||||||
namespace hos {
|
namespace hos {
|
||||||
namespace cosgi {
|
namespace cosgi {
|
||||||
namespace service {
|
namespace service {
|
||||||
namespace webserver {
|
namespace webresource {
|
||||||
namespace resources {
|
namespace resources {
|
||||||
|
|
||||||
|
|
||||||
@@ -20,22 +20,21 @@ using namespace Poco;
|
|||||||
using namespace libvariant;
|
using namespace libvariant;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
DevicesResourceHandlerFactory::DevicesResourceHandlerFactory(WebServerService* service, devicerepository::DeviceRepositoryService* repoService)
|
DevicesResourceHandlerFactory::DevicesResourceHandlerFactory(WebServerService* service, devicerepository::DeviceRepositoryService* repoService)
|
||||||
: service(service), repoService(repoService) {
|
: service(service), repoService(repoService) {
|
||||||
infoCategoryFuncs.insert({"type", [](devicerepository::Device* device, Poco::Net::HTTPServerRequest &req, const std::string& category, bool ssl)->Variant {
|
infoCategoryFuncs.insert({"type", [](Poco::URI& matchUri, devicerepository::Device* device, Poco::Net::HTTPServerRequest &req, const std::string& category, bool ssl)->Variant {
|
||||||
return device->getDeviceType();
|
return device->getDeviceType();
|
||||||
} });
|
} });
|
||||||
|
|
||||||
infoCategoryFuncs.insert({"status_topic", [](devicerepository::Device* device, Poco::Net::HTTPServerRequest &req, const std::string& category, bool ssl)->Variant {
|
infoCategoryFuncs.insert({"status_topic", [](Poco::URI& matchUri, devicerepository::Device* device, Poco::Net::HTTPServerRequest &req, const std::string& category, bool ssl)->Variant {
|
||||||
return device->getStatusTopic();
|
return device->getStatusTopic();
|
||||||
} });
|
} });
|
||||||
|
|
||||||
infoCategoryFuncs.insert({"command_topic", [](devicerepository::Device* device, Poco::Net::HTTPServerRequest &req, const std::string& category, bool ssl)->Variant {
|
infoCategoryFuncs.insert({"command_topic", [](Poco::URI& matchUri, devicerepository::Device* device, Poco::Net::HTTPServerRequest &req, const std::string& category, bool ssl)->Variant {
|
||||||
return device->getCmdTopic();
|
return device->getCmdTopic();
|
||||||
} });
|
} });
|
||||||
|
|
||||||
infoCategoryFuncs.insert({"current_state", [](devicerepository::Device* device, Poco::Net::HTTPServerRequest &req, const std::string& category, bool ssl)->Variant {
|
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();
|
auto retval = device->getCurrentState();
|
||||||
if (retval.IsMap()) {
|
if (retval.IsMap()) {
|
||||||
retval["timestamp"] = utils::timestamp_to_ISO8601(device->getCurrentStateTimestamp());
|
retval["timestamp"] = utils::timestamp_to_ISO8601(device->getCurrentStateTimestamp());
|
||||||
@@ -43,7 +42,7 @@ DevicesResourceHandlerFactory::DevicesResourceHandlerFactory(WebServerService* s
|
|||||||
return retval;
|
return retval;
|
||||||
} });
|
} });
|
||||||
|
|
||||||
infoCategoryFuncs.insert({"last_state", [](devicerepository::Device* device, Poco::Net::HTTPServerRequest &req, const std::string& category, bool ssl)->Variant {
|
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();
|
auto retval = device->getLastState();
|
||||||
if (retval.IsMap()) {
|
if (retval.IsMap()) {
|
||||||
retval["timestamp"] = utils::timestamp_to_ISO8601(device->getLastStateTimestamp());
|
retval["timestamp"] = utils::timestamp_to_ISO8601(device->getLastStateTimestamp());
|
||||||
@@ -51,23 +50,22 @@ DevicesResourceHandlerFactory::DevicesResourceHandlerFactory(WebServerService* s
|
|||||||
return retval;
|
return retval;
|
||||||
} });
|
} });
|
||||||
|
|
||||||
infoCategoryFuncs.insert({"uri", [=](devicerepository::Device* device, Poco::Net::HTTPServerRequest &req, const std::string& category, bool ssl)->Variant {
|
infoCategoryFuncs.insert({"uri", [=](Poco::URI& matchUri, devicerepository::Device* device, Poco::Net::HTTPServerRequest &req, const std::string& category, bool ssl)->Variant {
|
||||||
auto& baseUri = service->getPrefixPath();
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
if (ssl) {
|
if (ssl) {
|
||||||
ss << "https://";
|
ss << "https://";
|
||||||
} else {
|
} else {
|
||||||
ss << "http://";
|
ss << "http://";
|
||||||
}
|
}
|
||||||
ss << req.getHost() << baseUri.toString() << "/devices/" << device->getDeviceID();
|
ss << req.getHost() << matchUri.toString() << device->getDeviceID();
|
||||||
return ss.str();
|
return ss.str();
|
||||||
} });
|
} });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Net::HTTPRequestHandler* DevicesResourceHandlerFactory::createRequestHandler( const Net::HTTPServerRequest& request, bool ssl ) noexcept {
|
Net::HTTPRequestHandler* DevicesResourceHandlerFactory::createRequestHandler( Poco::URI matchUri, const Net::HTTPServerRequest& request, bool ssl ) noexcept {
|
||||||
return new DevicesResourceHandler(this, service, repoService, infoCategoryFuncs, ssl);
|
return new DevicesResourceHandler(matchUri, service, repoService, infoCategoryFuncs, ssl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -102,13 +100,13 @@ void DevicesResourceHandler::_handleGET(Poco::Net::HTTPServerRequest &req, Poco:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& prefixPath = service->getPrefixPathPieces();
|
std::vector<std::string> pathPieces, matchPieces;
|
||||||
|
matchUri.getPathSegments(matchPieces);
|
||||||
Poco::URI uri(req.getURI());
|
Poco::URI uri(req.getURI());
|
||||||
std::vector<std::string> pathPieces;
|
|
||||||
uri.getPathSegments(pathPieces);
|
uri.getPathSegments(pathPieces);
|
||||||
|
|
||||||
// No device given
|
// No device given
|
||||||
if (pathPieces.size() <= prefixPath.size() + 1) {
|
if (pathPieces.size() <= matchPieces.size()) {
|
||||||
if (dataMethod != DevicesAPIMethod::GET) {
|
if (dataMethod != DevicesAPIMethod::GET) {
|
||||||
throw WebResourceHandlerException("Requested API method requires a device",
|
throw WebResourceHandlerException("Requested API method requires a device",
|
||||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
||||||
@@ -122,18 +120,18 @@ void DevicesResourceHandler::_handleGET(Poco::Net::HTTPServerRequest &req, Poco:
|
|||||||
|
|
||||||
// Device given
|
// Device given
|
||||||
} else {
|
} else {
|
||||||
std::string devid = pathPieces[prefixPath.size() + 1];
|
std::string devid = pathPieces[matchPieces.size()];
|
||||||
auto device = repoService->getDevice(devid);
|
auto device = repoService->getDevice(devid);
|
||||||
if (!device.expired()) {
|
if (!device.expired()) {
|
||||||
switch (dataMethod) {
|
switch (dataMethod) {
|
||||||
case DevicesAPIMethod::GET:
|
case DevicesAPIMethod::GET:
|
||||||
{
|
{
|
||||||
std::string category;
|
std::string category;
|
||||||
if (pathPieces.size() > prefixPath.size() + 2) {
|
if (pathPieces.size() > matchPieces.size() + 1) {
|
||||||
category = pathPieces[prefixPath.size() + 2];
|
category = pathPieces[matchPieces.size() + 1];
|
||||||
}
|
}
|
||||||
std::vector<std::string> path;
|
std::vector<std::string> path;
|
||||||
for (int i = prefixPath.size() + 3; i < pathPieces.size(); i++) {
|
for (int i = matchPieces.size() + 2; i < pathPieces.size(); i++) {
|
||||||
path.push_back(pathPieces[i]);
|
path.push_back(pathPieces[i]);
|
||||||
}
|
}
|
||||||
Variant result = getDeviceInfo(device.lock().get(), req, category, path);
|
Variant result = getDeviceInfo(device.lock().get(), req, category, path);
|
||||||
@@ -143,7 +141,7 @@ void DevicesResourceHandler::_handleGET(Poco::Net::HTTPServerRequest &req, Poco:
|
|||||||
case DevicesAPIMethod::COMMAND:
|
case DevicesAPIMethod::COMMAND:
|
||||||
{
|
{
|
||||||
std::vector<std::string> path;
|
std::vector<std::string> path;
|
||||||
for (int i = prefixPath.size() + 2; i < pathPieces.size(); i++) {
|
for (int i = matchPieces.size()+1; i < pathPieces.size(); i++) {
|
||||||
path.push_back(pathPieces[i]);
|
path.push_back(pathPieces[i]);
|
||||||
}
|
}
|
||||||
sendDeviceCommand(device.lock().get(), req, methodValue, path);
|
sendDeviceCommand(device.lock().get(), req, methodValue, path);
|
||||||
@@ -176,14 +174,14 @@ Variant DevicesResourceHandler::getDeviceInfo(devicerepository::Device* device,
|
|||||||
// We want all info categories
|
// We want all info categories
|
||||||
if (category.empty()) {
|
if (category.empty()) {
|
||||||
for (auto c : infoCategoryFuncs) {
|
for (auto c : infoCategoryFuncs) {
|
||||||
retval[c.first] = c.second(device, req, category, ssl);
|
retval[c.first] = c.second(matchUri, device, req, category, ssl);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We want a single info category
|
// We want a single info category
|
||||||
} else {
|
} else {
|
||||||
auto c = infoCategoryFuncs.find(category);
|
auto c = infoCategoryFuncs.find(category);
|
||||||
if (c != infoCategoryFuncs.end()) {
|
if (c != infoCategoryFuncs.end()) {
|
||||||
retval = c->second(device, req, category, ssl);
|
retval = c->second(matchUri, device, req, category, ssl);
|
||||||
if (path.size() > 0) {
|
if (path.size() > 0) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
for (auto p : path) {
|
for (auto p : path) {
|
||||||
|
|||||||
+10
-7
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <hos/cosgi/service/webserver/WebServerService.h>
|
#include <hos/cosgi/service/webserver/WebServerService.h>
|
||||||
|
#include <hos/cosgi/service/Implementation.h>
|
||||||
#include <hos/cosgi/service/webserver/resources/WebResourceHandlerImpl.h>
|
#include <hos/cosgi/service/webserver/resources/WebResourceHandlerImpl.h>
|
||||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||||
#include <Poco/Net/HTTPRequestHandler.h>
|
#include <Poco/Net/HTTPRequestHandler.h>
|
||||||
@@ -18,7 +19,7 @@
|
|||||||
namespace hos {
|
namespace hos {
|
||||||
namespace cosgi {
|
namespace cosgi {
|
||||||
namespace service {
|
namespace service {
|
||||||
namespace webserver {
|
namespace webresource {
|
||||||
namespace resources {
|
namespace resources {
|
||||||
|
|
||||||
|
|
||||||
@@ -31,9 +32,11 @@ enum class DevicesAPIMethod {
|
|||||||
|
|
||||||
|
|
||||||
class DevicesResourceHandlerFactory
|
class DevicesResourceHandlerFactory
|
||||||
: public virtual WebResourceHandlerFactory {
|
: public virtual WebResourceHandlerFactory,
|
||||||
|
public implementation::Service<GenericWebResourceHandlerFactory> {
|
||||||
public:
|
public:
|
||||||
typedef std::function<libvariant::Variant( devicerepository::Device* device,
|
typedef std::function<libvariant::Variant( Poco::URI& matchUri,
|
||||||
|
devicerepository::Device* device,
|
||||||
Poco::Net::HTTPServerRequest &req,
|
Poco::Net::HTTPServerRequest &req,
|
||||||
const std::string& category,
|
const std::string& category,
|
||||||
bool ssl )> infoCategoryFunc_t;
|
bool ssl )> infoCategoryFunc_t;
|
||||||
@@ -43,7 +46,7 @@ private:
|
|||||||
std::map<std::string, infoCategoryFunc_t> infoCategoryFuncs;
|
std::map<std::string, infoCategoryFunc_t> infoCategoryFuncs;
|
||||||
public:
|
public:
|
||||||
DevicesResourceHandlerFactory(WebServerService* service, devicerepository::DeviceRepositoryService* repoService);
|
DevicesResourceHandlerFactory(WebServerService* service, devicerepository::DeviceRepositoryService* repoService);
|
||||||
virtual Poco::Net::HTTPRequestHandler* createRequestHandler( const Poco::Net::HTTPServerRequest& request, bool ssl = false ) noexcept override;
|
virtual Poco::Net::HTTPRequestHandler* createRequestHandler(Poco::URI matchUri, const Poco::Net::HTTPServerRequest& request, bool ssl ) noexcept override;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -75,8 +78,8 @@ class DevicesResourceHandler
|
|||||||
: public virtual WebResourceHandlerImpl {
|
: public virtual WebResourceHandlerImpl {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DevicesResourceHandlerFactory* parent;
|
|
||||||
WebServerService* service;
|
WebServerService* service;
|
||||||
|
Poco::URI matchUri;
|
||||||
devicerepository::DeviceRepositoryService* repoService;
|
devicerepository::DeviceRepositoryService* repoService;
|
||||||
const std::map<std::string, DevicesResourceHandlerFactory::infoCategoryFunc_t>& infoCategoryFuncs;
|
const std::map<std::string, DevicesResourceHandlerFactory::infoCategoryFunc_t>& infoCategoryFuncs;
|
||||||
bool ssl;
|
bool ssl;
|
||||||
@@ -94,12 +97,12 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DevicesResourceHandler( DevicesResourceHandlerFactory* parent,
|
DevicesResourceHandler( Poco::URI matchUri,
|
||||||
WebServerService* service,
|
WebServerService* service,
|
||||||
devicerepository::DeviceRepositoryService* repoService,
|
devicerepository::DeviceRepositoryService* repoService,
|
||||||
const std::map<std::string, DevicesResourceHandlerFactory::infoCategoryFunc_t>& infoCategoryFuncs,
|
const std::map<std::string, DevicesResourceHandlerFactory::infoCategoryFunc_t>& infoCategoryFuncs,
|
||||||
bool ssl = false )
|
bool ssl = false )
|
||||||
: parent(parent), service(service), repoService(repoService), infoCategoryFuncs(infoCategoryFuncs), ssl(ssl) {}
|
: matchUri(matchUri), service(service), repoService(repoService), infoCategoryFuncs(infoCategoryFuncs), 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) override;
|
||||||
|
|
||||||
|
|||||||
+24
-5
@@ -20,30 +20,49 @@ namespace resources {
|
|||||||
|
|
||||||
using namespace httpserver;
|
using namespace httpserver;
|
||||||
using namespace libvariant;
|
using namespace libvariant;
|
||||||
|
using namespace Poco;
|
||||||
|
|
||||||
|
|
||||||
|
HOS_SERVICE_IMPL_INFO( GenericWebResourceHandlerFactory, // Implementation
|
||||||
|
service::webserver::WebResourceHandlerFactory::SERVICE_NAME, // Service Name
|
||||||
|
1, 0 ) // Version
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SchemaResourceHandler::_handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
void SchemaResourceHandler::_handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
||||||
// Requested URL is too short to contain any schema
|
|
||||||
Poco::URI uri(req.getURI());
|
Poco::URI uri(req.getURI());
|
||||||
std::vector<std::string> pathPieces;
|
std::vector<std::string> pathPieces, matchPieces;
|
||||||
uri.getPathSegments(pathPieces);
|
uri.getPathSegments(pathPieces);
|
||||||
size_t prefixPathSize = service->getPrefixPathPieces().size();
|
matchUri.getPathSegments(matchPieces);
|
||||||
if (pathPieces.size() <= prefixPathSize + 1) {
|
|
||||||
|
// Requested URL is too short to contain any schema
|
||||||
|
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 = prefixPathSize + 1; 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);
|
||||||
|
if (form.has("pointer")) {
|
||||||
|
std::string pointer = form.get("pointer");
|
||||||
|
if (schema.HasPath(pointer)) {
|
||||||
|
schema = schema.GetPath(pointer);
|
||||||
|
} else {
|
||||||
|
throw WebResourceHandlerException((boost::format("Could not resolve pointer \"%1%\"") % pointer ).str(),
|
||||||
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
||||||
|
}
|
||||||
|
}
|
||||||
handleResponse(req, resp, schema);
|
handleResponse(req, resp, schema);
|
||||||
|
} catch(WebResourceHandlerException& e) {
|
||||||
|
throw e;
|
||||||
} catch(std::exception& e) {
|
} catch(std::exception& e) {
|
||||||
throw WebResourceHandlerException((boost::format("Could not find schema \"%1%\": %2%") % schemaPath % e.what()).str(),
|
throw WebResourceHandlerException((boost::format("Could not find schema \"%1%\": %2%") % schemaPath % e.what()).str(),
|
||||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
||||||
|
|||||||
@@ -21,16 +21,17 @@ namespace resources {
|
|||||||
|
|
||||||
|
|
||||||
class SchemaResourceHandler
|
class SchemaResourceHandler
|
||||||
: public virtual WebResourceHandlerImpl {
|
: public WebResourceHandlerImpl {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Poco::URI matchUri;
|
||||||
ros::NodeHandle* nodehandle;
|
ros::NodeHandle* nodehandle;
|
||||||
utils::SchemaLoader* schemaLoader;
|
utils::SchemaLoader* schemaLoader;
|
||||||
WebServerService* service;
|
WebServerService* service;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SchemaResourceHandler(ros::NodeHandle* nodehandle, utils::SchemaLoader* schemaLoader, webserver::WebServerService* service)
|
SchemaResourceHandler(Poco::URI matchUri, ros::NodeHandle* nodehandle, utils::SchemaLoader* schemaLoader, webserver::WebServerService* service)
|
||||||
: 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 _handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -163,11 +163,15 @@ IF(Poco_INCLUDE_DIR)
|
|||||||
ENDIF(Poco_BINARY_DIR AND EXISTS "${Poco_BINARY_DIR}/bin")
|
ENDIF(Poco_BINARY_DIR AND EXISTS "${Poco_BINARY_DIR}/bin")
|
||||||
ENDIF(Poco_LIBRARY_DIR AND Poco_FOUNDATION_LIB)
|
ENDIF(Poco_LIBRARY_DIR AND Poco_FOUNDATION_LIB)
|
||||||
IF(Poco_FOUNDATION_LIB)
|
IF(Poco_FOUNDATION_LIB)
|
||||||
IF ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
|
||||||
SET(DBG "d")
|
# Debug libs are broken on Ubuntu
|
||||||
ELSE ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
# IF ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
||||||
|
# SET(DBG "d")
|
||||||
|
# ELSE ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
||||||
SET(DBG "")
|
SET(DBG "")
|
||||||
ENDIF ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
# ENDIF ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
||||||
|
|
||||||
|
|
||||||
SET(Comp_List "Foundation${DBG}")
|
SET(Comp_List "Foundation${DBG}")
|
||||||
FOREACH(COMPONENT ${Poco_FIND_COMPONENTS})
|
FOREACH(COMPONENT ${Poco_FIND_COMPONENTS})
|
||||||
FIND_LIBRARY(LIB${COMPONENT} "Poco${COMPONENT}${DBG}" Poco_LIBRARY_DIR)
|
FIND_LIBRARY(LIB${COMPONENT} "Poco${COMPONENT}${DBG}" Poco_LIBRARY_DIR)
|
||||||
|
|||||||
Reference in New Issue
Block a user