From 8cd6866ffb6ebd9c167556a41b3c0b55841ceaa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Sun, 27 Sep 2015 12:53:11 +0200 Subject: [PATCH] error handling for devices and deviceclasses resource --- guh.pri | 2 +- libguh/devicemanager.cpp | 2 + libguh/devicemanager.h | 1 + server/rest/deviceclassesresource.cpp | 20 ++++----- server/rest/devicesresource.cpp | 61 +++++++++++++++++++-------- server/rest/restresource.cpp | 32 ++++++++++++++ server/rest/restresource.h | 4 ++ tests/auto/api.json | 1 + 8 files changed, 94 insertions(+), 29 deletions(-) diff --git a/guh.pri b/guh.pri index 1bafb986..71b7a2c0 100644 --- a/guh.pri +++ b/guh.pri @@ -2,7 +2,7 @@ GUH_VERSION_STRING=$$system('dpkg-parsechangelog | sed -n -e "s/^Version: //p"') # define protocol versions -JSON_PROTOCOL_VERSION=28 +JSON_PROTOCOL_VERSION=29 REST_API_VERSION=1 DEFINES += GUH_VERSION_STRING=\\\"$${GUH_VERSION_STRING}\\\" \ diff --git a/libguh/devicemanager.cpp b/libguh/devicemanager.cpp index 57c5792b..9370d215 100644 --- a/libguh/devicemanager.cpp +++ b/libguh/devicemanager.cpp @@ -61,6 +61,8 @@ No Error. Everything went fine. \value DeviceErrorPluginNotFound Couldn't find the Plugin for the given id. + \value DeviceErrorVendorNotFound + Couldn't find the Vendor for the given id. \value DeviceErrorDeviceNotFound Couldn't find a \l{Device} for the given id. \value DeviceErrorDeviceClassNotFound diff --git a/libguh/devicemanager.h b/libguh/devicemanager.h index 3dbe44f1..db7f098e 100644 --- a/libguh/devicemanager.h +++ b/libguh/devicemanager.h @@ -64,6 +64,7 @@ public: enum DeviceError { DeviceErrorNoError, DeviceErrorPluginNotFound, + DeviceErrorVendorNotFound, DeviceErrorDeviceNotFound, DeviceErrorDeviceClassNotFound, DeviceErrorActionTypeNotFound, diff --git a/server/rest/deviceclassesresource.cpp b/server/rest/deviceclassesresource.cpp index 5b913781..970497c2 100644 --- a/server/rest/deviceclassesresource.cpp +++ b/server/rest/deviceclassesresource.cpp @@ -47,12 +47,12 @@ HttpReply *DeviceClassesResource::proccessRequest(const HttpRequest &request, co DeviceClassId deviceClassId = DeviceClassId(urlTokens.at(3)); if (deviceClassId.isNull()) { qCWarning(dcRest) << "Could not parse DeviceClassId:" << urlTokens.at(3); - return createErrorReply(HttpReply::BadRequest); + return createDeviceErrorReply(HttpReply::BadRequest, DeviceManager::DeviceErrorDeviceClassNotFound); } m_deviceClass = GuhCore::instance()->findDeviceClass(deviceClassId); if (!m_deviceClass.isValid()) { qCWarning(dcRest) << "DeviceClassId" << deviceClassId.toString() << "not found"; - return createErrorReply(HttpReply::NotFound); + return createDeviceErrorReply(HttpReply::NotFound, DeviceManager::DeviceErrorDeviceClassNotFound); } } @@ -81,7 +81,7 @@ HttpReply *DeviceClassesResource::proccessGetRequest(const HttpRequest &request, vendorId = VendorId(request.urlQuery().queryItemValue("vendorId")); if (vendorId.isNull()) { qCWarning(dcRest) << "Could not parse VendorId:" << request.urlQuery().queryItemValue("vendorId"); - return createErrorReply(HttpReply::BadRequest); + return createDeviceErrorReply(HttpReply::BadRequest, DeviceManager::DeviceErrorVendorNotFound); } } } @@ -101,7 +101,7 @@ HttpReply *DeviceClassesResource::proccessGetRequest(const HttpRequest &request, ActionTypeId actionTypeId = ActionTypeId(urlTokens.at(5)); if (actionTypeId.isNull()) { qCWarning(dcRest) << "Could not parse ActionTypeId:" << urlTokens.at(5); - return createErrorReply(HttpReply::BadRequest); + return createDeviceErrorReply(HttpReply::BadRequest, DeviceManager::DeviceErrorActionTypeNotFound); } return getActionType(actionTypeId); } @@ -115,7 +115,7 @@ HttpReply *DeviceClassesResource::proccessGetRequest(const HttpRequest &request, StateTypeId stateTypeId = StateTypeId(urlTokens.at(5)); if (stateTypeId.isNull()) { qCWarning(dcRest) << "Could not parse StateTypeId:" << urlTokens.at(5); - return createErrorReply(HttpReply::BadRequest); + return createDeviceErrorReply(HttpReply::BadRequest, DeviceManager::DeviceErrorStateTypeNotFound); } return getStateType(stateTypeId); } @@ -129,7 +129,7 @@ HttpReply *DeviceClassesResource::proccessGetRequest(const HttpRequest &request, EventTypeId eventTypeId = EventTypeId(urlTokens.at(5)); if (eventTypeId.isNull()) { qCWarning(dcRest) << "Could not parse EventTypeId:" << urlTokens.at(5); - return createErrorReply(HttpReply::BadRequest); + return createDeviceErrorReply(HttpReply::BadRequest, DeviceManager::DeviceErrorEventTypeNotFound); } return getEventType(eventTypeId); } @@ -182,7 +182,7 @@ HttpReply *DeviceClassesResource::getActionType(const ActionTypeId &actionTypeId return reply; } } - return createErrorReply(HttpReply::NotFound); + return createDeviceErrorReply(HttpReply::NotFound, DeviceManager::DeviceErrorActionTypeNotFound); } HttpReply *DeviceClassesResource::getStateTypes() @@ -206,7 +206,7 @@ HttpReply *DeviceClassesResource::getStateType(const StateTypeId &stateTypeId) return reply; } } - return createErrorReply(HttpReply::NotFound); + return createDeviceErrorReply(HttpReply::NotFound, DeviceManager::DeviceErrorStateTypeNotFound); } HttpReply *DeviceClassesResource::getEventTypes() @@ -230,7 +230,7 @@ HttpReply *DeviceClassesResource::getEventType(const EventTypeId &eventTypeId) return reply; } } - return createErrorReply(HttpReply::NotFound); + return createDeviceErrorReply(HttpReply::NotFound, DeviceManager::DeviceErrorEventTypeNotFound); } HttpReply *DeviceClassesResource::getDiscoverdDevices(const ParamList &discoveryParams) @@ -247,7 +247,7 @@ HttpReply *DeviceClassesResource::getDiscoverdDevices(const ParamList &discovery } if (status != DeviceManager::DeviceErrorNoError) - return createErrorReply(HttpReply::InternalServerError); + return createDeviceErrorReply(HttpReply::InternalServerError, status); return createSuccessReply(); } diff --git a/server/rest/devicesresource.cpp b/server/rest/devicesresource.cpp index 13d33ca5..67925569 100644 --- a/server/rest/devicesresource.cpp +++ b/server/rest/devicesresource.cpp @@ -51,12 +51,12 @@ HttpReply *DevicesResource::proccessRequest(const HttpRequest &request, const QS DeviceId deviceId = DeviceId(urlTokens.at(3)); if (deviceId.isNull()) { qCWarning(dcRest) << "Could not parse DeviceId:" << urlTokens.at(3); - return createErrorReply(HttpReply::BadRequest); + return createDeviceErrorReply(HttpReply::BadRequest, DeviceManager::DeviceErrorDeviceNotFound); } m_device = GuhCore::instance()->findConfiguredDevice(deviceId); if (!m_device) { qCWarning(dcRest) << "Could find any device with DeviceId:" << urlTokens.at(3); - return createErrorReply(HttpReply::NotFound); + return createDeviceErrorReply(HttpReply::NotFound, DeviceManager::DeviceErrorDeviceNotFound); } } @@ -106,12 +106,12 @@ HttpReply *DevicesResource::proccessGetRequest(const HttpRequest &request, const StateTypeId stateTypeId = StateTypeId(urlTokens.at(5)); if (stateTypeId.isNull()) { qCWarning(dcRest) << "Could not parse StateTypeId:" << urlTokens.at(5); - return createErrorReply(HttpReply::BadRequest); + return createDeviceErrorReply(HttpReply::BadRequest, DeviceManager::DeviceErrorStateTypeNotFound); } if (!m_device->hasState(stateTypeId)){ qCWarning(dcRest) << "This device has no StateTypeId:" << urlTokens.at(5); - return createErrorReply(HttpReply::NotFound); + return createDeviceErrorReply(HttpReply::NotFound, DeviceManager::DeviceErrorStateTypeNotFound); } return getDeviceStateValue(m_device, stateTypeId); } @@ -172,7 +172,7 @@ HttpReply *DevicesResource::proccessPostRequest(const HttpRequest &request, cons ActionTypeId actionTypeId = ActionTypeId(urlTokens.at(5)); if (actionTypeId.isNull()) { qCWarning(dcRest) << "Could not parse ActionTypeId:" << urlTokens.at(5); - return createErrorReply(HttpReply::BadRequest); + return createDeviceErrorReply(HttpReply::BadRequest, DeviceManager::DeviceErrorActionTypeNotFound); } bool found = false; DeviceClass deviceClass = GuhCore::instance()->findDeviceClass(m_device->deviceClassId()); @@ -184,7 +184,7 @@ HttpReply *DevicesResource::proccessPostRequest(const HttpRequest &request, cons } if (!found) { qCWarning(dcRest) << "Could not find ActionTypeId:" << actionTypeId.toString(); - return createErrorReply(HttpReply::NotFound); + return createDeviceErrorReply(HttpReply::NotFound, DeviceManager::DeviceErrorActionTypeNotFound); } return executeAction(m_device, actionTypeId, request.payload()); @@ -263,10 +263,10 @@ HttpReply *DevicesResource::removeDevice(Device *device) const // TODO: /api/v1/devices/{deviceId}?ruleId={ruleId}&removePolicy={RemovePolicy} if (result == DeviceManager::DeviceErrorNoError) { - HttpReply *reply = createSuccessReply(); + HttpReply *reply = createDeviceErrorReply(HttpReply::Ok, result); return reply; } - return createErrorReply(HttpReply::Forbidden); + return createDeviceErrorReply(HttpReply::BadRequest, result); } HttpReply *DevicesResource::executeAction(Device *device, const ActionTypeId &actionTypeId, const QByteArray &payload) const @@ -295,9 +295,9 @@ HttpReply *DevicesResource::executeAction(Device *device, const ActionTypeId &ac } if (status != DeviceManager::DeviceErrorNoError) - return createErrorReply(HttpReply::InternalServerError); + return createDeviceErrorReply(HttpReply::InternalServerError, status); - return createSuccessReply(); + return createDeviceErrorReply(HttpReply::Ok, status); } HttpReply *DevicesResource::addConfiguredDevice(const QByteArray &payload) const @@ -310,7 +310,7 @@ HttpReply *DevicesResource::addConfiguredDevice(const QByteArray &payload) const DeviceClassId deviceClassId(params.value("deviceClassId").toString()); if (deviceClassId.isNull()) - return createErrorReply(HttpReply::BadRequest); + return createDeviceErrorReply(HttpReply::BadRequest, DeviceManager::DeviceErrorDeviceClassNotFound); DeviceId newDeviceId = DeviceId::createDeviceId(); ParamList deviceParams = JsonTypes::unpackParams(params.value("deviceParams").toList()); @@ -332,7 +332,7 @@ HttpReply *DevicesResource::addConfiguredDevice(const QByteArray &payload) const } if (status != DeviceManager::DeviceErrorNoError) - return createErrorReply(HttpReply::InternalServerError); + return createDeviceErrorReply(HttpReply::InternalServerError, status); QVariant result = JsonTypes::packDevice(GuhCore::instance()->findConfiguredDevice(newDeviceId)); HttpReply *reply = createSuccessReply(); @@ -354,7 +354,7 @@ HttpReply *DevicesResource::pairDevice(const QByteArray &payload) const if (deviceClassId.isNull()) { qCWarning(dcRest) << "Could not find deviceClassId" << params.value("deviceClassId").toString(); - return createErrorReply(HttpReply::BadRequest); + return createDeviceErrorReply(HttpReply::BadRequest, DeviceManager::DeviceErrorDeviceClassNotFound); } qCDebug(dcRest) << "Pair device with deviceClassId" << deviceClassId.toString(); @@ -370,7 +370,7 @@ HttpReply *DevicesResource::pairDevice(const QByteArray &payload) const } if (status != DeviceManager::DeviceErrorNoError) - return createErrorReply(HttpReply::BadRequest); + return createDeviceErrorReply(HttpReply::BadRequest, status); QVariantMap returns; returns.insert("displayMessage", deviceClass.pairingInfo()); @@ -402,9 +402,9 @@ HttpReply *DevicesResource::confirmPairDevice(const QByteArray &payload) const } if (status != DeviceManager::DeviceErrorNoError) - return createErrorReply(HttpReply::InternalServerError); + return createDeviceErrorReply(HttpReply::InternalServerError, status); - return createSuccessReply(); + return createDeviceErrorReply(HttpReply::Ok, DeviceManager::DeviceErrorNoError); } HttpReply *DevicesResource::editDevice(Device *device, const QByteArray &payload) const @@ -435,9 +435,9 @@ HttpReply *DevicesResource::editDevice(Device *device, const QByteArray &payload } if (status != DeviceManager::DeviceErrorNoError) - return createErrorReply(HttpReply::InternalServerError); + return createDeviceErrorReply(HttpReply::InternalServerError, status); - return createSuccessReply(); + return createDeviceErrorReply(HttpReply::Ok, DeviceManager::DeviceErrorNoError); } void DevicesResource::actionExecuted(const ActionId &actionId, DeviceManager::DeviceError status) @@ -445,13 +445,21 @@ void DevicesResource::actionExecuted(const ActionId &actionId, DeviceManager::De if (!m_asyncActionExecutions.contains(actionId)) return; // Not the action we are waiting for. + QVariantMap response; + response.insert("error", JsonTypes::deviceErrorToString(status)); + HttpReply *reply = m_asyncActionExecutions.take(actionId); + reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";"); if (status == DeviceManager::DeviceErrorNoError) { qCDebug(dcRest) << "Action execution finished successfully"; reply->setHttpStatusCode(HttpReply::Ok); + reply->setPayload(QJsonDocument::fromVariant(response).toJson()); } else { qCDebug(dcRest) << "Action execution finished with error" << status; + QVariantMap response; + response.insert("error", JsonTypes::deviceErrorToString(status)); reply->setHttpStatusCode(HttpReply::InternalServerError); + reply->setPayload(QJsonDocument::fromVariant(response).toJson()); } reply->finished(); @@ -462,13 +470,19 @@ void DevicesResource::deviceSetupFinished(Device *device, DeviceManager::DeviceE if (!m_asyncDeviceAdditions.contains(device->id())) return; // Not the device we are waiting for. + QVariantMap response; + response.insert("error", JsonTypes::deviceErrorToString(status)); + HttpReply *reply = m_asyncDeviceAdditions.take(device->id()); + reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";"); if (status == DeviceManager::DeviceErrorNoError) { qCDebug(dcRest) << "Device setup finished successfully"; reply->setHttpStatusCode(HttpReply::Ok); + reply->setPayload(QJsonDocument::fromVariant(response).toJson()); } else { qCDebug(dcRest) << "Device setup finished with error" << status; reply->setHttpStatusCode(HttpReply::InternalServerError); + reply->setPayload(QJsonDocument::fromVariant(response).toJson()); } QVariant result = JsonTypes::packDevice(device); @@ -482,13 +496,19 @@ void DevicesResource::deviceEditFinished(Device *device, DeviceManager::DeviceEr if (!m_asyncEditDevice.contains(device)) return; // Not the device we are waiting for. + QVariantMap response; + response.insert("error", JsonTypes::deviceErrorToString(status)); + HttpReply *reply = m_asyncEditDevice.take(device); + reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";"); if (status == DeviceManager::DeviceErrorNoError) { qCDebug(dcRest) << "Device edit finished successfully"; reply->setHttpStatusCode(HttpReply::Ok); + reply->setPayload(QJsonDocument::fromVariant(response).toJson()); } else { qCDebug(dcRest) << "Device edit finished with error" << status; reply->setHttpStatusCode(HttpReply::InternalServerError); + reply->setPayload(QJsonDocument::fromVariant(response).toJson()); } reply->finished(); @@ -499,10 +519,15 @@ void DevicesResource::pairingFinished(const PairingTransactionId &pairingTransac if (!m_asyncPairingRequests.contains(pairingTransactionId)) return; // Not the device pairing we are waiting for. + QVariantMap response; + response.insert("error", JsonTypes::deviceErrorToString(status)); + HttpReply *reply = m_asyncPairingRequests.take(pairingTransactionId); if (status != DeviceManager::DeviceErrorNoError) { qCDebug(dcRest) << "Pairing device finished with error."; + reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";"); reply->setHttpStatusCode(HttpReply::InternalServerError); + reply->setPayload(QJsonDocument::fromVariant(response).toJson()); reply->finished(); return; } diff --git a/server/rest/restresource.cpp b/server/rest/restresource.cpp index 8a2ff2cb..6b4bfebf 100644 --- a/server/rest/restresource.cpp +++ b/server/rest/restresource.cpp @@ -60,6 +60,7 @@ #include "restresource.h" #include "httprequest.h" #include "loggingcategories.h" +#include "devicemanager.h" #include "guhcore.h" #include @@ -105,6 +106,37 @@ HttpReply *RestResource::createErrorReply(const HttpReply::HttpStatusCode &statu return reply; } +/*! Returns the pointer to a new created error \l{HttpReply} initialized with the given \a statusCode, \l{HttpReply::TypeSync} and the \a deviceError. */ +HttpReply *RestResource::createDeviceErrorReply(const HttpReply::HttpStatusCode &statusCode, const DeviceManager::DeviceError &deviceError) +{ + HttpReply *reply = new HttpReply(statusCode, HttpReply::TypeSync); + QVariantMap response; + response.insert("error", JsonTypes::deviceErrorToString(deviceError)); + reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";"); + reply->setPayload(QJsonDocument::fromVariant(response).toJson()); + return reply; +} + +HttpReply *RestResource::createRuleErrorReply(const HttpReply::HttpStatusCode &statusCode, const RuleEngine::RuleError &ruleError) +{ + HttpReply *reply = new HttpReply(statusCode, HttpReply::TypeSync); + QVariantMap response; + response.insert("error", JsonTypes::ruleErrorToString(ruleError)); + reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";"); + reply->setPayload(QJsonDocument::fromVariant(response).toJson()); + return reply; +} + +HttpReply *RestResource::createLoggingErrorReply(const HttpReply::HttpStatusCode &statusCode, const Logging::LoggingError &loggingError) +{ + HttpReply *reply = new HttpReply(statusCode, HttpReply::TypeSync); + QVariantMap response; + response.insert("error", JsonTypes::loggingErrorToString(loggingError)); + reply->setHeader(HttpReply::ContentTypeHeader, "application/json; charset=\"utf-8\";"); + reply->setPayload(QJsonDocument::fromVariant(response).toJson()); + return reply; +} + /*! Returns the pointer to a new created \l{HttpReply} initialized with \l{HttpReply::Ok} and \l{HttpReply::TypeAsync}. */ HttpReply *RestResource::createAsyncReply() { diff --git a/server/rest/restresource.h b/server/rest/restresource.h index 954b3ac9..6d9f6c4f 100644 --- a/server/rest/restresource.h +++ b/server/rest/restresource.h @@ -26,6 +26,7 @@ #include "httpreply.h" #include "httprequest.h" +#include "jsontypes.h" class QVariant; @@ -45,6 +46,9 @@ public: static HttpReply *createSuccessReply(); static HttpReply *createCorsSuccessReply(); static HttpReply *createErrorReply(const HttpReply::HttpStatusCode &statusCode); + static HttpReply *createDeviceErrorReply(const HttpReply::HttpStatusCode &statusCode, const DeviceManager::DeviceError &deviceError); + static HttpReply *createRuleErrorReply(const HttpReply::HttpStatusCode &statusCode, const RuleEngine::RuleError &ruleError); + static HttpReply *createLoggingErrorReply(const HttpReply::HttpStatusCode &statusCode, const Logging::LoggingError &loggingError); static HttpReply *createAsyncReply(); static QPair verifyPayload(const QByteArray &payload); diff --git a/tests/auto/api.json b/tests/auto/api.json index 48037efb..95d77cd2 100644 --- a/tests/auto/api.json +++ b/tests/auto/api.json @@ -566,6 +566,7 @@ "DeviceError": [ "DeviceErrorNoError", "DeviceErrorPluginNotFound", + "DeviceErrorVendorNotFound", "DeviceErrorDeviceNotFound", "DeviceErrorDeviceClassNotFound", "DeviceErrorActionTypeNotFound",