diff --git a/libguh/network/httpreply.cpp b/libguh/network/httpreply.cpp index 32d00c93..bf486b7a 100644 --- a/libguh/network/httpreply.cpp +++ b/libguh/network/httpreply.cpp @@ -97,16 +97,41 @@ ... */ +/*! \enum HttpReply::Type + +*/ + #include "httpreply.h" #include #include /*! 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(); +} diff --git a/libguh/network/httpreply.h b/libguh/network/httpreply.h index 3f66746a..a6268f15 100644 --- a/libguh/network/httpreply.h +++ b/libguh/network/httpreply.h @@ -21,13 +21,17 @@ #ifndef HTTPREPLY_H #define HTTPREPLY_H +#include #include #include +#include +#include // 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 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 diff --git a/libguh/network/httprequest.cpp b/libguh/network/httprequest.cpp index cba273bc..137f2e34 100644 --- a/libguh/network/httprequest.cpp +++ b/libguh/network/httprequest.cpp @@ -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"; diff --git a/libguh/network/httprequest.h b/libguh/network/httprequest.h index ce0eda28..3cb6f558 100644 --- a/libguh/network/httprequest.h +++ b/libguh/network/httprequest.h @@ -43,7 +43,10 @@ public: QHash 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 m_rawHeaderList; RequestMethod m_method; + QString m_methodString; QByteArray m_httpVersion; + + QUrl m_url; QUrlQuery m_urlQuery; QByteArray m_payload; diff --git a/server/jsonrpc/devicehandler.cpp b/server/jsonrpc/devicehandler.cpp index b6b4d007..579cbed2 100644 --- a/server/jsonrpc/devicehandler.cpp +++ b/server/jsonrpc/devicehandler.cpp @@ -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); diff --git a/server/jsonrpc/jsontypes.cpp b/server/jsonrpc/jsontypes.cpp index 9d795ae5..cb14b111 100644 --- a/server/jsonrpc/jsontypes.cpp +++ b/server/jsonrpc/jsontypes.cpp @@ -713,6 +713,42 @@ QVariantList JsonTypes::packDeviceStates(Device *device) return stateValues; } +QVariantList JsonTypes::packDeviceDescriptors(const QList 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; diff --git a/server/jsonrpc/jsontypes.h b/server/jsonrpc/jsontypes.h index a7e247eb..0968c1e6 100644 --- a/server/jsonrpc/jsontypes.h +++ b/server/jsonrpc/jsontypes.h @@ -165,6 +165,13 @@ public: static QVariantList packSupportedDevices(const VendorId &vendorId); static QVariantList packConfiguredDevices(); static QVariantList packDeviceStates(Device *device); + static QVariantList packDeviceDescriptors(const QList deviceDescriptors); + + + static QVariantList packActionTypes(const DeviceClass &deviceClass); + static QVariantList packStateTypes(const DeviceClass &deviceClass); + static QVariantList packEventTypes(const DeviceClass &deviceClass); + static QVariantList packPlugins(); diff --git a/server/rest/deviceclassesresource.cpp b/server/rest/deviceclassesresource.cpp new file mode 100644 index 00000000..aff05a54 --- /dev/null +++ b/server/rest/deviceclassesresource.cpp @@ -0,0 +1,269 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stuerz * + * * + * 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 . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "deviceclassesresource.h" +#include "network/httprequest.h" +#include "guhcore.h" + +#include + +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 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; +} + +} diff --git a/server/rest/deviceclassesresource.h b/server/rest/deviceclassesresource.h new file mode 100644 index 00000000..b71c1196 --- /dev/null +++ b/server/rest/deviceclassesresource.h @@ -0,0 +1,74 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stuerz * + * * + * 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 . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef DEVICECLASSESRESOURCE_H +#define DEVICECLASSESRESOURCE_H + +#include +#include + +#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 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 deviceDescriptors); + + +}; + +} + +#endif // DEVICECLASSESRESOURCE_H diff --git a/server/rest/devicesresource.cpp b/server/rest/devicesresource.cpp index e79ff658..0945c662 100644 --- a/server/rest/devicesresource.cpp +++ b/server/rest/devicesresource.cpp @@ -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 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()); - // 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 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 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 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(); } } diff --git a/server/rest/devicesresource.h b/server/rest/devicesresource.h index e3dcbe3f..0ab9c235 100644 --- a/server/rest/devicesresource.h +++ b/server/rest/devicesresource.h @@ -22,32 +22,58 @@ #define DEVICESRESOURCE_H #include -#include "jsontypes.h" +#include + +#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 m_asyncActionExecutions; + mutable QHash m_asynDeviceAdditions; + mutable QHash m_asyncEditDevice; + mutable QHash 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); }; diff --git a/server/rest/logsresource.cpp b/server/rest/logsresource.cpp new file mode 100644 index 00000000..ba382f84 --- /dev/null +++ b/server/rest/logsresource.cpp @@ -0,0 +1,71 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stuerz * + * * + * 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 . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#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); +} + +} + diff --git a/server/rest/logsresource.h b/server/rest/logsresource.h new file mode 100644 index 00000000..469178e2 --- /dev/null +++ b/server/rest/logsresource.h @@ -0,0 +1,62 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stuerz * + * * + * 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 . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef LOGSRESOURCE_H +#define LOGSRESOURCE_H + +#include +#include + +#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 diff --git a/server/rest/pluginsresource.cpp b/server/rest/pluginsresource.cpp new file mode 100644 index 00000000..e63091f0 --- /dev/null +++ b/server/rest/pluginsresource.cpp @@ -0,0 +1,72 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stuerz * + * * + * 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 . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#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); +} + +} + diff --git a/server/rest/pluginsresource.h b/server/rest/pluginsresource.h new file mode 100644 index 00000000..d9c83414 --- /dev/null +++ b/server/rest/pluginsresource.h @@ -0,0 +1,62 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stuerz * + * * + * 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 . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef PLUGINSRESOURCE_H +#define PLUGINSRESOURCE_H + +#include +#include + +#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 diff --git a/server/rest/restresource.cpp b/server/rest/restresource.cpp new file mode 100644 index 00000000..85440401 --- /dev/null +++ b/server/rest/restresource.cpp @@ -0,0 +1,108 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stuerz * + * * + * 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 . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "restresource.h" +#include "network/httprequest.h" +#include "loggingcategories.h" +#include "guhcore.h" + +#include +#include + +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 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(true, QVariant()); + } + + data = jsonDoc.toVariant(); + } + return QPair(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); +} + +} diff --git a/server/rest/restresource.h b/server/rest/restresource.h new file mode 100644 index 00000000..9e701e73 --- /dev/null +++ b/server/rest/restresource.h @@ -0,0 +1,59 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stuerz * + * * + * 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 . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef RESTRESOURCE_H +#define RESTRESOURCE_H + +#include +#include + +#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 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 diff --git a/server/rest/restserver.cpp b/server/rest/restserver.cpp index 79a4eb5d..8541338c 100644 --- a/server/rest/restserver.cpp +++ b/server/rest/restserver.cpp @@ -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 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(sender()); - QUuid clientId = m_asyncReplies.key(jsonReply); + HttpReply *reply = qobject_cast(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(); } diff --git a/server/rest/restserver.h b/server/rest/restserver.h index f49e59ba..cf20d3f2 100644 --- a/server/rest/restserver.h +++ b/server/rest/restserver.h @@ -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 m_clientList; - QHash m_asyncReplies; + QHash 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); diff --git a/server/rest/rulesresource.cpp b/server/rest/rulesresource.cpp new file mode 100644 index 00000000..a4adce54 --- /dev/null +++ b/server/rest/rulesresource.cpp @@ -0,0 +1,70 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stuerz * + * * + * 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 . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#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); +} + +} + diff --git a/server/rest/rulesresource.h b/server/rest/rulesresource.h new file mode 100644 index 00000000..1c7fd8cb --- /dev/null +++ b/server/rest/rulesresource.h @@ -0,0 +1,62 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stuerz * + * * + * 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 . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef RULESRESOURCE_H +#define RULESRESOURCE_H + +#include +#include + +#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 diff --git a/server/rest/vendorsresource.cpp b/server/rest/vendorsresource.cpp new file mode 100644 index 00000000..ff02f978 --- /dev/null +++ b/server/rest/vendorsresource.cpp @@ -0,0 +1,72 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stuerz * + * * + * 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 . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#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); +} + +} + diff --git a/server/rest/vendorsresource.h b/server/rest/vendorsresource.h new file mode 100644 index 00000000..6d7994e6 --- /dev/null +++ b/server/rest/vendorsresource.h @@ -0,0 +1,62 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2015 Simon Stuerz * + * * + * 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 . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef VENDORSRESOURCE_H +#define VENDORSRESOURCE_H + +#include +#include + +#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 diff --git a/server/server.pri b/server/server.pri index 9e19d953..312f8089 100644 --- a/server/server.pri +++ b/server/server.pri @@ -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 \ diff --git a/server/servermanager.cpp b/server/servermanager.cpp index 41388942..f44b25a6 100644 --- a/server/servermanager.cpp +++ b/server/servermanager.cpp @@ -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); } diff --git a/server/webserver.cpp b/server/webserver.cpp index 88722933..97f5f589 100644 --- a/server/webserver.cpp +++ b/server/webserver.cpp @@ -84,10 +84,16 @@ void WebServer::sendData(const QList &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; } diff --git a/server/webserver.h b/server/webserver.h index 9e3d68cd..7b04d080 100644 --- a/server/webserver.h +++ b/server/webserver.h @@ -50,7 +50,7 @@ public: void sendData(const QUuid &clientId, const QVariantMap &data) override; void sendData(const QList &clients, const QVariantMap &data) override; - void sendHttpReply(const QUuid &clientId, const HttpReply &reply); + void sendHttpReply(HttpReply *reply); private: QTcpServer *m_server; diff --git a/server/websocketserver.cpp b/server/websocketserver.cpp index 05ba7e27..4af45f87 100644 --- a/server/websocketserver.cpp +++ b/server/websocketserver.cpp @@ -23,8 +23,9 @@ namespace guhserver { WebSocketServer::WebSocketServer(QObject *parent) : - QObject(parent) + TransportInterface(parent) { + } } diff --git a/server/websocketserver.h b/server/websocketserver.h index 3044f261..829ecc83 100644 --- a/server/websocketserver.h +++ b/server/websocketserver.h @@ -23,12 +23,14 @@ #include +#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: