added deviceresources and first tests
This commit is contained in:
parent
5a3c7a6cfb
commit
b86a062a87
@ -28,5 +28,6 @@ Q_LOGGING_CATEGORY(dcConnection, "Connection")
|
|||||||
Q_LOGGING_CATEGORY(dcTcpServer, "TcpServer")
|
Q_LOGGING_CATEGORY(dcTcpServer, "TcpServer")
|
||||||
Q_LOGGING_CATEGORY(dcWebServer, "WebServer")
|
Q_LOGGING_CATEGORY(dcWebServer, "WebServer")
|
||||||
Q_LOGGING_CATEGORY(dcJsonRpc, "JsonRpc")
|
Q_LOGGING_CATEGORY(dcJsonRpc, "JsonRpc")
|
||||||
|
Q_LOGGING_CATEGORY(dcRest, "Rest")
|
||||||
Q_LOGGING_CATEGORY(dcLogEngine, "LogEngine")
|
Q_LOGGING_CATEGORY(dcLogEngine, "LogEngine")
|
||||||
|
|
||||||
|
|||||||
@ -30,6 +30,7 @@ Q_DECLARE_LOGGING_CATEGORY(dcRuleEngine)
|
|||||||
Q_DECLARE_LOGGING_CATEGORY(dcHardware)
|
Q_DECLARE_LOGGING_CATEGORY(dcHardware)
|
||||||
Q_DECLARE_LOGGING_CATEGORY(dcConnection)
|
Q_DECLARE_LOGGING_CATEGORY(dcConnection)
|
||||||
Q_DECLARE_LOGGING_CATEGORY(dcJsonRpc)
|
Q_DECLARE_LOGGING_CATEGORY(dcJsonRpc)
|
||||||
|
Q_DECLARE_LOGGING_CATEGORY(dcRest)
|
||||||
Q_DECLARE_LOGGING_CATEGORY(dcLogEngine)
|
Q_DECLARE_LOGGING_CATEGORY(dcLogEngine)
|
||||||
Q_DECLARE_LOGGING_CATEGORY(dcTcpServer)
|
Q_DECLARE_LOGGING_CATEGORY(dcTcpServer)
|
||||||
Q_DECLARE_LOGGING_CATEGORY(dcWebServer)
|
Q_DECLARE_LOGGING_CATEGORY(dcWebServer)
|
||||||
|
|||||||
@ -109,9 +109,9 @@ HttpReply::HttpReply(const HttpStatusCode &statusCode) :
|
|||||||
{
|
{
|
||||||
// set known headers
|
// set known headers
|
||||||
setHeader(HttpHeaderType::ServerHeader, "guh/" + QByteArray(GUH_VERSION_STRING));
|
setHeader(HttpHeaderType::ServerHeader, "guh/" + QByteArray(GUH_VERSION_STRING));
|
||||||
setHeader(HttpHeaderType::UserAgentHeader, "guh/" + QByteArray(REST_API_VERSION));
|
|
||||||
setHeader(HttpHeaderType::DateHeader, QDateTime::currentDateTime().toString("ddd, dd MMM yyyy hh:mm:ss").toUtf8() + " GMT");
|
setHeader(HttpHeaderType::DateHeader, QDateTime::currentDateTime().toString("ddd, dd MMM yyyy hh:mm:ss").toUtf8() + " GMT");
|
||||||
setHeader(HttpHeaderType::CacheControlHeader, "no-cache");
|
setHeader(HttpHeaderType::CacheControlHeader, "no-cache");
|
||||||
|
packReply();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Set the \a statusCode for this \l{HttpReply}.*/
|
/*! Set the \a statusCode for this \l{HttpReply}.*/
|
||||||
|
|||||||
@ -62,7 +62,7 @@ public:
|
|||||||
ServerHeader
|
ServerHeader
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit HttpReply(const HttpStatusCode &statusCode);
|
explicit HttpReply(const HttpStatusCode &statusCode = HttpStatusCode::Ok);
|
||||||
|
|
||||||
void setHttpStatusCode(const HttpStatusCode &statusCode);
|
void setHttpStatusCode(const HttpStatusCode &statusCode);
|
||||||
HttpStatusCode httpStatusCode() const;
|
HttpStatusCode httpStatusCode() const;
|
||||||
|
|||||||
@ -50,15 +50,17 @@ HttpRequest::HttpRequest(QByteArray rawData) :
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_method = statusLineTokens.at(0).toUtf8().simplified();
|
// verify http version
|
||||||
m_urlQuery = QUrlQuery(statusLineTokens.at(1).simplified());
|
|
||||||
m_httpVersion = statusLineTokens.at(2).toUtf8().simplified();
|
m_httpVersion = statusLineTokens.at(2).toUtf8().simplified();
|
||||||
|
|
||||||
if (!m_httpVersion.contains("HTTP")) {
|
if (!m_httpVersion.contains("HTTP")) {
|
||||||
qCWarning(dcWebServer) << "Unknown HTTP version:" << m_httpVersion;
|
qCWarning(dcWebServer) << "Unknown HTTP version:" << m_httpVersion;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
m_method = getRequestMethodType(statusLineTokens.at(0).simplified());
|
||||||
|
|
||||||
|
m_urlQuery = QUrlQuery(statusLineTokens.at(1).simplified());
|
||||||
|
|
||||||
|
// verify headers
|
||||||
foreach (const QString &line, headerLines) {
|
foreach (const QString &line, headerLines) {
|
||||||
if (!line.contains(":")) {
|
if (!line.contains(":")) {
|
||||||
qCWarning(dcWebServer) << "Invalid HTTP header:" << line;
|
qCWarning(dcWebServer) << "Invalid HTTP header:" << line;
|
||||||
@ -70,6 +72,8 @@ HttpRequest::HttpRequest(QByteArray rawData) :
|
|||||||
m_rawHeaderList.insert(key, value);
|
m_rawHeaderList.insert(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: check content size
|
||||||
|
|
||||||
m_valid = true;
|
m_valid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +87,7 @@ QHash<QByteArray, QByteArray> HttpRequest::rawHeaderList() const
|
|||||||
return m_rawHeaderList;
|
return m_rawHeaderList;
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray HttpRequest::method() const
|
HttpRequest::RequestMethod HttpRequest::method() const
|
||||||
{
|
{
|
||||||
return m_method;
|
return m_method;
|
||||||
}
|
}
|
||||||
@ -113,6 +117,21 @@ bool HttpRequest::hasPayload() const
|
|||||||
return !m_payload.isEmpty();
|
return !m_payload.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HttpRequest::RequestMethod HttpRequest::getRequestMethodType(const QString &methodString)
|
||||||
|
{
|
||||||
|
if (methodString == "GET") {
|
||||||
|
return RequestMethod::Get;
|
||||||
|
} else if (methodString == "POST") {
|
||||||
|
return RequestMethod::Post;
|
||||||
|
} else if (methodString == "PUT") {
|
||||||
|
return RequestMethod::Put;
|
||||||
|
} else if (methodString == "DELETE") {
|
||||||
|
return RequestMethod::Delete;
|
||||||
|
}
|
||||||
|
qCWarning(dcWebServer) << "Method" << methodString << "will not be handled.";
|
||||||
|
return RequestMethod::Unhandled;
|
||||||
|
}
|
||||||
|
|
||||||
QDebug operator<<(QDebug debug, const HttpRequest &httpRequest)
|
QDebug operator<<(QDebug debug, const HttpRequest &httpRequest)
|
||||||
{
|
{
|
||||||
debug << "===================================" << "\n";
|
debug << "===================================" << "\n";
|
||||||
|
|||||||
@ -29,12 +29,20 @@
|
|||||||
class HttpRequest
|
class HttpRequest
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum RequestMethod {
|
||||||
|
Get,
|
||||||
|
Post,
|
||||||
|
Put,
|
||||||
|
Delete,
|
||||||
|
Unhandled
|
||||||
|
};
|
||||||
|
|
||||||
explicit HttpRequest(QByteArray rawData);
|
explicit HttpRequest(QByteArray rawData);
|
||||||
|
|
||||||
QByteArray rawHeader() const;
|
QByteArray rawHeader() const;
|
||||||
QHash<QByteArray, QByteArray> rawHeaderList() const;
|
QHash<QByteArray, QByteArray> rawHeaderList() const;
|
||||||
|
|
||||||
QByteArray method() const;
|
RequestMethod method() const;
|
||||||
QByteArray httpVersion() const;
|
QByteArray httpVersion() const;
|
||||||
QUrlQuery urlQuery() const;
|
QUrlQuery urlQuery() const;
|
||||||
|
|
||||||
@ -48,13 +56,15 @@ private:
|
|||||||
QByteArray m_rawHeader;
|
QByteArray m_rawHeader;
|
||||||
QHash<QByteArray, QByteArray> m_rawHeaderList;
|
QHash<QByteArray, QByteArray> m_rawHeaderList;
|
||||||
|
|
||||||
QByteArray m_method;
|
RequestMethod m_method;
|
||||||
QByteArray m_httpVersion;
|
QByteArray m_httpVersion;
|
||||||
QUrlQuery m_urlQuery;
|
QUrlQuery m_urlQuery;
|
||||||
|
|
||||||
QByteArray m_payload;
|
QByteArray m_payload;
|
||||||
|
|
||||||
bool m_valid;
|
bool m_valid;
|
||||||
|
|
||||||
|
RequestMethod getRequestMethodType(const QString &methodString);
|
||||||
};
|
};
|
||||||
|
|
||||||
QDebug operator<< (QDebug debug, const HttpRequest &httpRequest);
|
QDebug operator<< (QDebug debug, const HttpRequest &httpRequest);
|
||||||
|
|||||||
@ -262,29 +262,16 @@ QString DeviceHandler::name() const
|
|||||||
JsonReply* DeviceHandler::GetSupportedVendors(const QVariantMap ¶ms) const
|
JsonReply* DeviceHandler::GetSupportedVendors(const QVariantMap ¶ms) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(params)
|
Q_UNUSED(params)
|
||||||
|
|
||||||
QVariantMap returns;
|
QVariantMap returns;
|
||||||
QVariantList supportedVendors;
|
returns.insert("vendors", JsonTypes::packSupportedVendors());
|
||||||
foreach (const Vendor &vendor, GuhCore::instance()->supportedVendors()) {
|
|
||||||
supportedVendors.append(JsonTypes::packVendor(vendor));
|
|
||||||
}
|
|
||||||
returns.insert("vendors", supportedVendors);
|
|
||||||
return createReply(returns);
|
return createReply(returns);
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonReply* DeviceHandler::GetSupportedDevices(const QVariantMap ¶ms) const
|
JsonReply* DeviceHandler::GetSupportedDevices(const QVariantMap ¶ms) const
|
||||||
{
|
{
|
||||||
QVariantMap returns;
|
QVariantMap returns;
|
||||||
QVariantList supportedDeviceList;
|
returns.insert("deviceClasses", JsonTypes::packSupportedDevices(VendorId(params.value("vendorId").toString())));
|
||||||
QList<DeviceClass> supportedDevices;
|
|
||||||
if (params.contains("vendorId")) {
|
|
||||||
supportedDevices = GuhCore::instance()->supportedDevices(VendorId(params.value("vendorId").toString()));
|
|
||||||
} else {
|
|
||||||
supportedDevices = GuhCore::instance()->supportedDevices();
|
|
||||||
}
|
|
||||||
foreach (const DeviceClass &deviceClass, supportedDevices) {
|
|
||||||
supportedDeviceList.append(JsonTypes::packDeviceClass(deviceClass));
|
|
||||||
}
|
|
||||||
returns.insert("deviceClasses", supportedDeviceList);
|
|
||||||
return createReply(returns);
|
return createReply(returns);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,20 +296,9 @@ JsonReply *DeviceHandler::GetDiscoveredDevices(const QVariantMap ¶ms) const
|
|||||||
JsonReply* DeviceHandler::GetPlugins(const QVariantMap ¶ms) const
|
JsonReply* DeviceHandler::GetPlugins(const QVariantMap ¶ms) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(params)
|
Q_UNUSED(params)
|
||||||
|
|
||||||
QVariantMap returns;
|
QVariantMap returns;
|
||||||
QVariantList plugins;
|
returns.insert("plugins", JsonTypes::packPlugins());
|
||||||
foreach (DevicePlugin *plugin, GuhCore::instance()->plugins()) {
|
|
||||||
QVariantMap pluginMap;
|
|
||||||
pluginMap.insert("id", plugin->pluginId());
|
|
||||||
pluginMap.insert("name", plugin->pluginName());
|
|
||||||
QVariantList params;
|
|
||||||
foreach (const ParamType ¶m, plugin->configurationDescription()) {
|
|
||||||
params.append(JsonTypes::packParamType(param));
|
|
||||||
}
|
|
||||||
pluginMap.insert("params", params);
|
|
||||||
plugins.append(pluginMap);
|
|
||||||
}
|
|
||||||
returns.insert("plugins", plugins);
|
|
||||||
return createReply(returns);
|
return createReply(returns);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -531,14 +507,14 @@ JsonReply* DeviceHandler::GetStateValue(const QVariantMap ¶ms) const
|
|||||||
returns.insert("deviceError", JsonTypes::deviceErrorToString(DeviceManager::DeviceErrorDeviceNotFound));
|
returns.insert("deviceError", JsonTypes::deviceErrorToString(DeviceManager::DeviceErrorDeviceNotFound));
|
||||||
return createReply(returns);
|
return createReply(returns);
|
||||||
}
|
}
|
||||||
if (!device->hasState(StateTypeId(params.value("stateTypeId").toString()))) {
|
StateTypeId stateTypeId = StateTypeId(params.value("stateTypeId").toString());
|
||||||
|
if (!device->hasState(stateTypeId)) {
|
||||||
returns.insert("deviceError", JsonTypes::deviceErrorToString(DeviceManager::DeviceErrorStateTypeNotFound));
|
returns.insert("deviceError", JsonTypes::deviceErrorToString(DeviceManager::DeviceErrorStateTypeNotFound));
|
||||||
return createReply(returns);
|
return createReply(returns);
|
||||||
}
|
}
|
||||||
QVariant stateValue = device->stateValue(StateTypeId(params.value("stateTypeId").toString()));
|
|
||||||
|
|
||||||
returns.insert("deviceError", JsonTypes::deviceErrorToString(DeviceManager::DeviceErrorNoError));
|
returns.insert("deviceError", JsonTypes::deviceErrorToString(DeviceManager::DeviceErrorNoError));
|
||||||
returns.insert("value", stateValue);
|
returns.insert("value", device->state(stateTypeId).value());
|
||||||
return createReply(returns);
|
return createReply(returns);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -552,20 +528,8 @@ JsonReply *DeviceHandler::GetStateValues(const QVariantMap ¶ms) const
|
|||||||
return createReply(returns);
|
return createReply(returns);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceClass deviceClass = GuhCore::instance()->findDeviceClass(device->deviceClassId());
|
|
||||||
if (!deviceClass.isValid()) {
|
|
||||||
returns.insert("deviceError", JsonTypes::deviceErrorToString(DeviceManager::DeviceErrorDeviceClassNotFound));
|
|
||||||
return createReply(returns);
|
|
||||||
}
|
|
||||||
QVariantList values;
|
|
||||||
foreach (const StateType &stateType, deviceClass.stateTypes()) {
|
|
||||||
QVariantMap stateValue;
|
|
||||||
stateValue.insert("stateTypeId", stateType.id().toString());
|
|
||||||
stateValue.insert("value", device->stateValue(stateType.id()));
|
|
||||||
values.append(stateValue);
|
|
||||||
}
|
|
||||||
returns.insert("deviceError", JsonTypes::deviceErrorToString(DeviceManager::DeviceErrorNoError));
|
returns.insert("deviceError", JsonTypes::deviceErrorToString(DeviceManager::DeviceErrorNoError));
|
||||||
returns.insert("values", values);
|
returns.insert("values", JsonTypes::packDeviceStates(device));
|
||||||
return createReply(returns);
|
return createReply(returns);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include "plugin/device.h"
|
#include "plugin/device.h"
|
||||||
#include "devicemanager.h"
|
#include "devicemanager.h"
|
||||||
|
#include "guhcore.h"
|
||||||
#include "ruleengine.h"
|
#include "ruleengine.h"
|
||||||
#include "loggingcategories.h"
|
#include "loggingcategories.h"
|
||||||
|
|
||||||
@ -387,6 +388,14 @@ QVariantMap JsonTypes::packRuleActionParam(const RuleActionParam &ruleActionPara
|
|||||||
return variantMap;
|
return variantMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariantMap JsonTypes::packState(const State &state)
|
||||||
|
{
|
||||||
|
QVariantMap stateMap;
|
||||||
|
stateMap.insert("stateTypeId", state.stateTypeId().toString());
|
||||||
|
stateMap.insert("value", state.value());
|
||||||
|
return stateMap;
|
||||||
|
}
|
||||||
|
|
||||||
QVariantMap JsonTypes::packStateType(const StateType &stateType)
|
QVariantMap JsonTypes::packStateType(const StateType &stateType)
|
||||||
{
|
{
|
||||||
QVariantMap variantMap;
|
QVariantMap variantMap;
|
||||||
@ -526,9 +535,17 @@ QVariantMap JsonTypes::packDeviceClass(const DeviceClass &deviceClass)
|
|||||||
|
|
||||||
QVariantMap JsonTypes::packPlugin(DevicePlugin *plugin)
|
QVariantMap JsonTypes::packPlugin(DevicePlugin *plugin)
|
||||||
{
|
{
|
||||||
Q_UNUSED(plugin)
|
QVariantMap pluginMap;
|
||||||
qCWarning(dcDeviceManager) << "packPlugin not implemented yet!";
|
pluginMap.insert("id", plugin->pluginId());
|
||||||
return QVariantMap();
|
pluginMap.insert("name", plugin->pluginName());
|
||||||
|
|
||||||
|
QVariantList params;
|
||||||
|
foreach (const ParamType ¶m, plugin->configurationDescription()) {
|
||||||
|
params.append(packParamType(param));
|
||||||
|
}
|
||||||
|
pluginMap.insert("params", params);
|
||||||
|
|
||||||
|
return pluginMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariantMap JsonTypes::packDevice(Device *device)
|
QVariantMap JsonTypes::packDevice(Device *device)
|
||||||
@ -656,6 +673,56 @@ QVariantList JsonTypes::packCreateMethods(DeviceClass::CreateMethods createMetho
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariantList JsonTypes::packSupportedVendors()
|
||||||
|
{
|
||||||
|
QVariantList supportedVendors;
|
||||||
|
foreach (const Vendor &vendor, GuhCore::instance()->supportedVendors()) {
|
||||||
|
supportedVendors.append(packVendor(vendor));
|
||||||
|
}
|
||||||
|
return supportedVendors;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantList JsonTypes::packSupportedDevices(const VendorId &vendorId)
|
||||||
|
{
|
||||||
|
QVariantList supportedDeviceList;
|
||||||
|
foreach (const DeviceClass &deviceClass, GuhCore::instance()->supportedDevices(vendorId)) {
|
||||||
|
supportedDeviceList.append(packDeviceClass(deviceClass));
|
||||||
|
}
|
||||||
|
return supportedDeviceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantList JsonTypes::packConfiguredDevices()
|
||||||
|
{
|
||||||
|
QVariantList configuredDeviceList;
|
||||||
|
foreach (Device *device, GuhCore::instance()->configuredDevices()) {
|
||||||
|
configuredDeviceList.append(packDevice(device));
|
||||||
|
}
|
||||||
|
return configuredDeviceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantList JsonTypes::packDeviceStates(Device *device)
|
||||||
|
{
|
||||||
|
DeviceClass deviceClass = GuhCore::instance()->findDeviceClass(device->deviceClassId());
|
||||||
|
QVariantList stateValues;
|
||||||
|
foreach (const StateType &stateType, deviceClass.stateTypes()) {
|
||||||
|
QVariantMap stateValue;
|
||||||
|
stateValue.insert("stateTypeId", stateType.id().toString());
|
||||||
|
stateValue.insert("value", device->stateValue(stateType.id()));
|
||||||
|
stateValues.append(stateValue);
|
||||||
|
}
|
||||||
|
return stateValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantList JsonTypes::packPlugins()
|
||||||
|
{
|
||||||
|
QVariantList pluginsList;
|
||||||
|
foreach (DevicePlugin *plugin, GuhCore::instance()->plugins()) {
|
||||||
|
QVariantMap pluginMap = packPlugin(plugin);
|
||||||
|
pluginsList.append(pluginMap);
|
||||||
|
}
|
||||||
|
return pluginsList;
|
||||||
|
}
|
||||||
|
|
||||||
Param JsonTypes::unpackParam(const QVariantMap ¶mMap)
|
Param JsonTypes::unpackParam(const QVariantMap ¶mMap)
|
||||||
{
|
{
|
||||||
if (paramMap.keys().count() == 0) {
|
if (paramMap.keys().count() == 0) {
|
||||||
|
|||||||
@ -135,6 +135,7 @@ public:
|
|||||||
DECLARE_OBJECT(ruleDescription, "RuleDescription")
|
DECLARE_OBJECT(ruleDescription, "RuleDescription")
|
||||||
DECLARE_OBJECT(logEntry, "LogEntry")
|
DECLARE_OBJECT(logEntry, "LogEntry")
|
||||||
|
|
||||||
|
// pack types
|
||||||
static QVariantMap packEventType(const EventType &eventType);
|
static QVariantMap packEventType(const EventType &eventType);
|
||||||
static QVariantMap packEvent(const Event &event);
|
static QVariantMap packEvent(const Event &event);
|
||||||
static QVariantMap packEventDescriptor(const EventDescriptor &event);
|
static QVariantMap packEventDescriptor(const EventDescriptor &event);
|
||||||
@ -142,6 +143,7 @@ public:
|
|||||||
static QVariantMap packAction(const Action &action);
|
static QVariantMap packAction(const Action &action);
|
||||||
static QVariantMap packRuleAction(const RuleAction &ruleAction);
|
static QVariantMap packRuleAction(const RuleAction &ruleAction);
|
||||||
static QVariantMap packRuleActionParam(const RuleActionParam &ruleActionParam);
|
static QVariantMap packRuleActionParam(const RuleActionParam &ruleActionParam);
|
||||||
|
static QVariantMap packState(const State &state);
|
||||||
static QVariantMap packStateType(const StateType &stateType);
|
static QVariantMap packStateType(const StateType &stateType);
|
||||||
static QVariantMap packStateDescriptor(const StateDescriptor &stateDescriptor);
|
static QVariantMap packStateDescriptor(const StateDescriptor &stateDescriptor);
|
||||||
static QVariantMap packStateEvaluator(const StateEvaluator &stateEvaluator);
|
static QVariantMap packStateEvaluator(const StateEvaluator &stateEvaluator);
|
||||||
@ -158,6 +160,16 @@ public:
|
|||||||
static QVariantMap packLogEntry(const LogEntry &logEntry);
|
static QVariantMap packLogEntry(const LogEntry &logEntry);
|
||||||
static QVariantList packCreateMethods(DeviceClass::CreateMethods createMethods);
|
static QVariantList packCreateMethods(DeviceClass::CreateMethods createMethods);
|
||||||
|
|
||||||
|
// pack resources
|
||||||
|
static QVariantList packSupportedVendors();
|
||||||
|
static QVariantList packSupportedDevices(const VendorId &vendorId);
|
||||||
|
static QVariantList packConfiguredDevices();
|
||||||
|
static QVariantList packDeviceStates(Device *device);
|
||||||
|
|
||||||
|
static QVariantList packPlugins();
|
||||||
|
|
||||||
|
|
||||||
|
// unpack Types
|
||||||
static Param unpackParam(const QVariantMap ¶mMap);
|
static Param unpackParam(const QVariantMap ¶mMap);
|
||||||
static ParamList unpackParams(const QVariantList ¶mList);
|
static ParamList unpackParams(const QVariantList ¶mList);
|
||||||
static RuleActionParam unpackRuleActionParam(const QVariantMap &ruleActionParamMap);
|
static RuleActionParam unpackRuleActionParam(const QVariantMap &ruleActionParamMap);
|
||||||
@ -169,6 +181,7 @@ public:
|
|||||||
static StateDescriptor unpackStateDescriptor(const QVariantMap &stateDescriptorMap);
|
static StateDescriptor unpackStateDescriptor(const QVariantMap &stateDescriptorMap);
|
||||||
static LogFilter unpackLogFilter(const QVariantMap &logFilterMap);
|
static LogFilter unpackLogFilter(const QVariantMap &logFilterMap);
|
||||||
|
|
||||||
|
// validate
|
||||||
static QPair<bool, QString> validateMap(const QVariantMap &templateMap, const QVariantMap &map);
|
static QPair<bool, QString> validateMap(const QVariantMap &templateMap, const QVariantMap &map);
|
||||||
static QPair<bool, QString> validateProperty(const QVariant &templateValue, const QVariant &value);
|
static QPair<bool, QString> validateProperty(const QVariant &templateValue, const QVariant &value);
|
||||||
static QPair<bool, QString> validateList(const QVariantList &templateList, const QVariantList &list);
|
static QPair<bool, QString> validateList(const QVariantList &templateList, const QVariantList &list);
|
||||||
|
|||||||
@ -65,6 +65,7 @@ int main(int argc, char *argv[])
|
|||||||
s_loggingFilters.insert("TcpServer", true);
|
s_loggingFilters.insert("TcpServer", true);
|
||||||
s_loggingFilters.insert("WebServer", true);
|
s_loggingFilters.insert("WebServer", true);
|
||||||
s_loggingFilters.insert("JsonRpc", false);
|
s_loggingFilters.insert("JsonRpc", false);
|
||||||
|
s_loggingFilters.insert("Rest", true);
|
||||||
s_loggingFilters.insert("Hardware", false);
|
s_loggingFilters.insert("Hardware", false);
|
||||||
s_loggingFilters.insert("LogEngine", false);
|
s_loggingFilters.insert("LogEngine", false);
|
||||||
|
|
||||||
|
|||||||
153
server/rest/devicesresource.cpp
Normal file
153
server/rest/devicesresource.cpp
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* *
|
||||||
|
* 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 "devicesresource.h"
|
||||||
|
#include "jsontypes.h"
|
||||||
|
#include "guhcore.h"
|
||||||
|
#include "network/httpreply.h"
|
||||||
|
#include "network/httprequest.h"
|
||||||
|
|
||||||
|
#include <QJsonDocument>
|
||||||
|
|
||||||
|
namespace guhserver {
|
||||||
|
|
||||||
|
DevicesResource::DevicesResource(QObject *parent) :
|
||||||
|
QObject(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpReply DevicesResource::proccessDeviceRequest(const HttpRequest &request, const QStringList &urlTokens)
|
||||||
|
{
|
||||||
|
DeviceId deviceId;
|
||||||
|
StateTypeId stateTypeId;
|
||||||
|
|
||||||
|
Device *device = 0;
|
||||||
|
|
||||||
|
// first parse device, stateTypeId
|
||||||
|
if (urlTokens.count() >= 4) {
|
||||||
|
deviceId = DeviceId(urlTokens.at(3));
|
||||||
|
if (deviceId.isNull()) {
|
||||||
|
qCWarning(dcRest) << "Could not parse DeviceId:" << urlTokens.at(3);
|
||||||
|
return HttpReply(HttpReply::BadRequest);
|
||||||
|
}
|
||||||
|
device = GuhCore::instance()->findConfiguredDevice(deviceId);
|
||||||
|
if (!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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check methods
|
||||||
|
if (request.method() == HttpRequest::Get) {
|
||||||
|
|
||||||
|
// /api/v1/devices
|
||||||
|
if (urlTokens.count() == 3)
|
||||||
|
return getConfiguredDevices();
|
||||||
|
|
||||||
|
// /api/v1/devices/{deviceId}
|
||||||
|
if (urlTokens.count() == 4)
|
||||||
|
return getConfiguredDevice(device);
|
||||||
|
|
||||||
|
// /api/v1/devices/{deviceId}/states
|
||||||
|
if (urlTokens.count() == 5 && urlTokens.at(4) == "states")
|
||||||
|
return getDeviceStateValues(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) {
|
||||||
|
|
||||||
|
// /api/v1/devices
|
||||||
|
if (urlTokens.count() == 3)
|
||||||
|
return HttpReply(HttpReply::BadRequest);
|
||||||
|
|
||||||
|
if (urlTokens.count() == 4)
|
||||||
|
return removeDevice(device);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return HttpReply(HttpReply::BadRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpReply DevicesResource::getConfiguredDevices()
|
||||||
|
{
|
||||||
|
HttpReply httpReply(HttpReply::Ok);
|
||||||
|
httpReply.setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";");
|
||||||
|
httpReply.setPayload(QJsonDocument::fromVariant(JsonTypes::packConfiguredDevices()).toJson());
|
||||||
|
httpReply.packReply();
|
||||||
|
return httpReply;
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpReply DevicesResource::getConfiguredDevice(Device *device)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpReply DevicesResource::getDeviceStateValues(Device *device)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpReply DevicesResource::getDeviceStateValue(Device *device, const StateTypeId &stateTypeId)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpReply DevicesResource::removeDevice(Device *device)
|
||||||
|
{
|
||||||
|
DeviceManager::DeviceError result = GuhCore::instance()->removeConfiguredDevice(device->id(), QHash<RuleId, RuleEngine::RemovePolicy>());
|
||||||
|
|
||||||
|
// TODO: parse removepolicy query params
|
||||||
|
|
||||||
|
if (result == DeviceManager::DeviceErrorNoError)
|
||||||
|
return HttpReply(HttpReply::Ok);
|
||||||
|
|
||||||
|
return HttpReply(HttpReply::Forbidden);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
56
server/rest/devicesresource.h
Normal file
56
server/rest/devicesresource.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* *
|
||||||
|
* 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 DEVICESRESOURCE_H
|
||||||
|
#define DEVICESRESOURCE_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include "jsontypes.h"
|
||||||
|
|
||||||
|
class HttpReply;
|
||||||
|
class HttpRequest;
|
||||||
|
|
||||||
|
namespace guhserver {
|
||||||
|
|
||||||
|
class DevicesResource : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit DevicesResource(QObject *parent = 0);
|
||||||
|
|
||||||
|
HttpReply proccessDeviceRequest(const HttpRequest &request, const QStringList &urlTokens);
|
||||||
|
|
||||||
|
private:
|
||||||
|
HttpReply getConfiguredDevices();
|
||||||
|
HttpReply getConfiguredDevice(Device *device);
|
||||||
|
HttpReply getDeviceStateValues(Device *device);
|
||||||
|
HttpReply getDeviceStateValue(Device *device, const StateTypeId &stateTypeId);
|
||||||
|
|
||||||
|
HttpReply removeDevice(Device *device);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // DEVICESRESOURCE_H
|
||||||
@ -24,13 +24,6 @@
|
|||||||
#include "network/httpreply.h"
|
#include "network/httpreply.h"
|
||||||
#include "guhcore.h"
|
#include "guhcore.h"
|
||||||
|
|
||||||
#include "devicehandler.h"
|
|
||||||
#include "actionhandler.h"
|
|
||||||
#include "ruleshandler.h"
|
|
||||||
#include "eventhandler.h"
|
|
||||||
#include "logginghandler.h"
|
|
||||||
#include "statehandler.h"
|
|
||||||
|
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
|
||||||
namespace guhserver {
|
namespace guhserver {
|
||||||
@ -43,6 +36,10 @@ RestServer::RestServer(QObject *parent) :
|
|||||||
connect(m_webserver, &WebServer::clientDisconnected, this, &RestServer::clientDisconnected);
|
connect(m_webserver, &WebServer::clientDisconnected, this, &RestServer::clientDisconnected);
|
||||||
connect(m_webserver, &WebServer::httpRequestReady, this, &RestServer::processHttpRequest);
|
connect(m_webserver, &WebServer::httpRequestReady, this, &RestServer::processHttpRequest);
|
||||||
|
|
||||||
|
// Resources
|
||||||
|
m_deviceResource = new DevicesResource(this);
|
||||||
|
|
||||||
|
|
||||||
m_webserver->startServer();
|
m_webserver->startServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,57 +55,87 @@ void RestServer::clientDisconnected(const QUuid &clientId)
|
|||||||
|
|
||||||
void RestServer::processHttpRequest(const QUuid &clientId, const HttpRequest &request)
|
void RestServer::processHttpRequest(const QUuid &clientId, const HttpRequest &request)
|
||||||
{
|
{
|
||||||
qCDebug(dcWebServer) << "process http request" << clientId << request.method() << request.urlQuery().query();
|
qCDebug(dcRest) << "Process HTTP request" << clientId << request.method() << request.urlQuery().query();
|
||||||
|
|
||||||
QString targetNamespace;
|
QStringList urlTokens = request.urlQuery().query(QUrl::FullyDecoded).split("/");
|
||||||
QString method;
|
urlTokens.removeAll(QString());
|
||||||
QVariantMap params;
|
|
||||||
|
|
||||||
if (request.urlQuery().hasQueryItem("devices")) {
|
qCDebug(dcRest) << urlTokens;
|
||||||
qCDebug(dcWebServer) << "devices resource";
|
|
||||||
|
|
||||||
|
if (urlTokens.count() < 3) {
|
||||||
|
m_webserver->sendHttpReply(clientId, HttpReply(HttpReply::BadRequest));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.method() == "GET" && request.urlQuery().query() == "/api/v1/devices.json") {
|
if (urlTokens.at(2) == "devices") {
|
||||||
targetNamespace = "Devices";
|
HttpReply httpReply = m_deviceResource->proccessDeviceRequest(request, urlTokens);
|
||||||
method = "GetConfiguredDevices";
|
qCDebug(dcRest) << "sending header" << httpReply.rawHeader();
|
||||||
} else if (request.method() == "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);
|
m_webserver->sendHttpReply(clientId, httpReply);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
JsonHandler *handler = GuhCore::instance()->jsonRPCServer()->handlers().value(targetNamespace);
|
|
||||||
|
|
||||||
QPair<bool, QString> validationResult = handler->validateParams(method, params);
|
// QString targetNamespace;
|
||||||
if (!validationResult.first) {
|
// QString method;
|
||||||
qCWarning(dcWebServer) << "Invalid params: " << validationResult.second;
|
// QVariantMap params;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonReply *jsonReply;
|
// // check filter
|
||||||
QMetaObject::invokeMethod(handler, method.toLatin1().data(), Q_RETURN_ARG(JsonReply*, jsonReply), Q_ARG(QVariantMap, params));
|
// QVariantList deviceList;
|
||||||
if (jsonReply->type() == JsonReply::TypeAsync) {
|
// if (!request.urlQuery().hasQueryItem("id")) {
|
||||||
jsonReply->setClientId(clientId);
|
// HttpReply httpReply = m_deviceResource->proccessDeviceRequest(request);
|
||||||
connect(jsonReply, &JsonReply::finished, this, &RestServer::asyncReplyFinished);
|
// m_webserver->sendHttpReply(clientId, httpReply);
|
||||||
jsonReply->startWait();
|
// return;
|
||||||
m_asyncReplies.insert(clientId, jsonReply);
|
// } else {
|
||||||
return;
|
// foreach (const QString& idString, request.urlQuery().allQueryItemValues("id")) {
|
||||||
}
|
// Device *device = GuhCore::instance()->deviceManager()->findConfiguredDevice(DeviceId(idString));
|
||||||
|
// if (device == Device()) {
|
||||||
|
|
||||||
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 (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();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RestServer::asyncReplyFinished()
|
void RestServer::asyncReplyFinished()
|
||||||
|
|||||||
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include "webserver.h"
|
#include "webserver.h"
|
||||||
#include "jsonhandler.h"
|
#include "jsonhandler.h"
|
||||||
|
#include "devicesresource.h"
|
||||||
|
|
||||||
class HttpRequest;
|
class HttpRequest;
|
||||||
class HttpReply;
|
class HttpReply;
|
||||||
@ -42,6 +43,8 @@ private:
|
|||||||
QList<QUuid> m_clientList;
|
QList<QUuid> m_clientList;
|
||||||
QHash<QUuid, JsonReply *> m_asyncReplies;
|
QHash<QUuid, JsonReply *> m_asyncReplies;
|
||||||
|
|
||||||
|
DevicesResource *m_deviceResource;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void httpReplyReady(const HttpReply &httpReply);
|
void httpReplyReady(const HttpReply &httpReply);
|
||||||
|
|
||||||
|
|||||||
@ -25,7 +25,8 @@ SOURCES += $$top_srcdir/server/guhcore.cpp \
|
|||||||
$$top_srcdir/server/transportinterface.cpp \
|
$$top_srcdir/server/transportinterface.cpp \
|
||||||
$$top_srcdir/server/servermanager.cpp \
|
$$top_srcdir/server/servermanager.cpp \
|
||||||
$$top_srcdir/server/websocketserver.cpp \
|
$$top_srcdir/server/websocketserver.cpp \
|
||||||
$$top_srcdir/server/rest/restserver.cpp
|
$$top_srcdir/server/rest/restserver.cpp \
|
||||||
|
$$top_srcdir/server/rest/devicesresource.cpp \
|
||||||
|
|
||||||
|
|
||||||
HEADERS += $$top_srcdir/server/guhcore.h \
|
HEADERS += $$top_srcdir/server/guhcore.h \
|
||||||
@ -51,5 +52,6 @@ HEADERS += $$top_srcdir/server/guhcore.h \
|
|||||||
$$top_srcdir/server/servermanager.h \
|
$$top_srcdir/server/servermanager.h \
|
||||||
$$top_srcdir/server/websocketserver.h \
|
$$top_srcdir/server/websocketserver.h \
|
||||||
$$top_srcdir/server/rest/restserver.h \
|
$$top_srcdir/server/rest/restserver.h \
|
||||||
|
$$top_srcdir/server/rest/devicesresource.h \
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -40,7 +40,7 @@ WebServer::WebServer(QObject *parent) :
|
|||||||
{
|
{
|
||||||
// load webserver settings
|
// load webserver settings
|
||||||
GuhSettings settings(GuhSettings::SettingsRoleGlobal);
|
GuhSettings settings(GuhSettings::SettingsRoleGlobal);
|
||||||
qCDebug(dcTcpServer) << "Loading Webserver settings from:" << settings.fileName();
|
qCDebug(dcTcpServer) << "Loading webserver settings from:" << settings.fileName();
|
||||||
|
|
||||||
settings.beginGroup("Webserver");
|
settings.beginGroup("Webserver");
|
||||||
m_port = settings.value("port", 3000).toInt();
|
m_port = settings.value("port", 3000).toInt();
|
||||||
@ -140,21 +140,6 @@ QString WebServer::fileName(const QString &query)
|
|||||||
return QFileInfo(m_webinterfaceDir.path() + fileName).canonicalFilePath();
|
return QFileInfo(m_webinterfaceDir.path() + fileName).canonicalFilePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
WebServer::RequestMethod WebServer::getRequestMethodType(const QString &methodString)
|
|
||||||
{
|
|
||||||
if (methodString == "GET") {
|
|
||||||
return RequestMethod::Get;
|
|
||||||
} else if (methodString == "POST") {
|
|
||||||
return RequestMethod::Post;
|
|
||||||
} else if (methodString == "PUT") {
|
|
||||||
return RequestMethod::Put;
|
|
||||||
} else if (methodString == "DELETE") {
|
|
||||||
return RequestMethod::Delete;
|
|
||||||
}
|
|
||||||
return RequestMethod::Unhandled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebServer::writeData(QTcpSocket *socket, const QByteArray &data)
|
void WebServer::writeData(QTcpSocket *socket, const QByteArray &data)
|
||||||
{
|
{
|
||||||
QTextStream os(socket);
|
QTextStream os(socket);
|
||||||
@ -195,10 +180,10 @@ void WebServer::readClient()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// read http request
|
// read HTTP request
|
||||||
HttpRequest request = HttpRequest(socket->readAll());
|
HttpRequest request = HttpRequest(socket->readAll());
|
||||||
if (!request.isValid()) {
|
if (!request.isValid()) {
|
||||||
qCWarning(dcWebServer) << "Invalid request.";
|
qCWarning(dcWebServer) << "Got invalid request.";
|
||||||
HttpReply reply(HttpReply::BadRequest);
|
HttpReply reply(HttpReply::BadRequest);
|
||||||
reply.setPayload("400 Bad Request.");
|
reply.setPayload("400 Bad Request.");
|
||||||
reply.packReply();
|
reply.packReply();
|
||||||
@ -220,9 +205,7 @@ void WebServer::readClient()
|
|||||||
qCDebug(dcWebServer) << request;
|
qCDebug(dcWebServer) << request;
|
||||||
|
|
||||||
// verify method
|
// verify method
|
||||||
RequestMethod requestMethod = getRequestMethodType(request.method());
|
if (request.method() == HttpRequest::Unhandled) {
|
||||||
if (requestMethod == RequestMethod::Unhandled) {
|
|
||||||
qCWarning(dcWebServer) << "method" << request.method() << "not allowed";
|
|
||||||
HttpReply reply(HttpReply::MethodNotAllowed);
|
HttpReply reply(HttpReply::MethodNotAllowed);
|
||||||
reply.setHeader(HttpReply::AllowHeader, "GET, PUT, POST, DELETE");
|
reply.setHeader(HttpReply::AllowHeader, "GET, PUT, POST, DELETE");
|
||||||
reply.setPayload("405 Method not allowed.");
|
reply.setPayload("405 Method not allowed.");
|
||||||
@ -238,7 +221,7 @@ void WebServer::readClient()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// request for a file...
|
// request for a file...
|
||||||
if (requestMethod == RequestMethod::Get) {
|
if (request.method() == HttpRequest::Get) {
|
||||||
if (!verifyFile(socket, fileName(request.urlQuery().query())))
|
if (!verifyFile(socket, fileName(request.urlQuery().query())))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@ -43,13 +43,7 @@ class WebServer : public TransportInterface
|
|||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
enum RequestMethod {
|
|
||||||
Get,
|
|
||||||
Post,
|
|
||||||
Put,
|
|
||||||
Delete,
|
|
||||||
Unhandled
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit WebServer(QObject *parent = 0);
|
explicit WebServer(QObject *parent = 0);
|
||||||
~WebServer();
|
~WebServer();
|
||||||
@ -70,7 +64,6 @@ private:
|
|||||||
bool verifyFile(QTcpSocket *socket, const QString &fileName);
|
bool verifyFile(QTcpSocket *socket, const QString &fileName);
|
||||||
|
|
||||||
QString fileName(const QString &query);
|
QString fileName(const QString &query);
|
||||||
RequestMethod getRequestMethodType(const QString &methodString);
|
|
||||||
|
|
||||||
void writeData(QTcpSocket *socket, const QByteArray &data);
|
void writeData(QTcpSocket *socket, const QByteArray &data);
|
||||||
|
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
TEMPLATE=subdirs
|
TEMPLATE=subdirs
|
||||||
SUBDIRS=versioning devices jsonrpc events states actions rules plugins webserver
|
SUBDIRS=versioning devices jsonrpc events states actions rules plugins webserver restdevices
|
||||||
|
|||||||
5
tests/auto/restdevices/restdevices.pro
Normal file
5
tests/auto/restdevices/restdevices.pro
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
include(../../../guh.pri)
|
||||||
|
include(../autotests.pri)
|
||||||
|
|
||||||
|
TARGET = restdevices
|
||||||
|
SOURCES += testrestdevices.cpp
|
||||||
87
tests/auto/restdevices/testrestdevices.cpp
Normal file
87
tests/auto/restdevices/testrestdevices.cpp
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||||
|
* *
|
||||||
|
* 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 "guhtestbase.h"
|
||||||
|
#include "guhcore.h"
|
||||||
|
#include "devicemanager.h"
|
||||||
|
#include "mocktcpserver.h"
|
||||||
|
#include "webserver.h"
|
||||||
|
|
||||||
|
#include <QtTest/QtTest>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QTcpSocket>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QMetaType>
|
||||||
|
|
||||||
|
using namespace guhserver;
|
||||||
|
|
||||||
|
class TestRestDevices: public GuhTestBase
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void getConfiguredDevices();
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
// for debugging
|
||||||
|
void printResponse(QNetworkReply *reply);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
void TestRestDevices::getConfiguredDevices()
|
||||||
|
{
|
||||||
|
QNetworkAccessManager *nam = new QNetworkAccessManager(this);
|
||||||
|
QSignalSpy clientSpy(nam, SIGNAL(finished(QNetworkReply*)));
|
||||||
|
|
||||||
|
QNetworkRequest request;
|
||||||
|
request.setUrl(QUrl("http://localhost:3000/api/v1/devices"));
|
||||||
|
QNetworkReply *reply;
|
||||||
|
|
||||||
|
reply = nam->get(request);
|
||||||
|
clientSpy.wait(200);
|
||||||
|
QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver");
|
||||||
|
|
||||||
|
QJsonParseError error;
|
||||||
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error);
|
||||||
|
QCOMPARE(error.error, QJsonParseError::NoError);
|
||||||
|
QVariantList deviceList = jsonDoc.toVariant().toList();
|
||||||
|
QCOMPARE(deviceList.count(), 3);
|
||||||
|
reply->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TestRestDevices::printResponse(QNetworkReply *reply)
|
||||||
|
{
|
||||||
|
qDebug() << "-------------------------------";
|
||||||
|
qDebug() << reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
|
||||||
|
foreach (const QNetworkReply::RawHeaderPair &headerPair, reply->rawHeaderPairs()) {
|
||||||
|
qDebug() << headerPair.first << ":" << headerPair.second;
|
||||||
|
}
|
||||||
|
qDebug() << "-------------------------------";
|
||||||
|
qDebug() << reply->readAll();
|
||||||
|
qDebug() << "-------------------------------";
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "testrestdevices.moc"
|
||||||
|
QTEST_MAIN(TestRestDevices)
|
||||||
@ -40,7 +40,6 @@ class TestWebserver: public GuhTestBase
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void pingServer();
|
|
||||||
void httpVersion();
|
void httpVersion();
|
||||||
|
|
||||||
void checkAllowedMethodCall_data();
|
void checkAllowedMethodCall_data();
|
||||||
@ -55,11 +54,6 @@ private:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void TestWebserver::pingServer()
|
|
||||||
{
|
|
||||||
// TODO: when QWebsocket will be used
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestWebserver::httpVersion()
|
void TestWebserver::httpVersion()
|
||||||
{
|
{
|
||||||
QTcpSocket *socket = new QTcpSocket(this);
|
QTcpSocket *socket = new QTcpSocket(this);
|
||||||
@ -156,8 +150,6 @@ void TestWebserver::getFiles_data()
|
|||||||
QTest::newRow("get /etc/guh/guhd.conf") << "/etc/guh/guhd.conf" << 404;
|
QTest::newRow("get /etc/guh/guhd.conf") << "/etc/guh/guhd.conf" << 404;
|
||||||
QTest::newRow("get /etc/sudoers") << "/etc/sudoers" << 404;
|
QTest::newRow("get /etc/sudoers") << "/etc/sudoers" << 404;
|
||||||
QTest::newRow("get /root/.ssh/id_rsa.pub") << "/root/.ssh/id_rsa.pub" << 404;
|
QTest::newRow("get /root/.ssh/id_rsa.pub") << "/root/.ssh/id_rsa.pub" << 404;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestWebserver::getFiles()
|
void TestWebserver::getFiles()
|
||||||
|
|||||||
Reference in New Issue
Block a user