.
This commit is contained in:
@@ -324,7 +324,7 @@ public:
|
|||||||
* \param[in] e event.
|
* \param[in] e event.
|
||||||
* \return notified observer count.
|
* \return notified observer count.
|
||||||
*/
|
*/
|
||||||
size_t notifyObservers(const _Key& k, const _Event* e) noexcept override {
|
virtual size_t notifyObservers(const _Key& k, const _Event* e) noexcept override {
|
||||||
std::lock_guard<std::recursive_mutex> lock(_observersMutex);
|
std::lock_guard<std::recursive_mutex> lock(_observersMutex);
|
||||||
size_t retval = 0;
|
size_t retval = 0;
|
||||||
// We work with a copy so that we can insert/remove observers within a callback.
|
// We work with a copy so that we can insert/remove observers within a callback.
|
||||||
@@ -337,6 +337,27 @@ public:
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify observers of a new event.
|
||||||
|
*
|
||||||
|
* \param[in] key observer filter key.
|
||||||
|
* \param[in] substkey key that is send to the observers.
|
||||||
|
* \param[in] e event.
|
||||||
|
* \return notified observer count.
|
||||||
|
*/
|
||||||
|
virtual size_t notifyObservers(const _Key& key, const _Key& substkey, const _Event* e) noexcept override {
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(_observersMutex);
|
||||||
|
size_t retval = 0;
|
||||||
|
// We work with a copy so that we can insert/remove observers within a callback.
|
||||||
|
observers_type tmp = _observers;
|
||||||
|
auto ol = tmp.equal_range(key);
|
||||||
|
for (auto i = ol.first; i != ol.second; i++) {
|
||||||
|
i->second->notificationReceived(this, substkey, e);
|
||||||
|
retval++;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -269,6 +269,18 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual size_t notifyObservers(const _Key& key, const _Event* e) noexcept = 0;
|
virtual size_t notifyObservers(const _Key& key, const _Event* e) noexcept = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify observers of a new event.
|
||||||
|
*
|
||||||
|
* The purpose of this function is to implement an all-events key.
|
||||||
|
*
|
||||||
|
* \param[in] key observer filter key.
|
||||||
|
* \param[in] substkey key that is send to the observers.
|
||||||
|
* \param[in] e event.
|
||||||
|
* \return notified observer count.
|
||||||
|
*/
|
||||||
|
virtual size_t notifyObservers(const _Key& key, const _Key& substkey, const _Event* e) noexcept = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -38,7 +38,8 @@ enum class DeviceEventType : int {
|
|||||||
DEVICE_REMOVED = 2,
|
DEVICE_REMOVED = 2,
|
||||||
STATUS_UPDATE_RECEIVED = 3,
|
STATUS_UPDATE_RECEIVED = 3,
|
||||||
COMMAND_RECEIVED = 4,
|
COMMAND_RECEIVED = 4,
|
||||||
STATE_CHANGED = 5
|
STATE_CHANGED = 5,
|
||||||
|
ALL_EVENTS = 6
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+18
-1
@@ -40,10 +40,12 @@ bool DeviceImpl::handleStatusMsg(const Variant& msg, const timestamp_t& stamp) n
|
|||||||
|
|
||||||
DeviceStatusMsgEvent event(this, msg, stamp);
|
DeviceStatusMsgEvent event(this, msg, stamp);
|
||||||
notifyObservers(DeviceEventType::STATUS_UPDATE_RECEIVED, &event);
|
notifyObservers(DeviceEventType::STATUS_UPDATE_RECEIVED, &event);
|
||||||
|
notifyObservers(DeviceEventType::ALL_EVENTS, DeviceEventType::STATUS_UPDATE_RECEIVED, &event);
|
||||||
|
|
||||||
if (stateChanged){
|
if (stateChanged){
|
||||||
DeviceStateChangeEvent event(this, msg, stamp);
|
DeviceStateChangeEvent event(this, msg, stamp);
|
||||||
notifyObservers(DeviceEventType::STATE_CHANGED, &event);
|
notifyObservers(DeviceEventType::STATE_CHANGED, &event);
|
||||||
|
notifyObservers(DeviceEventType::ALL_EVENTS, DeviceEventType::STATE_CHANGED, &event);
|
||||||
}
|
}
|
||||||
|
|
||||||
return stateChanged;
|
return stateChanged;
|
||||||
@@ -54,6 +56,7 @@ void DeviceImpl::handleCommandMsg(const Variant& msg, const timestamp_t& stamp)
|
|||||||
std::lock_guard<std::recursive_mutex> lock(objMutex);
|
std::lock_guard<std::recursive_mutex> lock(objMutex);
|
||||||
DeviceCmdMsgEvent event(this, msg, stamp);
|
DeviceCmdMsgEvent event(this, msg, stamp);
|
||||||
notifyObservers(DeviceEventType::COMMAND_RECEIVED, &event);
|
notifyObservers(DeviceEventType::COMMAND_RECEIVED, &event);
|
||||||
|
notifyObservers(DeviceEventType::ALL_EVENTS, DeviceEventType::COMMAND_RECEIVED, &event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -173,6 +176,7 @@ void DeviceRepositoryServiceImpl::addDevice(const std::string& name, XmlRpc::Xml
|
|||||||
// send device added event
|
// send device added event
|
||||||
DeviceAddedEvent event(dev.get(), std::chrono::system_clock::now());
|
DeviceAddedEvent event(dev.get(), std::chrono::system_clock::now());
|
||||||
notifyObservers(DeviceEventType::DEVICE_ADDED, &event);
|
notifyObservers(DeviceEventType::DEVICE_ADDED, &event);
|
||||||
|
notifyObservers(DeviceEventType::ALL_EVENTS, DeviceEventType::DEVICE_ADDED, &event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -182,7 +186,9 @@ void DeviceRepositoryServiceImpl::removeDevice(const std::string& name) {
|
|||||||
if (dev != devices.end()) {
|
if (dev != devices.end()) {
|
||||||
DeviceRemovedEvent event(dev->second.get(), std::chrono::system_clock::now());
|
DeviceRemovedEvent event(dev->second.get(), std::chrono::system_clock::now());
|
||||||
notifyObservers(DeviceEventType::DEVICE_REMOVED, &event);
|
notifyObservers(DeviceEventType::DEVICE_REMOVED, &event);
|
||||||
|
notifyObservers(DeviceEventType::ALL_EVENTS, DeviceEventType::DEVICE_REMOVED, &event);
|
||||||
dev->second->notifyObservers(DeviceEventType::DEVICE_REMOVED, &event);
|
dev->second->notifyObservers(DeviceEventType::DEVICE_REMOVED, &event);
|
||||||
|
dev->second->notifyObservers(DeviceEventType::ALL_EVENTS, DeviceEventType::DEVICE_REMOVED, &event);
|
||||||
devices.erase(name);
|
devices.erase(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -232,7 +238,15 @@ void DeviceRepositoryServiceImpl::statusMsgCallback(const hos_core_msgs::DeviceS
|
|||||||
auto dev = devices.find(msg->device_id);
|
auto dev = devices.find(msg->device_id);
|
||||||
if (dev != devices.end()) {
|
if (dev != devices.end()) {
|
||||||
auto stamp = std::chrono::system_clock::now();
|
auto stamp = std::chrono::system_clock::now();
|
||||||
dev->second->handleStatusMsg(m, stamp);
|
bool stateChanged = dev->second->handleStatusMsg(m, stamp);
|
||||||
|
DeviceStatusMsgEvent event(dev->second.get(), m, stamp);
|
||||||
|
notifyObservers(DeviceEventType::STATUS_UPDATE_RECEIVED, &event);
|
||||||
|
notifyObservers(DeviceEventType::ALL_EVENTS, DeviceEventType::STATUS_UPDATE_RECEIVED, &event);
|
||||||
|
if (stateChanged) {
|
||||||
|
DeviceStateChangeEvent event(dev->second.get(), m, stamp);
|
||||||
|
notifyObservers(DeviceEventType::STATE_CHANGED, &event);
|
||||||
|
notifyObservers(DeviceEventType::ALL_EVENTS, DeviceEventType::STATE_CHANGED, &event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -261,6 +275,9 @@ void DeviceRepositoryServiceImpl::cmdMsgCallback(const hos_core_msgs::DeviceComm
|
|||||||
if (dev != devices.end()) {
|
if (dev != devices.end()) {
|
||||||
auto stamp = std::chrono::system_clock::now();
|
auto stamp = std::chrono::system_clock::now();
|
||||||
dev->second->handleCommandMsg(m, stamp);
|
dev->second->handleCommandMsg(m, stamp);
|
||||||
|
DeviceCmdMsgEvent event(dev->second.get(), m, stamp);
|
||||||
|
notifyObservers(DeviceEventType::COMMAND_RECEIVED, &event);
|
||||||
|
notifyObservers(DeviceEventType::ALL_EVENTS, DeviceEventType::COMMAND_RECEIVED, &event);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+98
-104
@@ -77,39 +77,103 @@ DeviceAPIMethod DeviceRepoHandlerFactory::getDeviceAPIMethod() noexcept {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::shared_ptr<DeviceEventQueue> DeviceRepoHandlerFactory::getDeviceEventQueue(std::string clientID) {
|
||||||
|
if (clientID.empty()) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Net::HTTPRequestHandler* DeviceRepoHandlerFactory::createRequestHandler( Poco::URI matchUri, const Net::HTTPServerRequest& request, bool ssl ) noexcept {
|
Net::HTTPRequestHandler* DeviceRepoHandlerFactory::createRequestHandler( Poco::URI matchUri, const Net::HTTPServerRequest& request, bool ssl ) noexcept {
|
||||||
return new DeviceRepoHandler(matchUri, repoService, infoCategoryFuncs, ssl);
|
if(request.find("Upgrade") != request.end() && Poco::icompare(request["Upgrade"], "websocket") == 0)
|
||||||
|
return new DeviceRepoEventWebSocketHandler(matchUri, repoService, infoCategoryFuncs, ssl);
|
||||||
|
else {
|
||||||
|
DeviceAPIMethod method = getDeviceAPIMethod();
|
||||||
|
if (method == DeviceAPIMethod::REGISTEREVENT) {
|
||||||
|
return new DeviceRepoEventLongPollingHandler(matchUri, repoService, infoCategoryFuncs, ssl);
|
||||||
|
} else {
|
||||||
|
return new DeviceRepoInfoHandler(matchUri, method, repoService, infoCategoryFuncs, ssl);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void DeviceRepoHandler::_handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
|
||||||
// Get API method parameter
|
|
||||||
Net::HTMLForm form(req);
|
|
||||||
DeviceAPIMethod dataMethod = DeviceAPIMethod::GET; // Default method is get
|
|
||||||
std::string methodValue;
|
Variant DeviceRepoHandlerBase::getDeviceInfo(devicerepository::Device* device, Net::HTTPServerRequest &req, const std::string& category, const std::vector<std::string>& path) {
|
||||||
if (form.has("method")) {
|
Variant retval;
|
||||||
std::string methodRaw = form.get("method");
|
|
||||||
bool requireValue = false;
|
// We want all info categories
|
||||||
if (methodRaw == "get") {
|
if (category.empty()) {
|
||||||
// do nothing
|
for (auto c : infoCategoryFuncs) {
|
||||||
} else if (methodRaw == "command") {
|
retval[c.first] = c.second(matchUri, device, req, category, ssl);
|
||||||
dataMethod = DeviceAPIMethod::COMMAND;
|
|
||||||
requireValue = true;
|
|
||||||
} else if (methodRaw.compare("statusupdate") == 0) {
|
|
||||||
dataMethod = DeviceAPIMethod::STATUSUPDATE;
|
|
||||||
requireValue = true;
|
|
||||||
} else {
|
|
||||||
throw webserver::webresource::WebResourceHandlerException((boost::format("Unknown API method \"%1%\"") % methodRaw).str(),
|
|
||||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
|
||||||
}
|
}
|
||||||
if (requireValue) {
|
|
||||||
if (form.has("value")) {
|
// We want a single info category
|
||||||
methodValue = form.get("value");
|
} else {
|
||||||
} else {
|
auto c = infoCategoryFuncs.find(category);
|
||||||
throw webserver::webresource::WebResourceHandlerException((boost::format("API method \"%1%\" requires a value parameter.") % methodRaw).str(),
|
if (c != infoCategoryFuncs.end()) {
|
||||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
retval = c->second(matchUri, device, req, category, ssl);
|
||||||
|
if (path.size() > 0) {
|
||||||
|
std::stringstream ss;
|
||||||
|
for (auto p : path) {
|
||||||
|
ss << "/" << p;
|
||||||
|
}
|
||||||
|
std::string pathstr = ss.str();
|
||||||
|
if (retval.HasPath(pathstr)) {
|
||||||
|
retval = retval.GetPath(pathstr);
|
||||||
|
} else {
|
||||||
|
throw webserver::webresource::WebResourceHandlerException((boost::format("Unknown path \"%1%\" for device info category \"%2%\".") % pathstr % category).str(),
|
||||||
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
throw webserver::webresource::WebResourceHandlerException((boost::format("Unknown device info category \"%1%\"") % category).str(),
|
||||||
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void DeviceRepoHandlerBase::sendDeviceCommand(devicerepository::Device* device, Net::HTTPServerRequest &req, const std::string& cmd, const std::vector<std::string>& path) {
|
||||||
|
Variant cmdMsg;
|
||||||
|
VariantRef mPart = cmdMsg.Ref();
|
||||||
|
if (path.size() > 0) {
|
||||||
|
for (int i = 0; i < path.size(); i++) {
|
||||||
|
mPart[path[i]] = Variant();
|
||||||
|
mPart.ReassignRef(mPart[path[i]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* The libvariant json deserializer knows nothing about RFC 7159, therefore non-object or non-array values are rejected.
|
||||||
|
* As a workaround we use the yaml deserializer (yaml can be considered a super-set of json).
|
||||||
|
* Fun fact: the json serializer accepts non-object or non-array values.
|
||||||
|
*/
|
||||||
|
//mPart = DeserializeJSON(cmd);
|
||||||
|
mPart = DeserializeYAML(cmd);
|
||||||
|
device->sendCommand(cmdMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void DeviceRepoInfoHandler::__handle(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Net::HTMLForm& form) {
|
||||||
|
|
||||||
|
std::string methodValue;
|
||||||
|
if (method == DeviceAPIMethod::COMMAND || method == DeviceAPIMethod::STATUSUPDATE) {
|
||||||
|
if (form.has("value")) {
|
||||||
|
methodValue = form.get("value");
|
||||||
|
} else {
|
||||||
|
throw webserver::webresource::WebResourceHandlerException("API method requires a value parameter.",
|
||||||
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +184,7 @@ void DeviceRepoHandler::_handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net:
|
|||||||
|
|
||||||
// No device given
|
// No device given
|
||||||
if (pathPieces.size() <= matchPieces.size()) {
|
if (pathPieces.size() <= matchPieces.size()) {
|
||||||
if (dataMethod != DeviceAPIMethod::GET) {
|
if (method != DeviceAPIMethod::GET) {
|
||||||
throw webserver::webresource::WebResourceHandlerException("Requested API method requires a device",
|
throw webserver::webresource::WebResourceHandlerException("Requested API method requires a device",
|
||||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_BAD_REQUEST);
|
||||||
}
|
}
|
||||||
@@ -181,7 +245,7 @@ void DeviceRepoHandler::_handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net:
|
|||||||
std::string devid = pathPieces[matchPieces.size()];
|
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 (method) {
|
||||||
case DeviceAPIMethod::GET:
|
case DeviceAPIMethod::GET:
|
||||||
{
|
{
|
||||||
std::string category;
|
std::string category;
|
||||||
@@ -220,84 +284,14 @@ void DeviceRepoHandler::_handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void DeviceRepoHandler::_handlePOST(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
void DeviceRepoInfoHandler::_handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
||||||
throw webserver::webresource::WebResourceHandlerException("ToDo: Implement POST.");
|
Net::HTMLForm form(req);
|
||||||
|
__handle(req, resp, form);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeviceRepoInfoHandler::_handlePOST(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
||||||
|
Net::HTMLForm form(req, req.stream());
|
||||||
Variant DeviceRepoHandler::getDeviceInfo(devicerepository::Device* device, Net::HTTPServerRequest &req, const std::string& category, const std::vector<std::string>& path) {
|
__handle(req, resp, form);
|
||||||
Variant retval;
|
|
||||||
|
|
||||||
// We want all info categories
|
|
||||||
if (category.empty()) {
|
|
||||||
for (auto c : infoCategoryFuncs) {
|
|
||||||
retval[c.first] = c.second(matchUri, device, req, category, ssl);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We want a single info category
|
|
||||||
} else {
|
|
||||||
auto c = infoCategoryFuncs.find(category);
|
|
||||||
if (c != infoCategoryFuncs.end()) {
|
|
||||||
retval = c->second(matchUri, device, req, category, ssl);
|
|
||||||
if (path.size() > 0) {
|
|
||||||
std::stringstream ss;
|
|
||||||
for (auto p : path) {
|
|
||||||
ss << "/" << p;
|
|
||||||
}
|
|
||||||
std::string pathstr = ss.str();
|
|
||||||
if (retval.HasPath(pathstr)) {
|
|
||||||
retval = retval.GetPath(pathstr);
|
|
||||||
} else {
|
|
||||||
throw webserver::webresource::WebResourceHandlerException((boost::format("Unknown path \"%1%\" for device info category \"%2%\".") % pathstr % category).str(),
|
|
||||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw webserver::webresource::WebResourceHandlerException((boost::format("Unknown device info category \"%1%\"") % category).str(),
|
|
||||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_FOUND);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeviceRepoHandler::notificationReceived(interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
|
||||||
switch (key) {
|
|
||||||
case devicerepository::DeviceEventType::DEVICE_ADDED:
|
|
||||||
break;
|
|
||||||
case devicerepository::DeviceEventType::DEVICE_REMOVED:
|
|
||||||
break;
|
|
||||||
case devicerepository::DeviceEventType::COMMAND_RECEIVED:
|
|
||||||
break;
|
|
||||||
case devicerepository::DeviceEventType::STATUS_UPDATE_RECEIVED:
|
|
||||||
break;
|
|
||||||
case devicerepository::DeviceEventType::STATE_CHANGED:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+103
-32
@@ -11,6 +11,8 @@
|
|||||||
#include <ros/ros.h>
|
#include <ros/ros.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <queue>
|
||||||
|
#include <memory>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
|
|
||||||
@@ -27,7 +29,51 @@ namespace webresource {
|
|||||||
enum class DeviceAPIMethod {
|
enum class DeviceAPIMethod {
|
||||||
GET,
|
GET,
|
||||||
COMMAND,
|
COMMAND,
|
||||||
STATUSUPDATE
|
STATUSUPDATE,
|
||||||
|
REGISTEREVENT
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceEventQueue
|
||||||
|
: public virtual interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent> {
|
||||||
|
public:
|
||||||
|
const std::string clientID;
|
||||||
|
DeviceRepositoryService* const repoService;
|
||||||
|
DeviceEventType eventType;
|
||||||
|
Device* device;
|
||||||
|
std::string pointer;
|
||||||
|
std::queue<libvariant::Variant> eventQueue;
|
||||||
|
size_t openConnectionCount = 0;
|
||||||
|
|
||||||
|
DeviceEventQueue( const std::string& clientID,
|
||||||
|
const DeviceEventType eventType,
|
||||||
|
DeviceRepositoryService* repoService,
|
||||||
|
Device* device,
|
||||||
|
std::string pointer )
|
||||||
|
: clientID(clientID), eventType(eventType), repoService(repoService), device(device), pointer(pointer) {}
|
||||||
|
|
||||||
|
virtual void notificationReceived( interface::Observer<devicerepository::DeviceEventType,
|
||||||
|
devicerepository::DeviceEvent>::observable_type* o,
|
||||||
|
const devicerepository::DeviceEventType& key,
|
||||||
|
const devicerepository::DeviceEvent* e) noexcept override {
|
||||||
|
if (eventType == DeviceEventType::ALL_EVENTS || eventType == key) {
|
||||||
|
switch (key) {
|
||||||
|
case devicerepository::DeviceEventType::COMMAND_RECEIVED:
|
||||||
|
break;
|
||||||
|
case devicerepository::DeviceEventType::STATUS_UPDATE_RECEIVED:
|
||||||
|
break;
|
||||||
|
case devicerepository::DeviceEventType::STATE_CHANGED:
|
||||||
|
break;
|
||||||
|
case devicerepository::DeviceEventType::DEVICE_ADDED:
|
||||||
|
break;
|
||||||
|
case devicerepository::DeviceEventType::DEVICE_REMOVED:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -43,8 +89,10 @@ public:
|
|||||||
bool ssl )> infoCategoryFunc_t;
|
bool ssl )> infoCategoryFunc_t;
|
||||||
private:
|
private:
|
||||||
webserver::WebServerService* service = nullptr;
|
webserver::WebServerService* service = nullptr;
|
||||||
devicerepository::DeviceRepositoryService* repoService;
|
DeviceRepositoryService* repoService;
|
||||||
std::map<std::string, infoCategoryFunc_t> infoCategoryFuncs;
|
std::map<std::string, infoCategoryFunc_t> infoCategoryFuncs;
|
||||||
|
std::map<std::string, std::shared_ptr<DeviceEventQueue>> deviceEventQueues;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DeviceRepoHandlerFactory(devicerepository::DeviceRepositoryService* repoService);
|
DeviceRepoHandlerFactory(devicerepository::DeviceRepositoryService* repoService);
|
||||||
|
|
||||||
@@ -60,6 +108,12 @@ public:
|
|||||||
|
|
||||||
static DeviceAPIMethod getDeviceAPIMethod() noexcept;
|
static DeviceAPIMethod getDeviceAPIMethod() noexcept;
|
||||||
|
|
||||||
|
std::shared_ptr<DeviceEventQueue> getDeviceEventQueue( const std::string& clientID,
|
||||||
|
const DeviceEventType eventType,
|
||||||
|
DeviceRepositoryService* repoService,
|
||||||
|
Device* device,
|
||||||
|
std::string pointer );
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -88,8 +142,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class DeviceRepoHandlerBase
|
class DeviceRepoHandlerBase
|
||||||
: public interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent>,
|
: public webserver::webresource::WebResourceHandlerImpl {
|
||||||
public webserver::webresource::WebResourceHandlerImpl {
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Poco::URI matchUri;
|
Poco::URI matchUri;
|
||||||
@@ -116,56 +169,74 @@ public:
|
|||||||
bool ssl = false )
|
bool ssl = false )
|
||||||
: matchUri(matchUri), repoService(repoService), infoCategoryFuncs(infoCategoryFuncs), ssl(ssl) {}
|
: matchUri(matchUri), repoService(repoService), infoCategoryFuncs(infoCategoryFuncs), ssl(ssl) {}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceRepoInfoHandler
|
||||||
|
: public DeviceRepoHandlerBase {
|
||||||
|
|
||||||
|
protected:
|
||||||
|
DeviceAPIMethod method;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
DeviceRepoInfoHandler( Poco::URI matchUri,
|
||||||
|
DeviceAPIMethod method,
|
||||||
|
devicerepository::DeviceRepositoryService* repoService,
|
||||||
|
const std::map<std::string, DeviceRepoHandlerFactory::infoCategoryFunc_t>& infoCategoryFuncs,
|
||||||
|
bool ssl = false )
|
||||||
|
: DeviceRepoHandlerBase(matchUri, repoService, infoCategoryFuncs, ssl), method(method) {}
|
||||||
|
|
||||||
virtual void _handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override;
|
virtual void _handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override;
|
||||||
|
|
||||||
virtual void _handlePOST(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override;
|
virtual void _handlePOST(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override;
|
||||||
|
|
||||||
virtual void notificationReceived( interface::Observer<devicerepository::DeviceEventType,
|
virtual void __handle(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp, Poco::Net::HTMLForm& form);
|
||||||
devicerepository::DeviceEvent>::observable_type* o,
|
|
||||||
const devicerepository::DeviceEventType& key,
|
|
||||||
const devicerepository::DeviceEvent* e) noexcept override;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DeviceRepoHandler
|
class DeviceRepoEventLongPollingHandler
|
||||||
: public interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent>,
|
: public DeviceRepoHandlerBase {
|
||||||
public webserver::webresource::WebResourceHandlerImpl {
|
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
Poco::URI matchUri;
|
|
||||||
devicerepository::DeviceRepositoryService* repoService;
|
|
||||||
const std::map<std::string, DeviceRepoHandlerFactory::infoCategoryFunc_t>& infoCategoryFuncs;
|
|
||||||
bool ssl;
|
|
||||||
|
|
||||||
libvariant::Variant getDeviceInfo( devicerepository::Device* device,
|
|
||||||
Poco::Net::HTTPServerRequest &req,
|
|
||||||
const std::string& category = std::string(),
|
|
||||||
const std::vector<std::string>& path = std::vector<std::string>() );
|
|
||||||
|
|
||||||
void sendDeviceCommand( devicerepository::Device* device,
|
|
||||||
Poco::Net::HTTPServerRequest &req,
|
|
||||||
const std::string& cmd,
|
|
||||||
const std::vector<std::string>& path = std::vector<std::string>() );
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
DeviceRepoHandler( Poco::URI matchUri,
|
DeviceRepoEventLongPollingHandler( Poco::URI matchUri,
|
||||||
devicerepository::DeviceRepositoryService* repoService,
|
devicerepository::DeviceRepositoryService* repoService,
|
||||||
const std::map<std::string, DeviceRepoHandlerFactory::infoCategoryFunc_t>& infoCategoryFuncs,
|
const std::map<std::string, DeviceRepoHandlerFactory::infoCategoryFunc_t>& infoCategoryFuncs,
|
||||||
bool ssl = false )
|
bool ssl = false )
|
||||||
: matchUri(matchUri), repoService(repoService), infoCategoryFuncs(infoCategoryFuncs), ssl(ssl) {}
|
: DeviceRepoHandlerBase(matchUri, repoService, infoCategoryFuncs, 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;
|
||||||
|
|
||||||
virtual void _handlePOST(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override;
|
virtual void _handlePOST(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override;
|
||||||
|
|
||||||
virtual void notificationReceived( interface::Observer<devicerepository::DeviceEventType,
|
};
|
||||||
devicerepository::DeviceEvent>::observable_type* o,
|
|
||||||
const devicerepository::DeviceEventType& key,
|
|
||||||
const devicerepository::DeviceEvent* e) noexcept override;
|
|
||||||
|
class DeviceRepoEventWebSocketHandler
|
||||||
|
: public DeviceRepoHandlerBase {
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
DeviceRepoEventWebSocketHandler( Poco::URI matchUri,
|
||||||
|
devicerepository::DeviceRepositoryService* repoService,
|
||||||
|
const std::map<std::string, DeviceRepoHandlerFactory::infoCategoryFunc_t>& infoCategoryFuncs,
|
||||||
|
bool ssl = false )
|
||||||
|
: DeviceRepoHandlerBase(matchUri, repoService, infoCategoryFuncs, ssl) {}
|
||||||
|
|
||||||
|
virtual void _handleGET(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override;
|
||||||
|
|
||||||
|
virtual void _handlePOST(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,33 @@
|
|||||||
HTTP - GET / HTTP - POST (application/x-www-form-urlencoded):
|
HTTP - GET / HTTP - POST (application/x-www-form-urlencoded):
|
||||||
==============================================================
|
==============================================================
|
||||||
x) [OUT] DeviceAPIMethod::GET [Args: format, pointer, query?]
|
x) [OUT] DeviceAPIMethod::GET [Args: format, pointer, query?]
|
||||||
x) [IN] DeviceAPIMethod::COMMAND [Args: format, pointer, msg]
|
-- http[s]://<baseURL>/devices[/<id>/<pointer>]
|
||||||
x) [IN] DeviceAPIMethod::STATUS_UPDATE [Args: format, pointer, msg]
|
|
||||||
x) [EVENT] DeviceAPIMethod::REGISTER_EVENT [Args: format, pointer, event]
|
|
||||||
- Long-Polling
|
|
||||||
- WebSocket
|
|
||||||
|
|
||||||
|
x) [IN] DeviceAPIMethod::COMMAND [Args: format, pointer, msg]
|
||||||
|
-- http[s]://<baseURL>/devices/<id>[/<pointer>]
|
||||||
|
|
||||||
|
x) [IN] DeviceAPIMethod::STATUS_UPDATE [Args: format, pointer, msg]
|
||||||
|
-- http[s]://<baseURL>/devices/<id>[/<pointer>]
|
||||||
|
|
||||||
|
x) [EVENT] DeviceAPIMethod::REGISTER_EVENT [Args: format, pointer, event]
|
||||||
|
-- http[s]://<baseURL>/devices/<id>[/<pointer>]
|
||||||
|
- Long-Polling
|
||||||
|
|
||||||
|
HTTP - PUT:
|
||||||
|
============
|
||||||
|
x) [IN] DeviceAPIMethod::COMMAND [Args: format, pointer, msg]
|
||||||
|
-- http[s]://<baseURL>/devices/<id>/command[/<pointer>]
|
||||||
|
|
||||||
|
x) [IN] DeviceAPIMethod::STATUS_UPDATE [Args: format, pointer, msg]
|
||||||
|
-- http[s]://<baseURL>/devices/<id>/statusupdate[/<pointer>]
|
||||||
|
|
||||||
|
HTTP - WebSocket:
|
||||||
|
==================
|
||||||
|
x) [EVENT] DeviceAPIMethod::REGISTER_EVENT [Args: format, pointer, event]
|
||||||
|
-- ws://<baseURL>/devices/<id>[/<pointer>]
|
||||||
|
|
||||||
|
|
||||||
|
==============================================================
|
||||||
|
|
||||||
API Method Parameter:
|
API Method Parameter:
|
||||||
-- Query: method = get | command | statusupdate | event
|
-- Query: method = get | command | statusupdate | event
|
||||||
@@ -30,3 +51,8 @@ COMMAND/STATUS_UPDATE Parameters:
|
|||||||
|
|
||||||
EVENT Parameters:
|
EVENT Parameters:
|
||||||
-- Query: event = command | statusupdate | statechange | added | removed | all
|
-- Query: event = command | statusupdate | statechange | added | removed | all
|
||||||
|
|
||||||
|
|
||||||
|
==============================================================
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+8
-2
@@ -261,6 +261,10 @@ protected:
|
|||||||
throw NotImplementedException();
|
throw NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void _handlePUT(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) {
|
||||||
|
throw NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
virtual void handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override {
|
virtual void handleRequest(Poco::Net::HTTPServerRequest &req, Poco::Net::HTTPServerResponse &resp) override {
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
@@ -271,14 +275,16 @@ protected:
|
|||||||
_handleGET(req, resp);
|
_handleGET(req, resp);
|
||||||
} else if (req.getMethod() == Poco::Net::HTTPRequest::HTTP_POST) {
|
} else if (req.getMethod() == Poco::Net::HTTPRequest::HTTP_POST) {
|
||||||
_handlePOST(req, resp);
|
_handlePOST(req, resp);
|
||||||
|
} else if (req.getMethod() == Poco::Net::HTTPRequest::HTTP_PUT) {
|
||||||
|
_handlePUT(req, resp);
|
||||||
} else {
|
} else {
|
||||||
std::cout << "Unsupported HTTP Request Method" << std::endl;
|
std::cout << "Unsupported HTTP Request Method" << std::endl;
|
||||||
handleErrorResponse(req, resp, (boost::format("HTTP method %1% not implemented") % req.getMethod()).str(),
|
handleErrorResponse(req, resp, (boost::format("HTTP method %1% not supported") % req.getMethod()).str(),
|
||||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_IMPLEMENTED);
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_IMPLEMENTED);
|
||||||
}
|
}
|
||||||
} catch (NotImplementedException& e) {
|
} catch (NotImplementedException& e) {
|
||||||
std::cout << "Unsupported HTTP Request Method" << std::endl;
|
std::cout << "Unsupported HTTP Request Method" << std::endl;
|
||||||
handleErrorResponse(req, resp, (boost::format("HTTP method %1% not implemented") % req.getMethod()).str(),
|
handleErrorResponse(req, resp, (boost::format("HTTP method %1% not supported") % req.getMethod()).str(),
|
||||||
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_IMPLEMENTED);
|
Poco::Net::HTTPResponse::HTTPStatus::HTTP_NOT_IMPLEMENTED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user