add more rest resources

This commit is contained in:
Simon Stürz 2015-07-27 18:18:36 +02:00 committed by Michael Zanetti
parent b86a062a87
commit 34e53ef5b3
29 changed files with 1617 additions and 204 deletions

View File

@ -97,16 +97,41 @@
...
*/
/*! \enum HttpReply::Type
*/
#include "httpreply.h"
#include <QDateTime>
#include <QPair>
/*! Construct a HttpReply with the given \a statusCode. */
HttpReply::HttpReply(const HttpStatusCode &statusCode) :
m_statusCode(statusCode),
m_payload(QByteArray())
HttpReply::HttpReply(QObject *parent) :
QObject(parent),
m_statusCode(HttpReply::Ok),
m_type(HttpReply::TypeSync),
m_payload(QByteArray()),
m_timedOut(false)
{
connect(&m_timer, &QTimer::timeout, this, &HttpReply::timedOut);
// set known headers
setHeader(HttpHeaderType::ServerHeader, "guh/" + QByteArray(GUH_VERSION_STRING));
setHeader(HttpHeaderType::DateHeader, QDateTime::currentDateTime().toString("ddd, dd MMM yyyy hh:mm:ss").toUtf8() + " GMT");
setHeader(HttpHeaderType::CacheControlHeader, "no-cache");
packReply();
}
HttpReply::HttpReply(const HttpReply::HttpStatusCode &statusCode, const HttpReply::Type &type, QObject *parent):
QObject(parent),
m_statusCode(statusCode),
m_type(type),
m_payload(QByteArray()),
m_timedOut(false)
{
connect(&m_timer, &QTimer::timeout, this, &HttpReply::timedOut);
// set known headers
setHeader(HttpHeaderType::ServerHeader, "guh/" + QByteArray(GUH_VERSION_STRING));
setHeader(HttpHeaderType::DateHeader, QDateTime::currentDateTime().toString("ddd, dd MMM yyyy hh:mm:ss").toUtf8() + " GMT");
@ -118,6 +143,7 @@ HttpReply::HttpReply(const HttpStatusCode &statusCode) :
void HttpReply::setHttpStatusCode(const HttpReply::HttpStatusCode &statusCode)
{
m_statusCode = statusCode;
packReply();
}
/*! Returns the status code of this \l{HttpReply}.*/
@ -126,11 +152,30 @@ HttpReply::HttpStatusCode HttpReply::httpStatusCode() const
return m_statusCode;
}
/*! Returns the type of this \l{HttpReply}.
* \sa Type
*/
HttpReply::Type HttpReply::type() const
{
return m_type;
}
void HttpReply::setClientId(const QUuid &clientId)
{
m_clientId = clientId;
}
QUuid HttpReply::clientId() const
{
return m_clientId;
}
/*! Set the payload of this \l{HttpReply} to the given \a data.*/
void HttpReply::setPayload(const QByteArray &data)
{
m_payload = data;
setHeader(HttpHeaderType::ContentLenghtHeader, QByteArray::number(data.length()));
packReply();
}
/*! Returns the payload of this \l{HttpReply}.*/
@ -149,6 +194,7 @@ void HttpReply::setRawHeader(const QByteArray headerType, const QByteArray &valu
m_rawHeaderList.remove(headerType);
}
m_rawHeaderList.insert(headerType, value);
packReply();
}
/*! This method appends a known header to the header list of this \l{HttpReply}.
@ -211,6 +257,11 @@ QByteArray HttpReply::data() const
return m_data;
}
bool HttpReply::timedOut() const
{
return m_timedOut;
}
QByteArray HttpReply::getHttpReasonPhrase(const HttpReply::HttpStatusCode &statusCode)
{
switch (statusCode) {
@ -278,3 +329,14 @@ QByteArray HttpReply::getHeaderType(const HttpReply::HttpHeaderType &headerType)
return QByteArray();
}
}
void HttpReply::startWait()
{
m_timer.start(5000);
}
void HttpReply::timeout()
{
m_timedOut = true;
emit finished();
}

View File

@ -21,13 +21,17 @@
#ifndef HTTPREPLY_H
#define HTTPREPLY_H
#include <QObject>
#include <QByteArray>
#include <QHash>
#include <QTimer>
#include <QUuid>
// Note: RFC 7231 HTTP/1.1 Semantics and Content -> http://tools.ietf.org/html/rfc7231
class HttpReply
class HttpReply: public QObject
{
Q_OBJECT
public:
enum HttpStatusCode {
@ -62,11 +66,22 @@ public:
ServerHeader
};
explicit HttpReply(const HttpStatusCode &statusCode = HttpStatusCode::Ok);
enum Type {
TypeSync,
TypeAsync
};
HttpReply(QObject *parent = 0);
HttpReply(const HttpStatusCode &statusCode = HttpStatusCode::Ok, const Type &type = TypeSync, QObject *parent = 0);
void setHttpStatusCode(const HttpStatusCode &statusCode);
HttpStatusCode httpStatusCode() const;
Type type() const;
void setClientId(const QUuid &clientId);
QUuid clientId() const;
void setPayload(const QByteArray &data);
QByteArray payload() const;
@ -82,18 +97,34 @@ public:
QByteArray data() const;
bool timedOut() const;
private:
HttpStatusCode m_statusCode;
Type m_type;
QUuid m_clientId;
QByteArray m_rawHeader;
QByteArray m_payload;
QByteArray m_data;
QHash<QByteArray, QByteArray> m_rawHeaderList;
QTimer m_timer;
bool m_timedOut;
QByteArray getHttpReasonPhrase(const HttpStatusCode &statusCode);
QByteArray getHeaderType(const HttpHeaderType &headerType);
QByteArray packHeader() const;
public slots:
void startWait();
signals:
void finished();
private slots:
void timeout();
};
#endif // HTTPREPLY_H

View File

@ -56,9 +56,13 @@ HttpRequest::HttpRequest(QByteArray rawData) :
qCWarning(dcWebServer) << "Unknown HTTP version:" << m_httpVersion;
return;
}
m_method = getRequestMethodType(statusLineTokens.at(0).simplified());
m_methodString = statusLineTokens.at(0).simplified();
m_method = getRequestMethodType(m_methodString);
m_urlQuery = QUrlQuery(statusLineTokens.at(1).simplified());
m_url = QUrl("http://example.com" + statusLineTokens.at(1).simplified());
if (m_url.hasQuery())
m_urlQuery = QUrlQuery(m_url.query());
// verify headers
foreach (const QString &line, headerLines) {
@ -92,11 +96,21 @@ HttpRequest::RequestMethod HttpRequest::method() const
return m_method;
}
QString HttpRequest::methodString() const
{
return m_methodString;
}
QByteArray HttpRequest::httpVersion() const
{
return m_httpVersion;
}
QUrl HttpRequest::url() const
{
return m_url;
}
QUrlQuery HttpRequest::urlQuery() const
{
return m_urlQuery;
@ -134,9 +148,10 @@ HttpRequest::RequestMethod HttpRequest::getRequestMethodType(const QString &meth
QDebug operator<<(QDebug debug, const HttpRequest &httpRequest)
{
debug << "===================================" << "\n";
debug << "\n===================================" << "\n";
debug << " http version: " << httpRequest.httpVersion() << "\n";
debug << " method: " << httpRequest.method() << "\n";
debug << " method: " << httpRequest.methodString() << "\n";
debug << " URL path: " << httpRequest.url().path() << "\n";
debug << " URL query: " << httpRequest.urlQuery().query() << "\n";
debug << " is valid: " << httpRequest.isValid() << "\n";
debug << "-----------------------------------" << "\n";

View File

@ -43,7 +43,10 @@ public:
QHash<QByteArray, QByteArray> rawHeaderList() const;
RequestMethod method() const;
QString methodString() const;
QByteArray httpVersion() const;
QUrl url() const;
QUrlQuery urlQuery() const;
QByteArray payload() const;
@ -57,7 +60,10 @@ private:
QHash<QByteArray, QByteArray> m_rawHeaderList;
RequestMethod m_method;
QString m_methodString;
QByteArray m_httpVersion;
QUrl m_url;
QUrlQuery m_urlQuery;
QByteArray m_payload;

View File

@ -574,12 +574,9 @@ void DeviceHandler::devicesDiscovered(const DeviceClassId &deviceClassId, const
}
JsonReply *reply = m_discoverRequests.take(deviceClassId);
QVariantList list;
foreach (const DeviceDescriptor &descriptor, deviceDescriptors) {
list.append(JsonTypes::packDeviceDescriptor(descriptor));
}
QVariantMap returns;
returns.insert("deviceDescriptors", list);
returns.insert("deviceDescriptors", JsonTypes::packDeviceDescriptors(deviceDescriptors));
returns.insert("deviceError", JsonTypes::deviceErrorToString(DeviceManager::DeviceErrorNoError));
reply->setData(returns);

View File

@ -713,6 +713,42 @@ QVariantList JsonTypes::packDeviceStates(Device *device)
return stateValues;
}
QVariantList JsonTypes::packDeviceDescriptors(const QList<DeviceDescriptor> deviceDescriptors)
{
QVariantList deviceDescriptorList;
foreach (const DeviceDescriptor &deviceDescriptor, deviceDescriptors) {
deviceDescriptorList.append(JsonTypes::packDeviceDescriptor(deviceDescriptor));
}
return deviceDescriptorList;
}
QVariantList JsonTypes::packActionTypes(const DeviceClass &deviceClass)
{
QVariantList actionTypes;
foreach (const ActionType &actionType, deviceClass.actionTypes()) {
actionTypes.append(JsonTypes::packActionType(actionType));
}
return actionTypes;
}
QVariantList JsonTypes::packStateTypes(const DeviceClass &deviceClass)
{
QVariantList stateTypes;
foreach (const StateType &stateType, deviceClass.stateTypes()) {
stateTypes.append(JsonTypes::packStateType(stateType));
}
return stateTypes;
}
QVariantList JsonTypes::packEventTypes(const DeviceClass &deviceClass)
{
QVariantList eventTypes;
foreach (const EventType &eventType, deviceClass.eventTypes()) {
eventTypes.append(JsonTypes::packEventType(eventType));
}
return eventTypes;
}
QVariantList JsonTypes::packPlugins()
{
QVariantList pluginsList;

View File

@ -165,6 +165,13 @@ public:
static QVariantList packSupportedDevices(const VendorId &vendorId);
static QVariantList packConfiguredDevices();
static QVariantList packDeviceStates(Device *device);
static QVariantList packDeviceDescriptors(const QList<DeviceDescriptor> deviceDescriptors);
static QVariantList packActionTypes(const DeviceClass &deviceClass);
static QVariantList packStateTypes(const DeviceClass &deviceClass);
static QVariantList packEventTypes(const DeviceClass &deviceClass);
static QVariantList packPlugins();

View File

@ -0,0 +1,269 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "deviceclassesresource.h"
#include "network/httprequest.h"
#include "guhcore.h"
#include <QJsonDocument>
namespace guhserver {
DeviceClassesResource::DeviceClassesResource(QObject *parent) :
RestResource(parent)
{
connect(GuhCore::instance(), &GuhCore::devicesDiscovered, this, &DeviceClassesResource::devicesDiscovered, Qt::QueuedConnection);
}
HttpReply *DeviceClassesResource::proccessRequest(const HttpRequest &request, const QStringList &urlTokens)
{
// get the main resource
// /api/v1/deviceclasses/{deviceClassId}/
if (urlTokens.count() >= 4) {
DeviceClassId deviceClassId = DeviceClassId(urlTokens.at(3));
if (deviceClassId.isNull()) {
qCWarning(dcRest) << "Could not parse DeviceClassId:" << urlTokens.at(3);
return createErrorReply(HttpReply::BadRequest);
}
m_deviceClass = GuhCore::instance()->findDeviceClass(deviceClassId);
if (!m_deviceClass.isValid()) {
return createErrorReply(HttpReply::NotFound);
}
}
// check method
HttpReply *reply;
switch (request.method()) {
case HttpRequest::Get:
reply = proccessGetRequest(request, urlTokens);
break;
default:
reply = createErrorReply(HttpReply::BadRequest);
break;
}
return reply;
return createErrorReply(HttpReply::NotImplemented);
}
HttpReply *DeviceClassesResource::proccessGetRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
// GET /api/v1/deviceclasses?vendorId="{vendorId}"
if (urlTokens.count() == 3) {
VendorId vendorId;
if (request.url().hasQuery()) {
if (request.urlQuery().hasQueryItem("vendorId")) {
vendorId = VendorId(request.urlQuery().queryItemValue("vendorId"));
if (vendorId.isNull()) {
qCWarning(dcRest) << "Could not parse VendorId:" << request.urlQuery().queryItemValue("vendorId");
return createErrorReply(HttpReply::BadRequest);
}
}
}
return getDeviceClasses(vendorId);
}
// GET /api/v1/deviceclasses/{deviceClassId}
if (urlTokens.count() == 4)
return getDeviceClass();
// GET /api/v1/deviceclasses/{deviceClassId}/actiontypes
if (urlTokens.count() == 5 && urlTokens.at(4) == "actiontypes")
return getActionTypes();
// GET /api/v1/deviceclasses/{deviceClassId}/actiontypes/{actionTypeId}
if (urlTokens.count() == 6 && urlTokens.at(4) == "actiontypes") {
ActionTypeId actionTypeId = ActionTypeId(urlTokens.at(5));
if (actionTypeId.isNull()) {
qCWarning(dcRest) << "Could not parse ActionTypeId:" << urlTokens.at(5);
return createErrorReply(HttpReply::BadRequest);
}
return getActionType(actionTypeId);
}
// GET /api/v1/deviceclasses/{deviceClassId}/statetypes
if (urlTokens.count() == 5 && urlTokens.at(4) == "statetypes")
return getStateTypes();
// GET /api/v1/deviceclasses/{deviceClassId}/statetypes/{stateTypeId}
if (urlTokens.count() == 6 && urlTokens.at(4) == "statetypes") {
StateTypeId stateTypeId = StateTypeId(urlTokens.at(5));
if (stateTypeId.isNull()) {
qCWarning(dcRest) << "Could not parse StateTypeId:" << urlTokens.at(5);
return createErrorReply(HttpReply::BadRequest);
}
return getStateType(stateTypeId);
}
// GET /api/v1/deviceclasses/{deviceClassId}/eventtypes
if (urlTokens.count() == 5 && urlTokens.at(4) == "eventtypes")
return getEventTypes();
// GET /api/v1/deviceclasses/{deviceClassId}/eventtypes/{eventTypeId}
if (urlTokens.count() == 6 && urlTokens.at(4) == "eventtypes") {
EventTypeId eventTypeId = EventTypeId(urlTokens.at(5));
if (eventTypeId.isNull()) {
qCWarning(dcRest) << "Could not parse EventTypeId:" << urlTokens.at(5);
return createErrorReply(HttpReply::BadRequest);
}
return getEventType(eventTypeId);
}
// GET /api/v1/deviceclasses/{deviceClassId}/discover?name=paramName&value=paramValue
if (urlTokens.count() == 5 && urlTokens.at(4) == "discover") {
// FIXME: find a better way to get discovery params
ParamList paramList;
if (request.url().hasQuery()) {
if (request.urlQuery().hasQueryItem("name") && request.urlQuery().hasQueryItem("name")) {
paramList.append(Param(request.urlQuery().queryItemValue("name"), QVariant(request.urlQuery().queryItemValue("value"))));
} else {
qCWarning(dcRest) << "Invalid discovery params in" << request.urlQuery().query();
return createErrorReply(HttpReply::BadRequest);
}
}
return getDiscoverdDevices(paramList);
}
return createErrorReply(HttpReply::BadRequest);
}
HttpReply *DeviceClassesResource::getDeviceClass()
{
qCDebug(dcRest) << "Get device class with id " << m_deviceClass.id();
HttpReply *reply = createSuccessReply();
reply->setPayload(QJsonDocument::fromVariant(JsonTypes::packDeviceClass(m_deviceClass)).toJson());
return reply;
}
HttpReply *DeviceClassesResource::getActionTypes()
{
qCDebug(dcRest) << "Get action types for device class" << m_deviceClass.id();
HttpReply *reply = createSuccessReply();
reply->setPayload(QJsonDocument::fromVariant(JsonTypes::packActionTypes(m_deviceClass)).toJson());
return reply;
}
HttpReply *DeviceClassesResource::getActionType(const ActionTypeId &actionTypeId)
{
qCDebug(dcRest) << "Get action type with id" << actionTypeId;
foreach (const ActionType &actionType, m_deviceClass.actionTypes()) {
if (actionType.id() == actionTypeId) {
HttpReply *reply = createSuccessReply();
reply->setPayload(QJsonDocument::fromVariant(JsonTypes::packActionType(actionType)).toJson());
return reply;
}
}
return createErrorReply(HttpReply::NotFound);
}
HttpReply *DeviceClassesResource::getStateTypes()
{
qCDebug(dcRest) << "Get state types for device class" << m_deviceClass.id();
HttpReply *reply = createSuccessReply();
reply->setPayload(QJsonDocument::fromVariant(JsonTypes::packStateTypes(m_deviceClass)).toJson());
return reply;
}
HttpReply *DeviceClassesResource::getStateType(const StateTypeId &stateTypeId)
{
qCDebug(dcRest) << "Get state type with id" << stateTypeId;
foreach (const StateType &stateType, m_deviceClass.stateTypes()) {
if (stateType.id() == stateTypeId) {
HttpReply *reply = createSuccessReply();
reply->setPayload(QJsonDocument::fromVariant(JsonTypes::packStateType(stateType)).toJson());
return reply;
}
}
return createErrorReply(HttpReply::NotFound);
}
HttpReply *DeviceClassesResource::getEventTypes()
{
qCDebug(dcRest) << "Get event types for device class" << m_deviceClass.id();
HttpReply *reply = createSuccessReply();
reply->setPayload(QJsonDocument::fromVariant(JsonTypes::packEventTypes(m_deviceClass)).toJson());
return reply;
}
HttpReply *DeviceClassesResource::getEventType(const EventTypeId &eventTypeId)
{
qCDebug(dcRest) << "Get event type with id" << eventTypeId;
foreach (const EventType &eventType, m_deviceClass.eventTypes()) {
if (eventType.id() == eventTypeId) {
HttpReply *reply = createSuccessReply();
reply->setPayload(QJsonDocument::fromVariant(JsonTypes::packEventType(eventType)).toJson());
return reply;
}
}
return createErrorReply(HttpReply::NotFound);
}
HttpReply *DeviceClassesResource::getDiscoverdDevices(const ParamList &discoveryParams)
{
qCDebug(dcRest) << "Discover devices for DeviceClass" << m_deviceClass.id();
DeviceManager::DeviceError status = GuhCore::instance()->discoverDevices(m_deviceClass.id(), discoveryParams);
if (status == DeviceManager::DeviceErrorAsync) {
HttpReply *reply = createAsyncReply();
m_discoverRequests.insert(m_deviceClass.id(), reply);
return reply;
}
if (status != DeviceManager::DeviceErrorNoError)
return createErrorReply(HttpReply::InternalServerError);
return createSuccessReply();
}
void DeviceClassesResource::devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> deviceDescriptors)
{
if (!m_discoverRequests.contains(deviceClassId))
return; // Not the discovery we are waiting for.
qCDebug(dcRest) << "Discovery finished. Found" << deviceDescriptors.count() << "devices.";
HttpReply *reply = m_discoverRequests.take(deviceClassId);
reply->setPayload(QJsonDocument::fromVariant(JsonTypes::packDeviceDescriptors(deviceDescriptors)).toJson());
reply->finished();
}
HttpReply *DeviceClassesResource::getDeviceClasses(const VendorId &vendorId)
{
if (vendorId == VendorId()) {
qCDebug(dcRest) << "Get all device classes.";
} else {
qCDebug(dcRest) << "Get device classes for vendor" << vendorId.toString();
}
HttpReply *reply = createSuccessReply();
reply->setPayload(QJsonDocument::fromVariant(JsonTypes::packSupportedDevices(vendorId)).toJson());
return reply;
}
}

View File

@ -0,0 +1,74 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef DEVICECLASSESRESOURCE_H
#define DEVICECLASSESRESOURCE_H
#include <QObject>
#include <QHash>
#include "jsontypes.h"
#include "restresource.h"
#include "network/httpreply.h"
class HttpRequest;
namespace guhserver {
class DeviceClassesResource : public RestResource
{
Q_OBJECT
public:
explicit DeviceClassesResource(QObject *parent = 0);
HttpReply *proccessRequest(const HttpRequest &request, const QStringList &urlTokens) override;
private:
mutable QHash<DeviceClassId, HttpReply *> m_discoverRequests;
DeviceClass m_deviceClass;
// Process method
HttpReply *proccessGetRequest(const HttpRequest &request, const QStringList &urlTokens) override;
// Get methods
HttpReply *getDeviceClasses(const VendorId &vendorId);
HttpReply *getDeviceClass();
HttpReply *getActionTypes();
HttpReply *getActionType(const ActionTypeId &actionTypeId);
HttpReply *getStateTypes();
HttpReply *getStateType(const StateTypeId &stateTypeId);
HttpReply *getEventTypes();
HttpReply *getEventType(const EventTypeId &eventTypeId);
HttpReply *getDiscoverdDevices(const ParamList &discoveryParams);
private slots:
void devicesDiscovered(const DeviceClassId &deviceClassId, const QList<DeviceDescriptor> deviceDescriptors);
};
}
#endif // DEVICECLASSESRESOURCE_H

View File

@ -19,135 +19,342 @@
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "devicesresource.h"
#include "jsontypes.h"
#include "guhcore.h"
#include "network/httpreply.h"
#include "network/httprequest.h"
#include "jsontypes.h"
#include "guhcore.h"
#include <QJsonDocument>
namespace guhserver {
DevicesResource::DevicesResource(QObject *parent) :
QObject(parent)
RestResource(parent)
{
connect(GuhCore::instance(), &GuhCore::actionExecuted, this, &DevicesResource::actionExecuted);
connect(GuhCore::instance(), &GuhCore::deviceSetupFinished, this, &DevicesResource::deviceSetupFinished);
connect(GuhCore::instance(), &GuhCore::deviceEditFinished, this, &DevicesResource::deviceEditFinished);
}
HttpReply DevicesResource::proccessDeviceRequest(const HttpRequest &request, const QStringList &urlTokens)
HttpReply *DevicesResource::proccessRequest(const HttpRequest &request, const QStringList &urlTokens)
{
DeviceId deviceId;
StateTypeId stateTypeId;
m_device = 0;
Device *device = 0;
// first parse device, stateTypeId
// get the main resource
if (urlTokens.count() >= 4) {
deviceId = DeviceId(urlTokens.at(3));
DeviceId deviceId = DeviceId(urlTokens.at(3));
if (deviceId.isNull()) {
qCWarning(dcRest) << "Could not parse DeviceId:" << urlTokens.at(3);
return HttpReply(HttpReply::BadRequest);
return createErrorReply(HttpReply::BadRequest);
}
device = GuhCore::instance()->findConfiguredDevice(deviceId);
if (!device) {
m_device = GuhCore::instance()->findConfiguredDevice(deviceId);
if (!m_device) {
qCWarning(dcRest) << "Could find any device with DeviceId:" << urlTokens.at(3);
return HttpReply(HttpReply::NotFound);
}
// /api/v1/devices/{deviceId}/states/{stateTypeId}
if (urlTokens.count() >= 6 && urlTokens.at(4) == "states") {
stateTypeId = StateTypeId(urlTokens.at(5));
if (stateTypeId.isNull()) {
qCWarning(dcRest) << "Could not parse StateTypeId:" << urlTokens.at(5);
return HttpReply(HttpReply::BadRequest);
}
if (!device->hasState(stateTypeId)){
qCWarning(dcRest) << "This device has no StateTypeId:" << urlTokens.at(5);
return HttpReply(HttpReply::NotFound);
}
return createErrorReply(HttpReply::NotFound);
}
}
// check methods
if (request.method() == HttpRequest::Get) {
// check method
HttpReply *reply;
switch (request.method()) {
case HttpRequest::Get:
reply = proccessGetRequest(request, urlTokens);
break;
case HttpRequest::Post:
reply = proccessPostRequest(request, urlTokens);
break;
case HttpRequest::Put:
reply = proccessPutRequest(request, urlTokens);
break;
case HttpRequest::Delete:
reply = proccessDeleteRequest(request, urlTokens);
break;
default:
reply = createErrorReply(HttpReply::BadRequest);
break;
}
return reply;
}
// /api/v1/devices
if (urlTokens.count() == 3)
return getConfiguredDevices();
HttpReply *DevicesResource::proccessGetRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
// /api/v1/devices/{deviceId}
if (urlTokens.count() == 4)
return getConfiguredDevice(device);
// GET /api/v1/devices
if (urlTokens.count() == 3)
return getConfiguredDevices();
// /api/v1/devices/{deviceId}/states
if (urlTokens.count() == 5 && urlTokens.at(4) == "states")
return getDeviceStateValues(device);
// GET /api/v1/devices/{deviceId}
if (urlTokens.count() == 4)
return getConfiguredDevice(m_device);
// /api/v1/devices/{deviceId}/states/{stateTypeId}
if (urlTokens.count() == 6 && urlTokens.at(4) == "states")
return getDeviceStateValue(device, stateTypeId);
} else if (request.method() == HttpRequest::Delete) {
// GET /api/v1/devices/{deviceId}/states
if (urlTokens.count() == 5 && urlTokens.at(4) == "states")
return getDeviceStateValues(m_device);
// /api/v1/devices
if (urlTokens.count() == 3)
return HttpReply(HttpReply::BadRequest);
if (urlTokens.count() == 4)
return removeDevice(device);
// /api/v1/devices/{deviceId}/states/{stateTypeId}
if (urlTokens.count() >= 6 && urlTokens.at(4) == "states") {
StateTypeId stateTypeId = StateTypeId(urlTokens.at(5));
if (stateTypeId.isNull()) {
qCWarning(dcRest) << "Could not parse StateTypeId:" << urlTokens.at(5);
return createErrorReply(HttpReply::BadRequest);
}
if (!m_device->hasState(stateTypeId)){
qCWarning(dcRest) << "This device has no StateTypeId:" << urlTokens.at(5);
return createErrorReply(HttpReply::NotFound);
}
return getDeviceStateValue(m_device, stateTypeId);
}
return createErrorReply(HttpReply::NotImplemented);
}
HttpReply *DevicesResource::proccessDeleteRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
// DELETE /api/v1/devices
if (urlTokens.count() == 3)
return createErrorReply(HttpReply::BadRequest);
// DELETE /api/v1/devices/{deviceId}
if (urlTokens.count() == 4)
return removeDevice(m_device);
// TODO: /api/v1/devices/{deviceId}?ruleId={ruleId}&removePolicy={RemovePolicy}
return createErrorReply(HttpReply::NotImplemented);
}
HttpReply *DevicesResource::proccessPutRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
// POST /api/v1/devices
if (urlTokens.count() == 3)
return createErrorReply(HttpReply::BadRequest);
// POST /api/v1/devices/{deviceId}
if (urlTokens.count() == 4)
return editDevice(m_device, request.payload());
return createErrorReply(HttpReply::NotImplemented);
}
HttpReply *DevicesResource::proccessPostRequest(const HttpRequest &request, const QStringList &urlTokens)
{
// POST /api/v1/devices
if (urlTokens.count() == 3)
return addConfiguredDevice(request.payload());
// POST /api/v1/devices/{deviceId}
if (urlTokens.count() == 4)
return createErrorReply(HttpReply::BadRequest);
// POST /api/v1/devices/{deviceId}/execute/{actionTypeId}
if (urlTokens.count() >= 6 && urlTokens.at(4) == "execute") {
ActionTypeId actionTypeId = ActionTypeId(urlTokens.at(5));
if (actionTypeId.isNull()) {
qCWarning(dcRest) << "Could not parse ActionTypeId:" << urlTokens.at(5);
return createErrorReply(HttpReply::BadRequest);
}
return executeAction(m_device, actionTypeId, request.payload());
}
return HttpReply(HttpReply::BadRequest);
return createErrorReply(HttpReply::NotImplemented);
}
HttpReply DevicesResource::getConfiguredDevices()
HttpReply *DevicesResource::getConfiguredDevices() const
{
HttpReply httpReply(HttpReply::Ok);
httpReply.setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
httpReply.setPayload(QJsonDocument::fromVariant(JsonTypes::packConfiguredDevices()).toJson());
httpReply.packReply();
return httpReply;
qCDebug(dcRest) << "Get all configured devices";
HttpReply *reply = createSuccessReply();
reply->setPayload(QJsonDocument::fromVariant(JsonTypes::packConfiguredDevices()).toJson());
return reply;
}
HttpReply DevicesResource::getConfiguredDevice(Device *device)
HttpReply *DevicesResource::getConfiguredDevice(Device *device) const
{
HttpReply httpReply(HttpReply::Ok);
httpReply.setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
httpReply.setPayload(QJsonDocument::fromVariant(JsonTypes::packDevice(device)).toJson());
httpReply.packReply();
return httpReply;
qCDebug(dcRest) << "Get configured device with id:" << device->id().toString();
HttpReply *reply = createSuccessReply();
reply->setPayload(QJsonDocument::fromVariant(JsonTypes::packDevice(device)).toJson());
return reply;
}
HttpReply DevicesResource::getDeviceStateValues(Device *device)
HttpReply *DevicesResource::getDeviceStateValues(Device *device) const
{
HttpReply httpReply(HttpReply::Ok);
httpReply.setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
httpReply.setPayload(QJsonDocument::fromVariant(JsonTypes::packDeviceStates(device)).toJson());
httpReply.packReply();
return httpReply;
qCDebug(dcRest) << "Get states of device with id:" << device->id().toString();
HttpReply *reply = createSuccessReply();
reply->setPayload(QJsonDocument::fromVariant(JsonTypes::packDeviceStates(device)).toJson());
return reply;
}
HttpReply DevicesResource::getDeviceStateValue(Device *device, const StateTypeId &stateTypeId)
HttpReply *DevicesResource::getDeviceStateValue(Device *device, const StateTypeId &stateTypeId) const
{
HttpReply httpReply(HttpReply::Ok);
httpReply.setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
QVariantMap stateValue;
stateValue.insert("value", device->state(stateTypeId).value());
httpReply.setPayload(QJsonDocument::fromVariant(stateValue).toJson());
httpReply.packReply();
return httpReply;
qCDebug(dcRest) << "Get device state value of state with id:" << stateTypeId.toString();
HttpReply *reply = createSuccessReply();
QVariantMap stateValueMap;
stateValueMap.insert("value", device->state(stateTypeId).value());
reply->setPayload(QJsonDocument::fromVariant(stateValueMap).toJson());
return reply;
}
HttpReply DevicesResource::removeDevice(Device *device)
HttpReply *DevicesResource::removeDevice(Device *device) const
{
qCDebug(dcRest) << "Remove device with id:" << device->id().toString();
DeviceManager::DeviceError result = GuhCore::instance()->removeConfiguredDevice(device->id(), QHash<RuleId, RuleEngine::RemovePolicy>());
// TODO: parse removepolicy query params
// TODO: /api/v1/devices/{deviceId}?ruleId={ruleId}&removePolicy={RemovePolicy}
if (result == DeviceManager::DeviceErrorNoError)
return HttpReply(HttpReply::Ok);
return createSuccessReply();
return HttpReply(HttpReply::Forbidden);
return createErrorReply(HttpReply::Forbidden);
}
HttpReply *DevicesResource::executeAction(Device *device, const ActionTypeId &actionTypeId, const QByteArray &payload) const
{
qCDebug(dcRest) << "Execute action" << actionTypeId.toString();
QPair<bool, QVariant> verification = RestResource::verifyPayload(payload);
if (!verification.first)
return createErrorReply(HttpReply::BadRequest);
QVariantMap message = verification.second.toMap();
if (!message.contains("params"))
return createErrorReply(HttpReply::BadRequest);
ParamList actionParams = JsonTypes::unpackParams(message.value("params").toList());
Action action(actionTypeId, device->id());
action.setParams(actionParams);
DeviceManager::DeviceError status = GuhCore::instance()->executeAction(action);
if (status == DeviceManager::DeviceErrorAsync) {
HttpReply *reply = createAsyncReply();
m_asyncActionExecutions.insert(action.id(), reply);
return reply;
}
if (status != DeviceManager::DeviceErrorNoError)
return createErrorReply(HttpReply::InternalServerError);
return createSuccessReply();
}
HttpReply *DevicesResource::addConfiguredDevice(const QByteArray &payload) const
{
QPair<bool, QVariant> verification = RestResource::verifyPayload(payload);
if (!verification.first)
return createErrorReply(HttpReply::BadRequest);
qCDebug(dcRest) << "Add device";
QVariantMap params = verification.second.toMap();
DeviceClassId deviceClass(params.value("deviceClassId").toString());
ParamList deviceParams = JsonTypes::unpackParams(params.value("deviceParams").toList());
DeviceDescriptorId deviceDescriptorId(params.value("deviceDescriptorId").toString());
DeviceId newDeviceId = DeviceId::createDeviceId();
DeviceManager::DeviceError status;
if (deviceDescriptorId.isNull()) {
qCDebug(dcRest) << "...adding device with params" << deviceParams;
status = GuhCore::instance()->addConfiguredDevice(deviceClass, deviceParams, newDeviceId);
} else {
qCDebug(dcRest) << "...adding discovered device with descriptor id" << deviceDescriptorId;
status = GuhCore::instance()->addConfiguredDevice(deviceClass, deviceDescriptorId, newDeviceId);
}
if (status == DeviceManager::DeviceErrorAsync) {
HttpReply *reply = createAsyncReply();
m_asynDeviceAdditions.insert(newDeviceId, reply);
return reply;
}
if (status != DeviceManager::DeviceErrorNoError)
return createErrorReply(HttpReply::InternalServerError);
return createSuccessReply();
}
HttpReply *DevicesResource::editDevice(Device *device, const QByteArray &payload) const
{
qCDebug(dcRest) << "Edit device" << device->id();
QPair<bool, QVariant> verification = RestResource::verifyPayload(payload);
if (!verification.first)
return createErrorReply(HttpReply::BadRequest);
QVariantMap params = verification.second.toMap();
ParamList deviceParams = JsonTypes::unpackParams(params.value("deviceParams").toList());
qCDebug(dcRest) << "Edit device with params:" << deviceParams;
DeviceManager::DeviceError status;
DeviceDescriptorId deviceDescriptorId(params.value("deviceDescriptorId").toString());
if (deviceDescriptorId.isNull()) {
status = GuhCore::instance()->editDevice(device->id(), deviceParams);
} else {
status = GuhCore::instance()->editDevice(device->id(), deviceDescriptorId);
}
if (status == DeviceManager::DeviceErrorAsync) {
HttpReply *reply = createAsyncReply();
m_asyncEditDevice.insert(device, reply);
return reply;
}
if (status != DeviceManager::DeviceErrorNoError)
return createErrorReply(HttpReply::InternalServerError);
return createSuccessReply();
}
void DevicesResource::actionExecuted(const ActionId &actionId, DeviceManager::DeviceError status)
{
if (!m_asyncActionExecutions.contains(actionId))
return; // Not the action we are waiting for.
HttpReply *reply = m_asyncActionExecutions.take(actionId);
if (status == DeviceManager::DeviceErrorNoError) {
reply->setHttpStatusCode(HttpReply::Ok);
} else {
reply->setHttpStatusCode(HttpReply::BadRequest);
}
reply->finished();
}
void DevicesResource::deviceSetupFinished(Device *device, DeviceManager::DeviceError status)
{
if (!m_asyncEditDevice.contains(device))
return; // Not the device we are waiting for.
HttpReply *reply = m_asyncEditDevice.take(device);
if (status == DeviceManager::DeviceErrorNoError) {
reply->setHttpStatusCode(HttpReply::Ok);
} else {
reply->setHttpStatusCode(HttpReply::BadRequest);
}
QVariantMap result;
result.insert("deviceId", device->id());
reply->setPayload(QJsonDocument::fromVariant(result).toJson());
reply->finished();
}
void DevicesResource::deviceEditFinished(Device *device, DeviceManager::DeviceError status)
{
if (!m_asynDeviceAdditions.contains(device->id()))
return; // Not the device we are waiting for.
HttpReply *reply = m_asyncEditDevice.take(device);
if (status == DeviceManager::DeviceErrorNoError) {
reply->setHttpStatusCode(HttpReply::Ok);
} else {
reply->setHttpStatusCode(HttpReply::BadRequest);
}
reply->finished();
}
}

View File

@ -22,32 +22,58 @@
#define DEVICESRESOURCE_H
#include <QObject>
#include "jsontypes.h"
#include <QHash>
#include "jsontypes.h"
#include "restresource.h"
#include "network/httpreply.h"
class HttpReply;
class HttpRequest;
namespace guhserver {
class DevicesResource : public QObject
class DevicesResource: public RestResource
{
Q_OBJECT
public:
explicit DevicesResource(QObject *parent = 0);
HttpReply proccessDeviceRequest(const HttpRequest &request, const QStringList &urlTokens);
HttpReply *proccessRequest(const HttpRequest &request, const QStringList &urlTokens) override;
private:
HttpReply getConfiguredDevices();
HttpReply getConfiguredDevice(Device *device);
HttpReply getDeviceStateValues(Device *device);
HttpReply getDeviceStateValue(Device *device, const StateTypeId &stateTypeId);
mutable QHash<ActionId, HttpReply *> m_asyncActionExecutions;
mutable QHash<DeviceId, HttpReply *> m_asynDeviceAdditions;
mutable QHash<Device *, HttpReply *> m_asyncEditDevice;
mutable QHash<QUuid, HttpReply *> m_asyncPairingRequests;
HttpReply removeDevice(Device *device);
Device *m_device;
signals:
// Process method
HttpReply *proccessGetRequest(const HttpRequest &request, const QStringList &urlTokens) override;
HttpReply *proccessDeleteRequest(const HttpRequest &request, const QStringList &urlTokens) override;
HttpReply *proccessPutRequest(const HttpRequest &request, const QStringList &urlTokens) override;
HttpReply *proccessPostRequest(const HttpRequest &request, const QStringList &urlTokens) override;
public slots:
// Get methods
HttpReply *getConfiguredDevices() const;
HttpReply *getConfiguredDevice(Device *device) const;
HttpReply *getDeviceStateValues(Device *device) const;
HttpReply *getDeviceStateValue(Device *device, const StateTypeId &stateTypeId) const;
// Delete methods
HttpReply *removeDevice(Device *device) const;
// Post methods
HttpReply *executeAction(Device *device, const ActionTypeId &actionTypeId, const QByteArray &payload) const;
HttpReply *addConfiguredDevice(const QByteArray &payload) const;
// Put methods
HttpReply *editDevice(Device *device, const QByteArray &payload) const;
private slots:
void actionExecuted(const ActionId &actionId, DeviceManager::DeviceError status);
void deviceSetupFinished(Device *device, DeviceManager::DeviceError status);
void deviceEditFinished(Device *device, DeviceManager::DeviceError status);
};

View File

@ -0,0 +1,71 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "logsresource.h"
#include "network/httprequest.h"
namespace guhserver {
LogsResource::LogsResource(QObject *parent) :
RestResource(parent)
{
}
HttpReply *LogsResource::proccessRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
Q_UNUSED(urlTokens)
return createErrorReply(HttpReply::NotImplemented);
}
HttpReply *LogsResource::proccessGetRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
Q_UNUSED(urlTokens)
return createErrorReply(HttpReply::NotImplemented);}
HttpReply *LogsResource::proccessDeleteRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
Q_UNUSED(urlTokens)
return createErrorReply(HttpReply::NotImplemented);
}
HttpReply *LogsResource::proccessPutRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
Q_UNUSED(urlTokens)
return createErrorReply(HttpReply::NotImplemented);
}
HttpReply *LogsResource::proccessPostRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
Q_UNUSED(urlTokens)
return createErrorReply(HttpReply::NotImplemented);
}
}

View File

@ -0,0 +1,62 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef LOGSRESOURCE_H
#define LOGSRESOURCE_H
#include <QObject>
#include <QHash>
#include "jsontypes.h"
#include "restresource.h"
#include "network/httpreply.h"
class HttpRequest;
namespace guhserver {
class LogsResource : public RestResource
{
Q_OBJECT
public:
explicit LogsResource(QObject *parent = 0);
HttpReply *proccessRequest(const HttpRequest &request, const QStringList &urlTokens) override;
private:
// Process method
HttpReply *proccessGetRequest(const HttpRequest &request, const QStringList &urlTokens) override;
HttpReply *proccessDeleteRequest(const HttpRequest &request, const QStringList &urlTokens) override;
HttpReply *proccessPutRequest(const HttpRequest &request, const QStringList &urlTokens) override;
HttpReply *proccessPostRequest(const HttpRequest &request, const QStringList &urlTokens) override;
// Get methods
// Delete methods
// Post methods
// Put methods
};
}
#endif // LOGSRESOURCE_H

View File

@ -0,0 +1,72 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "pluginsresource.h"
#include "network/httprequest.h"
namespace guhserver {
PluginsResource::PluginsResource(QObject *parent) :
RestResource(parent)
{
}
HttpReply *PluginsResource::proccessRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
Q_UNUSED(urlTokens)
return createErrorReply(HttpReply::NotImplemented);
}
HttpReply *PluginsResource::proccessGetRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
Q_UNUSED(urlTokens)
return createErrorReply(HttpReply::NotImplemented);
}
HttpReply *PluginsResource::proccessDeleteRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
Q_UNUSED(urlTokens)
return createErrorReply(HttpReply::NotImplemented);
}
HttpReply *PluginsResource::proccessPutRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
Q_UNUSED(urlTokens)
return createErrorReply(HttpReply::NotImplemented);
}
HttpReply *PluginsResource::proccessPostRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
Q_UNUSED(urlTokens)
return createErrorReply(HttpReply::NotImplemented);
}
}

View File

@ -0,0 +1,62 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef PLUGINSRESOURCE_H
#define PLUGINSRESOURCE_H
#include <QObject>
#include <QHash>
#include "jsontypes.h"
#include "restresource.h"
#include "network/httpreply.h"
class HttpRequest;
namespace guhserver {
class PluginsResource : public RestResource
{
Q_OBJECT
public:
explicit PluginsResource(QObject *parent = 0);
HttpReply *proccessRequest(const HttpRequest &request, const QStringList &urlTokens) override;
private:
// Process method
HttpReply *proccessGetRequest(const HttpRequest &request, const QStringList &urlTokens) override;
HttpReply *proccessDeleteRequest(const HttpRequest &request, const QStringList &urlTokens) override;
HttpReply *proccessPutRequest(const HttpRequest &request, const QStringList &urlTokens) override;
HttpReply *proccessPostRequest(const HttpRequest &request, const QStringList &urlTokens) override;
// Get methods
// Delete methods
// Post methods
// Put methods
};
}
#endif // PLUGINSRESOURCE_H

View File

@ -0,0 +1,108 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "restresource.h"
#include "network/httprequest.h"
#include "loggingcategories.h"
#include "guhcore.h"
#include <QJsonDocument>
#include <QVariant>
namespace guhserver {
RestResource::RestResource(QObject *parent) :
QObject(parent)
{
}
RestResource::~RestResource()
{
}
HttpReply *RestResource::createSuccessReply()
{
HttpReply *reply = new HttpReply(HttpReply::Ok, HttpReply::TypeSync);
reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
return reply;
}
HttpReply *RestResource::createErrorReply(const HttpReply::HttpStatusCode &statusCode)
{
HttpReply *reply = new HttpReply(statusCode, HttpReply::TypeSync);
return reply;
}
HttpReply *RestResource::createAsyncReply()
{
HttpReply *reply = new HttpReply(HttpReply::Ok, HttpReply::TypeAsync);
return reply;
}
QPair<bool, QVariant> RestResource::verifyPayload(const QByteArray &payload)
{
QVariant data;
if (!payload.isEmpty()) {
QJsonParseError error;
QJsonDocument jsonDoc = QJsonDocument::fromJson(payload, &error);
if(error.error != QJsonParseError::NoError) {
qCWarning(dcRest) << "Failed to parse JSON payload" << payload << ":" << error.errorString();
return QPair<bool, QVariant>(true, QVariant());
}
data = jsonDoc.toVariant();
}
return QPair<bool, QVariant>(true, data);
}
HttpReply *RestResource::proccessPostRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
Q_UNUSED(urlTokens)
return createErrorReply(HttpReply::NotImplemented);
}
HttpReply *RestResource::proccessPutRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
Q_UNUSED(urlTokens)
return createErrorReply(HttpReply::NotImplemented);
}
HttpReply *RestResource::proccessDeleteRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
Q_UNUSED(urlTokens)
return createErrorReply(HttpReply::NotImplemented);
}
HttpReply *RestResource::proccessGetRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
Q_UNUSED(urlTokens)
return createErrorReply(HttpReply::NotImplemented);
}
}

View File

@ -0,0 +1,59 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef RESTRESOURCE_H
#define RESTRESOURCE_H
#include <QObject>
#include <QPair>
#include "network/httpreply.h"
class HttpRequest;
class HttpReply;
class QVariant;
namespace guhserver {
class RestResource : public QObject
{
Q_OBJECT
public:
explicit RestResource(QObject *parent = 0);
virtual ~RestResource() = 0;
virtual HttpReply *proccessRequest(const HttpRequest &request, const QStringList &urlTokens) = 0;
static HttpReply *createSuccessReply();
static HttpReply *createErrorReply(const HttpReply::HttpStatusCode &statusCode);
static HttpReply *createAsyncReply();
static QPair<bool, QVariant> verifyPayload(const QByteArray &payload);
private:
virtual HttpReply *proccessGetRequest(const HttpRequest &request, const QStringList &urlTokens);
virtual HttpReply *proccessDeleteRequest(const HttpRequest &request, const QStringList &urlTokens);
virtual HttpReply *proccessPutRequest(const HttpRequest &request, const QStringList &urlTokens);
virtual HttpReply *proccessPostRequest(const HttpRequest &request, const QStringList &urlTokens);
};
}
#endif // RESTRESOURCE_H

View File

@ -36,11 +36,16 @@ RestServer::RestServer(QObject *parent) :
connect(m_webserver, &WebServer::clientDisconnected, this, &RestServer::clientDisconnected);
connect(m_webserver, &WebServer::httpRequestReady, this, &RestServer::processHttpRequest);
// Resources
m_deviceResource = new DevicesResource(this);
m_webserver->startServer();
QMetaObject::invokeMethod(this, "setup", Qt::QueuedConnection);
}
void RestServer::setup()
{
// Create resources
m_deviceResource = new DevicesResource(this);
m_deviceClassesResource = new DeviceClassesResource(this);
}
void RestServer::clientConnected(const QUuid &clientId)
@ -55,108 +60,65 @@ void RestServer::clientDisconnected(const QUuid &clientId)
void RestServer::processHttpRequest(const QUuid &clientId, const HttpRequest &request)
{
qCDebug(dcRest) << "Process HTTP request" << clientId << request.method() << request.urlQuery().query();
qCDebug(dcRest) << "Process HTTP request";
qCDebug(dcRest) << request;
QStringList urlTokens = request.urlQuery().query(QUrl::FullyDecoded).split("/");
QStringList urlTokens = request.url().path().split("/");
urlTokens.removeAll(QString());
qCDebug(dcRest) << urlTokens;
if (urlTokens.count() < 3) {
m_webserver->sendHttpReply(clientId, HttpReply(HttpReply::BadRequest));
HttpReply *reply = new HttpReply(HttpReply::BadRequest, HttpReply::TypeSync, this);
reply->setClientId(clientId);
m_webserver->sendHttpReply(reply);
reply->deleteLater();
return;
}
if (urlTokens.at(2) == "devices") {
HttpReply httpReply = m_deviceResource->proccessDeviceRequest(request, urlTokens);
qCDebug(dcRest) << "sending header" << httpReply.rawHeader();
m_webserver->sendHttpReply(clientId, httpReply);
HttpReply *reply = m_deviceResource->proccessRequest(request, urlTokens);
reply->setClientId(clientId);
if (reply->type() == HttpReply::TypeAsync) {
connect(reply, &HttpReply::finished, this, &RestServer::asyncReplyFinished);
reply->startWait();
m_asyncReplies.insert(clientId, reply);
return;
}
m_webserver->sendHttpReply(reply);
reply->deleteLater();
return;
}
// QString targetNamespace;
// QString method;
// QVariantMap params;
// // check filter
// QVariantList deviceList;
// if (!request.urlQuery().hasQueryItem("id")) {
// HttpReply httpReply = m_deviceResource->proccessDeviceRequest(request);
// m_webserver->sendHttpReply(clientId, httpReply);
// return;
// } else {
// foreach (const QString& idString, request.urlQuery().allQueryItemValues("id")) {
// Device *device = GuhCore::instance()->deviceManager()->findConfiguredDevice(DeviceId(idString));
// if (device == Device()) {
// }
// }
// }
// }
// if (request.method() == HttpRequest::Get && request.urlQuery().query() == "/api/v1/devices.json") {
// targetNamespace = "Devices";
// method = "GetConfiguredDevices";
// } else if (request.method() == HttpRequest::Get && request.urlQuery().query() == "/api/v1/devices.json") {
// targetNamespace = "Devices";
// method = "GetConfiguredDevices";
// } else {
// HttpReply httpReply(HttpReply::BadRequest);
// httpReply.setPayload("400 Bad Request.");
// httpReply.packReply();
// m_webserver->sendHttpReply(clientId, httpReply);
// return;
// }
// JsonHandler *handler = GuhCore::instance()->jsonRPCServer()->handlers().value(targetNamespace);
// QPair<bool, QString> validationResult = handler->validateParams(method, params);
// if (!validationResult.first) {
// qCWarning(dcWebServer) << "Invalid params: " << validationResult.second;
// return;
// }
// JsonReply *jsonReply;
// QMetaObject::invokeMethod(handler, method.toLatin1().data(), Q_RETURN_ARG(JsonReply*, jsonReply), Q_ARG(QVariantMap, params));
// if (jsonReply->type() == JsonReply::TypeAsync) {
// jsonReply->setClientId(clientId);
// connect(jsonReply, &JsonReply::finished, this, &RestServer::asyncReplyFinished);
// jsonReply->startWait();
// m_asyncReplies.insert(clientId, jsonReply);
// return;
// }
// HttpReply httpReply(HttpReply::Ok);
// httpReply.setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
// httpReply.setPayload(QJsonDocument::fromVariant(jsonReply->data()).toJson());
// httpReply.packReply();
// m_webserver->sendHttpReply(clientId, httpReply);
// jsonReply->deleteLater();
if (urlTokens.at(2) == "deviceclasses") {
HttpReply *reply = m_deviceClassesResource->proccessRequest(request, urlTokens);
reply->setClientId(clientId);
if (reply->type() == HttpReply::TypeAsync) {
connect(reply, &HttpReply::finished, this, &RestServer::asyncReplyFinished);
reply->startWait();
m_asyncReplies.insert(clientId, reply);
return;
}
m_webserver->sendHttpReply(reply);
reply->deleteLater();
return;
}
}
void RestServer::asyncReplyFinished()
{
JsonReply *jsonReply = qobject_cast<JsonReply*>(sender());
QUuid clientId = m_asyncReplies.key(jsonReply);
HttpReply *reply = qobject_cast<HttpReply*>(sender());
if (!jsonReply->timedOut()) {
HttpReply httpReply(HttpReply::Ok);
httpReply.setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
httpReply.setPayload(QJsonDocument::fromVariant(jsonReply->data()).toJson());
httpReply.packReply();
m_webserver->sendHttpReply(clientId, httpReply);
qCDebug(dcWebServer) << "sending reply" << reply->data();
if (!reply->timedOut()) {
reply->setHttpStatusCode(HttpReply::Ok);
} else {
HttpReply httpReply(HttpReply::GatewayTimeout);
httpReply.setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
httpReply.setPayload(QJsonDocument::fromVariant(jsonReply->data()).toJson());
httpReply.packReply();
m_webserver->sendHttpReply(clientId, httpReply);
reply->setHttpStatusCode(HttpReply::GatewayTimeout);
}
jsonReply->deleteLater();
m_webserver->sendHttpReply(reply);
reply->deleteLater();
}

View File

@ -26,6 +26,7 @@
#include "webserver.h"
#include "jsonhandler.h"
#include "devicesresource.h"
#include "deviceclassesresource.h"
class HttpRequest;
class HttpReply;
@ -38,17 +39,17 @@ class RestServer : public QObject
public:
explicit RestServer(QObject *parent = 0);
private:
WebServer *m_webserver;
QList<QUuid> m_clientList;
QHash<QUuid, JsonReply *> m_asyncReplies;
QHash<QUuid, HttpReply *> m_asyncReplies;
DevicesResource *m_deviceResource;
signals:
void httpReplyReady(const HttpReply &httpReply);
DeviceClassesResource *m_deviceClassesResource;
private slots:
void setup();
void clientConnected(const QUuid &clientId);
void clientDisconnected(const QUuid &clientId);

View File

@ -0,0 +1,70 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "rulesresource.h"
namespace guhserver {
RulesResource::RulesResource(QObject *parent) :
RestResource(parent)
{
}
HttpReply *RulesResource::proccessRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
Q_UNUSED(urlTokens)
return createErrorReply(HttpReply::NotImplemented);
}
HttpReply *RulesResource::proccessGetRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
Q_UNUSED(urlTokens)
return createErrorReply(HttpReply::NotImplemented);}
HttpReply *RulesResource::proccessDeleteRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
Q_UNUSED(urlTokens)
return createErrorReply(HttpReply::NotImplemented);
}
HttpReply *RulesResource::proccessPutRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
Q_UNUSED(urlTokens)
return createErrorReply(HttpReply::NotImplemented);
}
HttpReply *RulesResource::proccessPostRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
Q_UNUSED(urlTokens)
return createErrorReply(HttpReply::NotImplemented);
}
}

View File

@ -0,0 +1,62 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef RULESRESOURCE_H
#define RULESRESOURCE_H
#include <QObject>
#include <QHash>
#include "jsontypes.h"
#include "restresource.h"
#include "network/httpreply.h"
class HttpRequest;
namespace guhserver {
class RulesResource : public RestResource
{
Q_OBJECT
public:
explicit RulesResource(QObject *parent = 0);
HttpReply *proccessRequest(const HttpRequest &request, const QStringList &urlTokens) override;
private:
// Process method
HttpReply *proccessGetRequest(const HttpRequest &request, const QStringList &urlTokens) override;
HttpReply *proccessDeleteRequest(const HttpRequest &request, const QStringList &urlTokens) override;
HttpReply *proccessPutRequest(const HttpRequest &request, const QStringList &urlTokens) override;
HttpReply *proccessPostRequest(const HttpRequest &request, const QStringList &urlTokens) override;
// Get methods
// Delete methods
// Post methods
// Put methods
};
}
#endif // RULESRESOURCE_H

View File

@ -0,0 +1,72 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "vendorsresource.h"
#include "network/httprequest.h"
namespace guhserver {
VendorsResource::VendorsResource(QObject *parent) :
RestResource(parent)
{
}
HttpReply *VendorsResource::proccessRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
Q_UNUSED(urlTokens)
return createErrorReply(HttpReply::NotImplemented);
}
HttpReply *VendorsResource::proccessGetRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
Q_UNUSED(urlTokens)
return createErrorReply(HttpReply::NotImplemented);
}
HttpReply *VendorsResource::proccessDeleteRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
Q_UNUSED(urlTokens)
return createErrorReply(HttpReply::NotImplemented);
}
HttpReply *VendorsResource::proccessPutRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
Q_UNUSED(urlTokens)
return createErrorReply(HttpReply::NotImplemented);
}
HttpReply *VendorsResource::proccessPostRequest(const HttpRequest &request, const QStringList &urlTokens)
{
Q_UNUSED(request)
Q_UNUSED(urlTokens)
return createErrorReply(HttpReply::NotImplemented);
}
}

View File

@ -0,0 +1,62 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stuerz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. If not, see <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef VENDORSRESOURCE_H
#define VENDORSRESOURCE_H
#include <QObject>
#include <QHash>
#include "jsontypes.h"
#include "restresource.h"
#include "network/httpreply.h"
class HttpRequest;
namespace guhserver {
class VendorsResource : public RestResource
{
Q_OBJECT
public:
explicit VendorsResource(QObject *parent = 0);
HttpReply *proccessRequest(const HttpRequest &request, const QStringList &urlTokens) override;
private:
// Process method
HttpReply *proccessGetRequest(const HttpRequest &request, const QStringList &urlTokens) override;
HttpReply *proccessDeleteRequest(const HttpRequest &request, const QStringList &urlTokens) override;
HttpReply *proccessPutRequest(const HttpRequest &request, const QStringList &urlTokens) override;
HttpReply *proccessPostRequest(const HttpRequest &request, const QStringList &urlTokens) override;
// Get methods
// Delete methods
// Post methods
// Put methods
};
}
#endif // VENDORSRESOURCE_H

View File

@ -26,7 +26,13 @@ SOURCES += $$top_srcdir/server/guhcore.cpp \
$$top_srcdir/server/servermanager.cpp \
$$top_srcdir/server/websocketserver.cpp \
$$top_srcdir/server/rest/restserver.cpp \
$$top_srcdir/server/rest/restresource.cpp \
$$top_srcdir/server/rest/devicesresource.cpp \
$$top_srcdir/server/rest/deviceclassesresource.cpp \
$$top_srcdir/server/rest/vendorsresource.cpp \
$$top_srcdir/server/rest/logsresource.cpp \
$$top_srcdir/server/rest/pluginsresource.cpp \
$$top_srcdir/server/rest/rulesresource.cpp \
HEADERS += $$top_srcdir/server/guhcore.h \
@ -52,6 +58,12 @@ HEADERS += $$top_srcdir/server/guhcore.h \
$$top_srcdir/server/servermanager.h \
$$top_srcdir/server/websocketserver.h \
$$top_srcdir/server/rest/restserver.h \
$$top_srcdir/server/rest/restresource.h \
$$top_srcdir/server/rest/devicesresource.h \
$$top_srcdir/server/rest/deviceclassesresource.h \
$$top_srcdir/server/rest/vendorsresource.h \
$$top_srcdir/server/rest/logsresource.h \
$$top_srcdir/server/rest/pluginsresource.h \
$$top_srcdir/server/rest/rulesresource.h \

View File

@ -28,7 +28,7 @@ ServerManager::ServerManager(QObject *parent) :
qCDebug(dcApplication) << "Starting JSON RPC Server";
m_jsonServer = new JsonRPCServer(this);
qCDebug(dcApplication) << "Starting REST Webserver";
qCDebug(dcApplication) << "Starting REST Server";
m_restServer = new RestServer(this);
}

View File

@ -84,10 +84,16 @@ void WebServer::sendData(const QList<QUuid> &clients, const QVariantMap &data)
}
}
void WebServer::sendHttpReply(const QUuid &clientId, const HttpReply &reply)
void WebServer::sendHttpReply(HttpReply *reply)
{
QTcpSocket *socket = m_clientList.value(clientId);
writeData(socket, reply.data());
QTcpSocket *socket = 0;
socket = m_clientList.value(reply->clientId());
if (!socket) {
qCDebug(dcWebServer) << "Invalid socket pointer! This should never happen!!!";
return;
}
writeData(socket, reply->data());
}
bool WebServer::verifyFile(QTcpSocket *socket, const QString &fileName)
@ -202,7 +208,6 @@ void WebServer::readClient()
}
qCDebug(dcWebServer) << QString("Got valid request from %1:%2").arg(socket->peerAddress().toString()).arg(socket->peerPort());
qCDebug(dcWebServer) << request;
// verify method
if (request.method() == HttpRequest::Unhandled) {
@ -215,7 +220,7 @@ void WebServer::readClient()
}
// verify query
if (request.urlQuery().query().startsWith("/api/v1")) {
if (request.url().path().startsWith("/api/v1")) {
emit httpRequestReady(clientId, request);
return;
}

View File

@ -50,7 +50,7 @@ public:
void sendData(const QUuid &clientId, const QVariantMap &data) override;
void sendData(const QList<QUuid> &clients, const QVariantMap &data) override;
void sendHttpReply(const QUuid &clientId, const HttpReply &reply);
void sendHttpReply(HttpReply *reply);
private:
QTcpServer *m_server;

View File

@ -23,8 +23,9 @@
namespace guhserver {
WebSocketServer::WebSocketServer(QObject *parent) :
QObject(parent)
TransportInterface(parent)
{
}
}

View File

@ -23,12 +23,14 @@
#include <QObject>
#include "transportinterface.h"
// Note: WebSocket Protocol from the Internet Engineering Task Force (IETF) -> RFC6455 V13:
// http://tools.ietf.org/html/rfc6455
namespace guhserver {
class WebSocketServer : public QObject
class WebSocketServer : public TransportInterface
{
Q_OBJECT
public: