.
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.
|
||||
*/
|
||||
|
||||
@@ -113,7 +113,8 @@ int main(int argc, char **argv) {
|
||||
// Create and register hos-core-service
|
||||
CoreServiceImpl hosCoreService(rosPublicNodeHandle, rosPrivateNodeHandle);
|
||||
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");
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ find_package(catkin REQUIRED COMPONENTS
|
||||
hos_core_msgs
|
||||
hos_cosgi_core
|
||||
hos_deps
|
||||
hos_cosgi_webserver
|
||||
hos_cpp_utils
|
||||
roscpp
|
||||
)
|
||||
@@ -16,6 +17,7 @@ find_package(APR REQUIRED)
|
||||
find_package(CELIX REQUIRED)
|
||||
find_package(Boost 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-1.0
|
||||
${libvariant_INCLUDE_DIR}
|
||||
${Poco_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
set(BUNDLE_SYMBOLICNAME "hos.hos_devicerepository")
|
||||
@@ -52,12 +55,14 @@ bundle(hos_cosgi_devicerepository
|
||||
SOURCES
|
||||
${PROJECT_SOURCE_DIR}/src/BundleActivator
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/devicerepository/DeviceRepositoryServiceImpl
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/webresource/DeviceRepoHandler
|
||||
)
|
||||
|
||||
target_link_libraries(hos_cosgi_devicerepository
|
||||
${catkin_LIBRARIES}
|
||||
${APR_LIBRARIES}
|
||||
${libvariant_LIBRARY}
|
||||
${Poco_LIBRARIES}
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
<build_depend>roscpp</build_depend>
|
||||
<build_depend>hos_deps</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_core_msgs</run_depend>
|
||||
<run_depend>hos_cosgi_core</run_depend>
|
||||
|
||||
@@ -11,18 +11,25 @@
|
||||
#include <hos/cosgi/celix.h>
|
||||
// CoreService
|
||||
#include <hos/cosgi/service/core/CoreService.h>
|
||||
// Services
|
||||
#include "hos/cosgi/service/devicerepository/DeviceRepositoryServiceImpl.h"
|
||||
#include "hos/cosgi/service/webresource/DeviceRepoHandler.h"
|
||||
|
||||
|
||||
using namespace hos::cosgi;
|
||||
using namespace hos::cosgi::service::devicerepository;
|
||||
using namespace hos::cosgi::service::webserver;
|
||||
|
||||
|
||||
|
||||
struct UserData {
|
||||
apr_pool_t* memoryPool = nullptr;
|
||||
std::unique_ptr<DeviceRepositoryServiceImpl> serviceImpl;
|
||||
std::unique_ptr<webresource::DeviceRepoHandlerFactory> webResourceImpl;
|
||||
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());
|
||||
|
||||
// Create device repository webresource
|
||||
if (myUserData->webResourceReg != nullptr) {
|
||||
serviceRegistration_unregister(myUserData->webResourceReg);
|
||||
}
|
||||
myUserData->webResourceImpl.reset(new webresource::DeviceRepoHandlerFactory(myUserData->serviceImpl.get()));
|
||||
|
||||
// Get core service
|
||||
service_reference_pt ref = nullptr;
|
||||
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);
|
||||
}
|
||||
|
||||
// Register device repository service
|
||||
// Register device repository service and webresource
|
||||
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");
|
||||
|
||||
+3
-3
@@ -17,9 +17,9 @@ namespace devicerepository {
|
||||
|
||||
|
||||
// Service information
|
||||
template<> const char* implementation::ServiceInfo<DeviceRepositoryServiceImpl>::name = service::devicerepository::DeviceRepositoryService::SERVICE_NAME;
|
||||
template<> const int implementation::ServiceInfo<DeviceRepositoryServiceImpl>::major = 1;
|
||||
template<> const int implementation::ServiceInfo<DeviceRepositoryServiceImpl>::minor = 0;
|
||||
HOS_SERVICE_IMPL_INFO( DeviceRepositoryServiceImpl, // Implementation
|
||||
service::devicerepository::DeviceRepositoryService::SERVICE_NAME, // Service Name
|
||||
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
|
||||
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) {
|
||||
@@ -131,7 +132,8 @@ celix_status_t bundleActivator_start(void * userData, bundle_context_pt context)
|
||||
|
||||
// Register rule engine service
|
||||
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
|
||||
|
||||
@@ -27,15 +27,14 @@ namespace service {
|
||||
namespace ruleengine {
|
||||
|
||||
|
||||
using namespace ::libvariant;
|
||||
using namespace libvariant;
|
||||
|
||||
|
||||
|
||||
// Service information
|
||||
template<> const char* implementation::ServiceInfo<RuleEngineServiceImpl>::name = service::ruleengine::RuleEngineService::SERVICE_NAME;
|
||||
template<> const int implementation::ServiceInfo<RuleEngineServiceImpl>::major = 1;
|
||||
template<> const int implementation::ServiceInfo<RuleEngineServiceImpl>::minor = 0;
|
||||
|
||||
HOS_SERVICE_IMPL_INFO( RuleEngineServiceImpl, // Implementation
|
||||
service::ruleengine::RuleEngineService::SERVICE_NAME, // Service Name
|
||||
1, 0 ) // Version
|
||||
|
||||
|
||||
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
|
||||
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) {
|
||||
}
|
||||
@@ -111,7 +112,8 @@ celix_status_t bundleActivator_start(void * userData, bundle_context_pt context)
|
||||
}
|
||||
// Register hos-ruleexecution-python-service
|
||||
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
|
||||
myUserData->myServiceListener.handle = myUserData;
|
||||
|
||||
+3
-3
@@ -15,9 +15,9 @@ namespace python {
|
||||
|
||||
|
||||
// Service information
|
||||
template<> const char* implementation::ServiceInfo<PyScriptingService>::name = service::scripting::python::PyScriptingService::SERVICE_NAME;
|
||||
template<> const int implementation::ServiceInfo<PyScriptingService>::major = 1;
|
||||
template<> const int implementation::ServiceInfo<PyScriptingService>::minor = 0;
|
||||
HOS_SERVICE_IMPL_INFO( PyScriptingService, // Implementation
|
||||
service::scripting::python::PyScriptingService::SERVICE_NAME, // Service Name
|
||||
1, 0 ) // Version
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ project(hos_cosgi_webserver)
|
||||
## Find catkin macros and libraries
|
||||
find_package(catkin REQUIRED COMPONENTS
|
||||
hos_celix
|
||||
hos_cosgi_devicerepository
|
||||
hos_cosgi_core
|
||||
hos_cpp_utils
|
||||
hos_deps
|
||||
@@ -56,7 +55,7 @@ bundle(hos_cosgi_webserver
|
||||
SOURCES
|
||||
${PROJECT_SOURCE_DIR}/src/BundleActivator
|
||||
${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
|
||||
)
|
||||
|
||||
|
||||
@@ -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 WebResourceHandlerFactory
|
||||
: public virtual interface::Object {
|
||||
: public virtual interface::Service {
|
||||
|
||||
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
|
||||
: public virtual interface::Service {
|
||||
|
||||
@@ -47,11 +60,7 @@ public:
|
||||
|
||||
static constexpr const char* SERVICE_NAME = "hos_webserver_service";
|
||||
|
||||
virtual bool registerWebResource(const std::string& path, std::shared_ptr<WebResourceHandlerFactory> factory) noexcept = 0;
|
||||
|
||||
virtual const Poco::URI& getPrefixPath() noexcept = 0;
|
||||
|
||||
virtual const std::vector<std::string>& getPrefixPathPieces() noexcept = 0;
|
||||
virtual bool registerWebResource(const std::string& path, WebResourceHandlerFactory* factory) noexcept = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
+17
-4
@@ -3,10 +3,12 @@
|
||||
|
||||
|
||||
#include <hos/cosgi/service/webserver/WebServerService.h>
|
||||
#include <hos/cosgi/service/Implementation.h>
|
||||
#include <Poco/Net/HTTPRequestHandler.h>
|
||||
#include <Poco/Net/HTTPServerRequest.h>
|
||||
#include <Poco/Net/HTTPServerResponse.h>
|
||||
#include <Poco/Net/HTMLForm.h>
|
||||
#include <Poco/URI.h>
|
||||
#include <Variant/Variant.h>
|
||||
#include <boost/format.hpp>
|
||||
#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
|
||||
: public virtual WebResourceHandlerFactory {
|
||||
: public virtual WebResourceHandlerFactory,
|
||||
public implementation::Service<GenericWebResourceHandlerFactory> {
|
||||
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:
|
||||
factory_t _factory;
|
||||
public:
|
||||
GenericWebResourceHandlerFactory(factory_t factory)
|
||||
: _factory(factory) {}
|
||||
virtual Poco::Net::HTTPRequestHandler* createRequestHandler( const Poco::Net::HTTPServerRequest& request, bool ssl = false ) noexcept override {
|
||||
return _factory(request, ssl);
|
||||
virtual Poco::Net::HTTPRequestHandler* createRequestHandler( Poco::URI matchUri, const Poco::Net::HTTPServerRequest& request, bool ssl ) noexcept override {
|
||||
return _factory(matchUri, request, ssl);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
enum class ResponseDataFormat : int {
|
||||
JSON,
|
||||
JSONP,
|
||||
|
||||
@@ -41,13 +41,13 @@
|
||||
<!-- <test_depend>gtest</test_depend> -->
|
||||
<buildtool_depend>catkin</buildtool_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_cpp_utils</build_depend>
|
||||
<build_depend>hos_deps</build_depend>
|
||||
<build_depend>roscpp</build_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_cpp_utils</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::devicerepository;
|
||||
//using namespace hos::cosgi::service::devicerepository;
|
||||
using namespace hos::cosgi::service::core;
|
||||
using namespace hos::cosgi;
|
||||
|
||||
@@ -46,15 +46,33 @@ celix_status_t cb_serviceChanged(void* listener, service_event_pt event) {
|
||||
char* serviceName = nullptr;
|
||||
bool checkReg = false;
|
||||
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;
|
||||
bundleContext_getService(myUserData->bundleContext, event->reference, (void**)&service);
|
||||
myUserData->serviceImpl->setRepoService(service);
|
||||
checkReg = true;
|
||||
}
|
||||
}*/
|
||||
// Register hos-devicerepository-service
|
||||
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) {
|
||||
}
|
||||
@@ -106,13 +124,14 @@ celix_status_t bundleActivator_start(void * userData, bundle_context_pt context)
|
||||
myUserData->serviceImpl->setCoreService(coreService);
|
||||
}
|
||||
// Get HOS Core Service
|
||||
service_reference_pt ref2 = nullptr;
|
||||
/*service_reference_pt ref2 = nullptr;
|
||||
bundleContext_getServiceReference(context, (char*)DeviceRepositoryService::SERVICE_NAME, &ref2);
|
||||
DeviceRepositoryService* repoService = nullptr;
|
||||
bundleContext_getService(context, ref2, (void**)&repoService);
|
||||
if (repoService) {
|
||||
myUserData->serviceImpl->setRepoService(repoService);
|
||||
}
|
||||
}*/
|
||||
|
||||
// Register hos-devicerepository-service
|
||||
if (myUserData->serviceImpl->isInitialized()) {
|
||||
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.serviceChanged = cb_serviceChanged;
|
||||
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");
|
||||
} else {
|
||||
ROS_ERROR("WebServerService: Could not start bundle, user data struct is null");
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
|
||||
#include "WebServerServiceImpl.h"
|
||||
#include "resources/SchemaResource.h"
|
||||
//#include "resources/DevicesResource.h"
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <ros/ros.h>
|
||||
#include "resources/SchemaResource.h"
|
||||
#include "resources/DevicesResource.h"
|
||||
|
||||
#include <Poco/Net/KeyConsoleHandler.h>
|
||||
#include <Poco/Net/ConsoleCertificateHandler.h>
|
||||
#include <Poco/Net/SSLException.h>
|
||||
|
||||
|
||||
namespace hos {
|
||||
@@ -19,9 +21,10 @@ using namespace Poco;
|
||||
|
||||
|
||||
|
||||
template<> const char* implementation::ServiceInfo<WebServerServiceImpl>::name = service::webserver::WebServerServiceImpl::SERVICE_NAME;
|
||||
template<> const int implementation::ServiceInfo<WebServerServiceImpl>::major = 1;
|
||||
template<> const int implementation::ServiceInfo<WebServerServiceImpl>::minor = 0;
|
||||
// Service information
|
||||
HOS_SERVICE_IMPL_INFO( WebServerServiceImpl, // Implementation
|
||||
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;
|
||||
coreService->getServiceVersion(major, minor);
|
||||
ROS_INFO_STREAM("WebServerService: Found HOSCoreService Version " << major << "." << minor);
|
||||
if (repoService) {
|
||||
//if (repoService) {
|
||||
init();
|
||||
}
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WebServerServiceImpl::setRepoService(devicerepository::DeviceRepositoryService* repoService) noexcept {
|
||||
/*void WebServerServiceImpl::setRepoService(devicerepository::DeviceRepositoryService* repoService) noexcept {
|
||||
if (repoService && !this->repoService) {
|
||||
this->repoService = repoService;
|
||||
int major = 0, minor = 0;
|
||||
@@ -59,7 +62,7 @@ void WebServerServiceImpl::setRepoService(devicerepository::DeviceRepositoryServ
|
||||
init();
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
|
||||
@@ -73,8 +76,9 @@ Poco::Net::HTTPRequestHandler* WebServerServiceImpl::RequestHandlerFactory::crea
|
||||
// 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.
|
||||
for (auto i = parent->webResourceFactories.rbegin(); i != parent->webResourceFactories.rend(); i++) {
|
||||
if (boost::algorithm::starts_with(request.getURI(), i->first)) {
|
||||
return i->second->createRequestHandler(request, ssl);
|
||||
if ( boost::algorithm::starts_with(request.getURI(), i->first)
|
||||
&& ( request.getURI().size() == i->first.size() || request.getURI()[i->first.size()] == '/' ) ) {
|
||||
return i->second->createRequestHandler(Poco::URI(i->first), request, ssl);
|
||||
}
|
||||
}
|
||||
// return default handler
|
||||
@@ -89,48 +93,83 @@ void WebServerServiceImpl::init() noexcept {
|
||||
//serverParams.max_threads(5);
|
||||
//webServer.reset(new webserver::webserver(serverParams));
|
||||
|
||||
Net::ServerSocket webServerSocket(8080);
|
||||
Net::HTTPServerParams::Ptr webServerParams = new Net::HTTPServerParams();
|
||||
webServerParams->setServerName("Home Operating System");
|
||||
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->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",
|
||||
std::make_shared<resources::GenericWebResourceHandlerFactory>([=](const Net::HTTPServerRequest&, bool)->Net::HTTPRequestHandler* {
|
||||
return new resources::SchemaResourceHandler(nodehandle, &coreService->getSchemaLoader(), this);
|
||||
new resources::GenericWebResourceHandlerFactory([=](Poco::URI matchUri, const Net::HTTPServerRequest&, bool)->Net::HTTPRequestHandler* {
|
||||
return new resources::SchemaResourceHandler(matchUri, nodehandle, &coreService->getSchemaLoader(), this);
|
||||
})
|
||||
);
|
||||
registerWebResource("/devices",
|
||||
/*registerWebResource("/devices",
|
||||
std::make_shared<resources::DevicesResourceHandlerFactory>(this, repoService)
|
||||
);
|
||||
);*/
|
||||
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();
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
/*registerWebResource( "/schemas",
|
||||
std::make_shared<resources::SchemaHTTPResource>(nodehandle, &coreService->getSchemaLoader())
|
||||
);
|
||||
registerWebResource( "/devices",
|
||||
std::make_shared<resources::DevicesHTTPResource>(repoService)
|
||||
);*/
|
||||
|
||||
//webServer->start(false);
|
||||
initialized = true;
|
||||
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);
|
||||
if (webResourceFactories.find(uri.getPath()) == webResourceFactories.end()) {
|
||||
webResourceFactories[uri.getPath()] = factory;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <hos/cosgi/service/webserver/resources/WebResourceHandlerImpl.h>
|
||||
#include <hos/cosgi/service/Implementation.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 <boost/algorithm/string.hpp>
|
||||
#include <memory>
|
||||
@@ -63,25 +63,19 @@ private:
|
||||
};
|
||||
|
||||
service::core::CoreService* coreService = nullptr;
|
||||
devicerepository::DeviceRepositoryService* repoService = nullptr;
|
||||
//devicerepository::DeviceRepositoryService* repoService = nullptr;
|
||||
ros::NodeHandle* nodehandle = nullptr;
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
Poco::URI prefixPath = Poco::URI("/hos");
|
||||
std::vector<std::string> prefixPathPieces;
|
||||
Poco::URI prefixPath = Poco::URI("/hos/api");
|
||||
std::unique_ptr<Poco::Net::HTTPServer> webServer;
|
||||
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;
|
||||
|
||||
public:
|
||||
|
||||
WebServerServiceImpl() {
|
||||
prefixPath.getPathSegments(prefixPathPieces);
|
||||
}
|
||||
|
||||
~WebServerServiceImpl();
|
||||
|
||||
|
||||
@@ -89,20 +83,20 @@ public:
|
||||
|
||||
void setCoreService(service::core::CoreService* coreService) noexcept;
|
||||
|
||||
void setRepoService(devicerepository::DeviceRepositoryService* repoService) noexcept;
|
||||
//void setRepoService(devicerepository::DeviceRepositoryService* repoService) noexcept;
|
||||
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
virtual const std::vector<std::string>& getPrefixPathPieces() noexcept override {
|
||||
return prefixPathPieces;
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
/* Internal */
|
||||
|
||||
+20
-22
@@ -11,7 +11,7 @@
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace webserver {
|
||||
namespace webresource {
|
||||
namespace resources {
|
||||
|
||||
|
||||
@@ -20,22 +20,21 @@ using namespace Poco;
|
||||
using namespace libvariant;
|
||||
|
||||
|
||||
|
||||
DevicesResourceHandlerFactory::DevicesResourceHandlerFactory(WebServerService* service, devicerepository::DeviceRepositoryService* 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();
|
||||
} });
|
||||
|
||||
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();
|
||||
} });
|
||||
|
||||
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();
|
||||
} });
|
||||
|
||||
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();
|
||||
if (retval.IsMap()) {
|
||||
retval["timestamp"] = utils::timestamp_to_ISO8601(device->getCurrentStateTimestamp());
|
||||
@@ -43,7 +42,7 @@ DevicesResourceHandlerFactory::DevicesResourceHandlerFactory(WebServerService* s
|
||||
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();
|
||||
if (retval.IsMap()) {
|
||||
retval["timestamp"] = utils::timestamp_to_ISO8601(device->getLastStateTimestamp());
|
||||
@@ -51,23 +50,22 @@ DevicesResourceHandlerFactory::DevicesResourceHandlerFactory(WebServerService* s
|
||||
return retval;
|
||||
} });
|
||||
|
||||
infoCategoryFuncs.insert({"uri", [=](devicerepository::Device* device, Poco::Net::HTTPServerRequest &req, const std::string& category, bool ssl)->Variant {
|
||||
auto& baseUri = service->getPrefixPath();
|
||||
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() << baseUri.toString() << "/devices/" << device->getDeviceID();
|
||||
ss << req.getHost() << matchUri.toString() << device->getDeviceID();
|
||||
return ss.str();
|
||||
} });
|
||||
}
|
||||
|
||||
|
||||
|
||||
Net::HTTPRequestHandler* DevicesResourceHandlerFactory::createRequestHandler( const Net::HTTPServerRequest& request, bool ssl ) noexcept {
|
||||
return new DevicesResourceHandler(this, service, repoService, infoCategoryFuncs, ssl);
|
||||
Net::HTTPRequestHandler* DevicesResourceHandlerFactory::createRequestHandler( Poco::URI matchUri, const Net::HTTPServerRequest& request, bool ssl ) noexcept {
|
||||
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());
|
||||
std::vector<std::string> pathPieces;
|
||||
uri.getPathSegments(pathPieces);
|
||||
|
||||
// No device given
|
||||
if (pathPieces.size() <= prefixPath.size() + 1) {
|
||||
if (pathPieces.size() <= matchPieces.size()) {
|
||||
if (dataMethod != DevicesAPIMethod::GET) {
|
||||
throw WebResourceHandlerException("Requested API method requires a device",
|
||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
||||
@@ -122,18 +120,18 @@ void DevicesResourceHandler::_handleGET(Poco::Net::HTTPServerRequest &req, Poco:
|
||||
|
||||
// Device given
|
||||
} else {
|
||||
std::string devid = pathPieces[prefixPath.size() + 1];
|
||||
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() > prefixPath.size() + 2) {
|
||||
category = pathPieces[prefixPath.size() + 2];
|
||||
if (pathPieces.size() > matchPieces.size() + 1) {
|
||||
category = pathPieces[matchPieces.size() + 1];
|
||||
}
|
||||
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]);
|
||||
}
|
||||
Variant result = getDeviceInfo(device.lock().get(), req, category, path);
|
||||
@@ -143,7 +141,7 @@ void DevicesResourceHandler::_handleGET(Poco::Net::HTTPServerRequest &req, Poco:
|
||||
case DevicesAPIMethod::COMMAND:
|
||||
{
|
||||
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]);
|
||||
}
|
||||
sendDeviceCommand(device.lock().get(), req, methodValue, path);
|
||||
@@ -176,14 +174,14 @@ Variant DevicesResourceHandler::getDeviceInfo(devicerepository::Device* device,
|
||||
// We want all info categories
|
||||
if (category.empty()) {
|
||||
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
|
||||
} else {
|
||||
auto c = infoCategoryFuncs.find(category);
|
||||
if (c != infoCategoryFuncs.end()) {
|
||||
retval = c->second(device, req, category, ssl);
|
||||
retval = c->second(matchUri, device, req, category, ssl);
|
||||
if (path.size() > 0) {
|
||||
std::stringstream ss;
|
||||
for (auto p : path) {
|
||||
|
||||
+10
-7
@@ -3,6 +3,7 @@
|
||||
|
||||
|
||||
#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/devicerepository/DeviceRepositoryService.h>
|
||||
#include <Poco/Net/HTTPRequestHandler.h>
|
||||
@@ -18,7 +19,7 @@
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace webserver {
|
||||
namespace webresource {
|
||||
namespace resources {
|
||||
|
||||
|
||||
@@ -31,9 +32,11 @@ enum class DevicesAPIMethod {
|
||||
|
||||
|
||||
class DevicesResourceHandlerFactory
|
||||
: public virtual WebResourceHandlerFactory {
|
||||
: public virtual WebResourceHandlerFactory,
|
||||
public implementation::Service<GenericWebResourceHandlerFactory> {
|
||||
public:
|
||||
typedef std::function<libvariant::Variant( devicerepository::Device* device,
|
||||
typedef std::function<libvariant::Variant( Poco::URI& matchUri,
|
||||
devicerepository::Device* device,
|
||||
Poco::Net::HTTPServerRequest &req,
|
||||
const std::string& category,
|
||||
bool ssl )> infoCategoryFunc_t;
|
||||
@@ -43,7 +46,7 @@ private:
|
||||
std::map<std::string, infoCategoryFunc_t> infoCategoryFuncs;
|
||||
public:
|
||||
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 {
|
||||
|
||||
private:
|
||||
DevicesResourceHandlerFactory* parent;
|
||||
WebServerService* service;
|
||||
Poco::URI matchUri;
|
||||
devicerepository::DeviceRepositoryService* repoService;
|
||||
const std::map<std::string, DevicesResourceHandlerFactory::infoCategoryFunc_t>& infoCategoryFuncs;
|
||||
bool ssl;
|
||||
@@ -94,12 +97,12 @@ private:
|
||||
|
||||
public:
|
||||
|
||||
DevicesResourceHandler( DevicesResourceHandlerFactory* parent,
|
||||
DevicesResourceHandler( Poco::URI matchUri,
|
||||
WebServerService* service,
|
||||
devicerepository::DeviceRepositoryService* repoService,
|
||||
const std::map<std::string, DevicesResourceHandlerFactory::infoCategoryFunc_t>& infoCategoryFuncs,
|
||||
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;
|
||||
|
||||
|
||||
+24
-5
@@ -20,30 +20,49 @@ namespace resources {
|
||||
|
||||
using namespace httpserver;
|
||||
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) {
|
||||
// Requested URL is too short to contain any schema
|
||||
Poco::URI uri(req.getURI());
|
||||
std::vector<std::string> pathPieces;
|
||||
std::vector<std::string> pathPieces, matchPieces;
|
||||
uri.getPathSegments(pathPieces);
|
||||
size_t prefixPathSize = service->getPrefixPathPieces().size();
|
||||
if (pathPieces.size() <= prefixPathSize + 1) {
|
||||
matchUri.getPathSegments(matchPieces);
|
||||
|
||||
// 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);
|
||||
|
||||
// Requested URL may contain a valid schema
|
||||
} else {
|
||||
// Get requested schema
|
||||
std::stringstream ss;
|
||||
for (int i = prefixPathSize + 1; i < pathPieces.size(); i++) {
|
||||
for (int i = matchPieces.size(); i < pathPieces.size(); i++) {
|
||||
ss << "/" << pathPieces[i];
|
||||
}
|
||||
auto schemaPath = (boost::format("hos:schema:/%1%") % ss.str()).str();
|
||||
// Try to retrieve schema
|
||||
try {
|
||||
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);
|
||||
} 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);
|
||||
|
||||
@@ -21,16 +21,17 @@ namespace resources {
|
||||
|
||||
|
||||
class SchemaResourceHandler
|
||||
: public virtual WebResourceHandlerImpl {
|
||||
: public WebResourceHandlerImpl {
|
||||
|
||||
private:
|
||||
Poco::URI matchUri;
|
||||
ros::NodeHandle* nodehandle;
|
||||
utils::SchemaLoader* schemaLoader;
|
||||
WebServerService* service;
|
||||
|
||||
public:
|
||||
SchemaResourceHandler(ros::NodeHandle* nodehandle, utils::SchemaLoader* schemaLoader, webserver::WebServerService* service)
|
||||
: nodehandle(nodehandle), schemaLoader(schemaLoader), service(service) {}
|
||||
SchemaResourceHandler(Poco::URI matchUri, ros::NodeHandle* nodehandle, utils::SchemaLoader* schemaLoader, webserver::WebServerService* service)
|
||||
: matchUri(matchUri), nodehandle(nodehandle), schemaLoader(schemaLoader), service(service) {}
|
||||
|
||||
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_LIBRARY_DIR AND Poco_FOUNDATION_LIB)
|
||||
IF(Poco_FOUNDATION_LIB)
|
||||
IF ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
||||
SET(DBG "d")
|
||||
ELSE ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
||||
|
||||
# Debug libs are broken on Ubuntu
|
||||
# IF ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
||||
# SET(DBG "d")
|
||||
# ELSE ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
||||
SET(DBG "")
|
||||
ENDIF ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
||||
# ENDIF ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
||||
|
||||
|
||||
SET(Comp_List "Foundation${DBG}")
|
||||
FOREACH(COMPONENT ${Poco_FIND_COMPONENTS})
|
||||
FIND_LIBRARY(LIB${COMPONENT} "Poco${COMPONENT}${DBG}" Poco_LIBRARY_DIR)
|
||||
|
||||
Reference in New Issue
Block a user