diff --git a/debian/changelog b/debian/changelog index eee6047a..4dbbd4df 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,8 @@ +nymea (0.17.0) UNRELEASED; urgency=medium + + + -- Michael Zanetti Wed, 30 Oct 2019 00:32:48 +0100 + nymea (0.16.0) xenial; urgency=medium [ Michael Zanetti ] * Add account interface diff --git a/libnymea-core/devices/devicemanagerimplementation.cpp b/libnymea-core/devices/devicemanagerimplementation.cpp index bb079ad6..6148930a 100644 --- a/libnymea-core/devices/devicemanagerimplementation.cpp +++ b/libnymea-core/devices/devicemanagerimplementation.cpp @@ -865,6 +865,43 @@ QString DeviceManagerImplementation::translate(const PluginId &pluginId, const Q return m_translator->translate(pluginId, string, locale); } +ParamType DeviceManagerImplementation::translateParamType(const PluginId &pluginId, const ParamType ¶mType, const QLocale &locale) +{ + ParamType translatedParamType = paramType; + translatedParamType.setDisplayName(translate(pluginId, paramType.displayName(), locale)); + return translatedParamType; +} + +DeviceClass DeviceManagerImplementation::translateDeviceClass(const DeviceClass &deviceClass, const QLocale &locale) +{ + DeviceClass translatedDeviceClass = deviceClass; + translatedDeviceClass.setDisplayName(translate(deviceClass.pluginId(), deviceClass.displayName(), locale)); + + ParamTypes translatedSettingsTypes; + foreach (const ParamType ¶mType, deviceClass.settingsTypes()) { + translatedSettingsTypes.append(translateParamType(deviceClass.pluginId(), paramType, locale)); + } + translatedDeviceClass.setSettingsTypes(translatedSettingsTypes); + return translatedDeviceClass; +} + +Vendor DeviceManagerImplementation::translateVendor(const Vendor &vendor, const QLocale &locale) +{ + DevicePlugin *plugin = nullptr; + foreach (DevicePlugin *p, m_devicePlugins) { + if (p->supportedVendors().contains(vendor)) { + plugin = p; + } + } + if (!plugin) { + return vendor; + } + + Vendor translatedVendor = vendor; + translatedVendor.setDisplayName(translate(plugin->pluginId(), vendor.displayName(), locale)); + return translatedVendor; +} + /*! Returns the \l{Device} with the given \a id. Null if the id couldn't be found. */ Device *DeviceManagerImplementation::findConfiguredDevice(const DeviceId &id) const { diff --git a/libnymea-core/devices/devicemanagerimplementation.h b/libnymea-core/devices/devicemanagerimplementation.h index 0d40756d..b3e7918e 100644 --- a/libnymea-core/devices/devicemanagerimplementation.h +++ b/libnymea-core/devices/devicemanagerimplementation.h @@ -107,6 +107,9 @@ public: BrowserItemActionInfo *executeBrowserItemAction(const BrowserItemAction &browserItemAction) override; QString translate(const PluginId &pluginId, const QString &string, const QLocale &locale) override; + ParamType translateParamType(const PluginId &pluginId, const ParamType ¶mType, const QLocale &locale) override; + DeviceClass translateDeviceClass(const DeviceClass &deviceClass, const QLocale &locale) override; + Vendor translateVendor(const Vendor &vendor, const QLocale &locale) override; signals: void loaded(); diff --git a/libnymea-core/devices/translator.cpp b/libnymea-core/devices/translator.cpp index 16f2c6b1..f6e38b37 100644 --- a/libnymea-core/devices/translator.cpp +++ b/libnymea-core/devices/translator.cpp @@ -48,6 +48,10 @@ Translator::~Translator() QString Translator::translate(const PluginId &pluginId, const QString &string, const QLocale &locale) { DevicePlugin *plugin = m_deviceManager->plugins().findById(pluginId); + if (!plugin) { + qCWarning(dcDeviceManager()) << "Unable to translate" << string << "Plugin not found"; + return string; + } if (!m_translatorContexts.contains(plugin->pluginId()) || !m_translatorContexts.value(plugin->pluginId()).translators.contains(locale.name())) { loadTranslator(plugin, locale); diff --git a/libnymea-core/experiences/experiencemanager.cpp b/libnymea-core/experiences/experiencemanager.cpp new file mode 100644 index 00000000..88d86f23 --- /dev/null +++ b/libnymea-core/experiences/experiencemanager.cpp @@ -0,0 +1,100 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2019 Michael Zanetti * + * * + * This file is part of nymea. * + * * + * nymea 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. * + * * + * nymea 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 nymea. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "experiencemanager.h" +#include "experiences/experienceplugin.h" + +#include "jsonrpc/jsonrpcserverimplementation.h" +#include "loggingcategories.h" + +#include +#include +#include +#include + +namespace nymeaserver { + +ExperienceManager::ExperienceManager(DeviceManager *deviceManager, JsonRPCServer *jsonRpcServer, QObject *parent) : QObject(parent), + m_deviceManager(deviceManager), + m_jsonRpcServer(jsonRpcServer) +{ + staticMetaObject.invokeMethod(this, "loadPlugins", Qt::QueuedConnection); +} + +void ExperienceManager::loadPlugins() +{ + foreach (const QString &path, pluginSearchDirs()) { + QDir dir(path); + qCDebug(dcExperiences) << "Loading experience plugins from:" << dir.absolutePath(); + foreach (const QString &entry, dir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot)) { + QFileInfo fi(path + "/" + entry); + if (fi.isFile()) { + if (entry.startsWith("libnymea_experienceplugin") && entry.endsWith(".so")) { + loadExperiencePlugin(path + "/" + entry); + } + } else if (fi.isDir()) { + if (QFileInfo::exists(path + "/" + entry + "/libnymea_experienceplugin" + entry + ".so")) { + loadExperiencePlugin(path + "/" + entry + "/libnymea_experienceplugin" + entry + ".so"); + } + } + } + } +} + +QStringList ExperienceManager::pluginSearchDirs() const +{ + QStringList searchDirs; + QByteArray envPath = qgetenv("NYMEA_EXPERIENCE_PLUGINS_PATH"); + if (!envPath.isEmpty()) { + searchDirs << QString(envPath).split(':'); + } + + foreach (QString libraryPath, QCoreApplication::libraryPaths()) { + searchDirs << libraryPath.replace("qt5", "nymea").replace("plugins", "experiences"); + } + searchDirs << QCoreApplication::applicationDirPath() + "/../lib/nymea/experiences"; + searchDirs << QCoreApplication::applicationDirPath() + "/../experiences/"; + searchDirs << QCoreApplication::applicationDirPath() + "/../../../experiences/"; + return searchDirs; +} + +void ExperienceManager::loadExperiencePlugin(const QString &file) +{ + QPluginLoader loader; + loader.setFileName(file); + loader.setLoadHints(QLibrary::ResolveAllSymbolsHint); + if (!loader.load()) { + qCWarning(dcExperiences()) << loader.errorString(); + return; + } + ExperiencePlugin *plugin = qobject_cast(loader.instance()); + if (!plugin) { + qCWarning(dcExperiences()) << "Could not get plugin instance of" << loader.fileName(); + loader.unload(); + return; + } + qCDebug(dcExperiences()) << "Loaded experience plugin:" << loader.fileName(); + m_plugins.append(plugin); + plugin->setParent(this); + plugin->initPlugin(m_deviceManager, m_jsonRpcServer); + +} + +} diff --git a/libnymea-core/experiences/experiencemanager.h b/libnymea-core/experiences/experiencemanager.h new file mode 100644 index 00000000..d5b7a373 --- /dev/null +++ b/libnymea-core/experiences/experiencemanager.h @@ -0,0 +1,59 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2019 Michael Zanetti * + * * + * This file is part of nymea. * + * * + * nymea 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. * + * * + * nymea 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 nymea. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef EXPERIENCEMANAGER_H +#define EXPERIENCEMANAGER_H + +#include + +class ExperiencePlugin; +class JsonRPCServer; +class DeviceManager; + +namespace nymeaserver { + +class ExperienceManager : public QObject +{ + Q_OBJECT +public: + explicit ExperienceManager(DeviceManager *deviceManager, JsonRPCServer *jsonRpcServer, QObject *parent = nullptr); + +signals: + +public slots: + +private slots: + void loadPlugins(); + +private: + QStringList pluginSearchDirs() const; + +private: + DeviceManager *m_deviceManager = nullptr; + JsonRPCServer *m_jsonRpcServer = nullptr; + + void loadExperiencePlugin(const QString &file); + +private: + QList m_plugins; +}; + +} +#endif // EXPERIENCEMANAGER_H diff --git a/libnymea-core/jsonrpc/actionhandler.cpp b/libnymea-core/jsonrpc/actionhandler.cpp index 5a56f3b3..eafe3cff 100644 --- a/libnymea-core/jsonrpc/actionhandler.cpp +++ b/libnymea-core/jsonrpc/actionhandler.cpp @@ -40,6 +40,7 @@ #include "devices/browseractioninfo.h" #include "devices/browseritemactioninfo.h" #include "types/action.h" +#include "types/actiontype.h" #include "loggingcategories.h" namespace nymeaserver { @@ -48,41 +49,48 @@ namespace nymeaserver { ActionHandler::ActionHandler(QObject *parent) : JsonHandler(parent) { - QVariantMap params; - QVariantMap returns; + // Enums + registerEnum(); + registerEnum(); + + // Objects + registerObject(); + registerObject(); + registerObject(); + registerObject(); + + // Methods + QString description; QVariantMap params; QVariantMap returns; + description = "Execute a single action."; + params.insert("actionTypeId", enumValueName(Uuid)); + params.insert("deviceId", enumValueName(Uuid)); + params.insert("o:params", objectRef()); + returns.insert("deviceError", enumRef()); + returns.insert("o:displayMessage", enumValueName(String)); + registerMethod("ExecuteAction", description, params, returns, "Please use Devices.ExecuteAction instead."); params.clear(); returns.clear(); - setDescription("ExecuteAction", "Execute a single action."); - setParams("ExecuteAction", JsonTypes::actionDescription()); - returns.insert("deviceError", JsonTypes::deviceErrorRef()); - returns.insert("o:displayMessage", JsonTypes::basicTypeToString(JsonTypes::String)); - setReturns("ExecuteAction", returns); + description = "Get the ActionType for the given ActionTypeId."; + params.insert("actionTypeId", enumValueName(Uuid)); + returns.insert("deviceError", enumRef()); + returns.insert("o:actionType", objectRef()); + registerMethod("GetActionType", description, params, returns, "Please use the Devices namespace instead."); params.clear(); returns.clear(); - setDescription("GetActionType", "Get the ActionType for the given ActionTypeId"); - params.insert("actionTypeId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setParams("GetActionType", params); - returns.insert("deviceError", JsonTypes::deviceErrorRef()); - returns.insert("o:actionType", JsonTypes::actionTypeDescription()); - setReturns("GetActionType", returns); + description = "Execute the item identified by itemId on the given device."; + params.insert("deviceId", enumValueName(Uuid)); + params.insert("itemId", enumValueName(String)); + returns.insert("deviceError", enumRef()); + registerMethod("ExecuteBrowserItem", description, params, returns, "Please use Devices.ExecuteBrowserItem instead."); params.clear(); returns.clear(); - setDescription("ExecuteBrowserItem", "Execute the item identified by itemId on the given device."); - params.insert("deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("itemId", JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("ExecuteBrowserItem", params); - returns.insert("deviceError", JsonTypes::deviceErrorRef()); - setReturns("ExecuteBrowserItem", returns); - - params.clear(); returns.clear(); - setDescription("ExecuteBrowserItemAction", "Execute the action for the browser item identified by actionTypeId and the itemId on the given device."); - params.insert("deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("itemId", JsonTypes::basicTypeToString(JsonTypes::String)); - params.insert("actionTypeId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("o:params", QVariantList() << JsonTypes::paramRef()); - setParams("ExecuteBrowserItemAction", params); - returns.insert("deviceError", JsonTypes::deviceErrorRef()); - setReturns("ExecuteBrowserItemAction", returns); + description = "Execute the action for the browser item identified by actionTypeId and the itemId on the given device."; + params.insert("deviceId", enumValueName(Uuid)); + params.insert("itemId", enumValueName(String)); + params.insert("actionTypeId", enumValueName(Uuid)); + params.insert("o:params", objectRef()); + returns.insert("deviceError", enumRef()); + registerMethod("ExecuteBrowserItemAction", description, params, returns, "Please use Devices.ExecuteBrowserItem instead."); } @@ -96,7 +104,7 @@ JsonReply* ActionHandler::ExecuteAction(const QVariantMap ¶ms) { DeviceId deviceId(params.value("deviceId").toString()); ActionTypeId actionTypeId(params.value("actionTypeId").toString()); - ParamList actionParams = JsonTypes::unpackParams(params.value("params").toList()); + ParamList actionParams = unpack(params.value("params")); QLocale locale = params.value("locale").toLocale(); Action action(actionTypeId, deviceId); @@ -105,8 +113,9 @@ JsonReply* ActionHandler::ExecuteAction(const QVariantMap ¶ms) JsonReply *jsonReply = createAsyncReply("ExecuteAction"); DeviceActionInfo *info = NymeaCore::instance()->executeAction(action); - connect(info, &DeviceActionInfo::finished, jsonReply, [this, info, jsonReply, locale](){ - QVariantMap data = statusToReply(info->status()); + connect(info, &DeviceActionInfo::finished, jsonReply, [info, jsonReply, locale](){ + QVariantMap data; + data.insert("deviceError", enumValueName(info->status())); if (!info->displayMessage().isEmpty()) { data.insert("displayMessage", info->translatedDisplayMessage(locale)); } @@ -119,18 +128,25 @@ JsonReply* ActionHandler::ExecuteAction(const QVariantMap ¶ms) JsonReply *ActionHandler::GetActionType(const QVariantMap ¶ms) const { + QLocale locale = params.value("locale").toLocale(); qCDebug(dcJsonRpc) << "asked for action type" << params; ActionTypeId actionTypeId(params.value("actionTypeId").toString()); foreach (const DeviceClass &deviceClass, NymeaCore::instance()->deviceManager()->supportedDevices()) { foreach (const ActionType &actionType, deviceClass.actionTypes()) { if (actionType.id() == actionTypeId) { - QVariantMap data = statusToReply(Device::DeviceErrorNoError); - data.insert("actionType", JsonTypes::packActionType(actionType, deviceClass.pluginId(), params.value("locale").toLocale())); + ActionType translatedActionType = actionType; + translatedActionType.setDisplayName(NymeaCore::instance()->deviceManager()->translate(deviceClass.pluginId(), actionType.displayName(), locale)); + + QVariantMap data; + data.insert("deviceError", enumValueName(Device::DeviceErrorNoError)); + data.insert("actionType", pack(translatedActionType)); return createReply(data); } } } - return createReply(statusToReply(Device::DeviceErrorActionTypeNotFound)); + QVariantMap data; + data.insert("deviceError", enumValueName(Device::DeviceErrorActionTypeNotFound)); + return createReply(data); } JsonReply *ActionHandler::ExecuteBrowserItem(const QVariantMap ¶ms) @@ -142,8 +158,10 @@ JsonReply *ActionHandler::ExecuteBrowserItem(const QVariantMap ¶ms) JsonReply *jsonReply = createAsyncReply("ExecuteBrowserItem"); BrowserActionInfo *info = NymeaCore::instance()->executeBrowserItem(action); - connect(info, &BrowserActionInfo::finished, jsonReply, [this, info, jsonReply](){ - jsonReply->setData(statusToReply(info->status())); + connect(info, &BrowserActionInfo::finished, jsonReply, [info, jsonReply](){ + QVariantMap data; + data.insert("deviceError", enumValueName(info->status())); + jsonReply->setData(data); jsonReply->finished(); }); @@ -155,14 +173,16 @@ JsonReply *ActionHandler::ExecuteBrowserItemAction(const QVariantMap ¶ms) DeviceId deviceId = DeviceId(params.value("deviceId").toString()); QString itemId = params.value("itemId").toString(); ActionTypeId actionTypeId = ActionTypeId(params.value("actionTypeId").toString()); - ParamList paramList = JsonTypes::unpackParams(params.value("params").toList()); + ParamList paramList = unpack(params.value("params")); BrowserItemAction browserItemAction(deviceId, itemId, actionTypeId, paramList); JsonReply *jsonReply = createAsyncReply("ExecuteBrowserItemAction"); BrowserItemActionInfo *info = NymeaCore::instance()->executeBrowserItemAction(browserItemAction); - connect(info, &BrowserItemActionInfo::finished, jsonReply, [this, info, jsonReply](){ - jsonReply->setData(statusToReply(info->status())); + connect(info, &BrowserItemActionInfo::finished, jsonReply, [info, jsonReply](){ + QVariantMap data; + data.insert("deviceError", enumValueName(info->status())); + jsonReply->setData(data); jsonReply->finished(); }); diff --git a/libnymea-core/jsonrpc/actionhandler.h b/libnymea-core/jsonrpc/actionhandler.h index da081871..d1cae8be 100644 --- a/libnymea-core/jsonrpc/actionhandler.h +++ b/libnymea-core/jsonrpc/actionhandler.h @@ -22,7 +22,7 @@ #ifndef ACTIONHANDLER_H #define ACTIONHANDLER_H -#include "jsonhandler.h" +#include "jsonrpc/jsonhandler.h" #include "devices/devicemanager.h" namespace nymeaserver { diff --git a/libnymea-core/jsonrpc/configurationhandler.cpp b/libnymea-core/jsonrpc/configurationhandler.cpp index 0ae065fc..faf2ebff 100644 --- a/libnymea-core/jsonrpc/configurationhandler.cpp +++ b/libnymea-core/jsonrpc/configurationhandler.cpp @@ -60,6 +60,7 @@ #include "configurationhandler.h" #include "nymeacore.h" +#include "nymeaconfiguration.h" namespace nymeaserver { @@ -67,229 +68,217 @@ namespace nymeaserver { ConfigurationHandler::ConfigurationHandler(QObject *parent): JsonHandler(parent) { + // Enums + registerEnum(); + + // Objects + registerObject(); + registerObject(); + registerObject(); + // Methods - QVariantMap params; QVariantMap returns; - setDescription("GetTimeZones", "Get the list of available timezones."); - setParams("GetTimeZones", params); - returns.insert("timeZones", QVariantList() << JsonTypes::basicTypeToString(JsonTypes::String)); - setReturns("GetTimeZones", returns); + QString description; QVariantMap params; QVariantMap returns; + description = "Get the list of available timezones."; + returns.insert("timeZones", QVariantList() << enumValueName(String)); + registerMethod("GetTimeZones", description, params, returns); params.clear(); returns.clear(); - setDescription("GetAvailableLanguages", "DEPRECATED - Use the locale property in the Handshake message instead - Returns a list of locale codes available for the server. i.e. en_US, de_AT"); - setParams("GetAvailableLanguages", params); - returns.insert("languages", QVariantList() << JsonTypes::basicTypeToString(JsonTypes::String)); - setReturns("GetAvailableLanguages", returns); + description = "DEPRECATED - Use the locale property in the Handshake message instead - Returns a list of locale codes available for the server. i.e. en_US, de_AT"; + returns.insert("languages", QVariantList() << enumValueName(String)); + registerMethod("GetAvailableLanguages", description, params, returns); params.clear(); returns.clear(); - setDescription("GetConfigurations", "Get all configuration parameters of the server."); - setParams("GetConfigurations", params); + description = "Get all configuration parameters of the server."; QVariantMap basicConfiguration; - basicConfiguration.insert("serverName", JsonTypes::basicTypeToString(JsonTypes::String)); - basicConfiguration.insert("serverUuid", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - basicConfiguration.insert("serverTime", JsonTypes::basicTypeToString(JsonTypes::Uint)); - basicConfiguration.insert("timeZone", JsonTypes::basicTypeToString(JsonTypes::String)); - basicConfiguration.insert("language", JsonTypes::basicTypeToString(JsonTypes::String)); - basicConfiguration.insert("debugServerEnabled", JsonTypes::basicTypeToString(JsonTypes::Bool)); + basicConfiguration.insert("serverName", enumValueName(String)); + basicConfiguration.insert("serverUuid", enumValueName(Uuid)); + basicConfiguration.insert("serverTime", enumValueName(Uint)); + basicConfiguration.insert("timeZone", enumValueName(String)); + basicConfiguration.insert("language", enumValueName(String)); + basicConfiguration.insert("debugServerEnabled", enumValueName(Bool)); returns.insert("basicConfiguration", basicConfiguration); QVariantList tcpServerConfigurations; - tcpServerConfigurations.append(JsonTypes::serverConfigurationRef()); + tcpServerConfigurations.append(objectRef()); returns.insert("tcpServerConfigurations", tcpServerConfigurations); QVariantList webServerConfigurations; - webServerConfigurations.append(JsonTypes::webServerConfigurationRef()); + webServerConfigurations.append(objectRef()); returns.insert("webServerConfigurations", webServerConfigurations); QVariantList webSocketServerConfigurations; - webSocketServerConfigurations.append(JsonTypes::serverConfigurationRef()); + webSocketServerConfigurations.append(objectRef()); returns.insert("webSocketServerConfigurations", webSocketServerConfigurations); QVariantList mqttServerConfigurations; - mqttServerConfigurations.append(JsonTypes::serverConfigurationRef()); + mqttServerConfigurations.append(objectRef()); QVariantMap cloudConfiguration; - cloudConfiguration.insert("enabled", JsonTypes::basicTypeToString(JsonTypes::Bool)); + cloudConfiguration.insert("enabled", enumValueName(Bool)); returns.insert("cloud", cloudConfiguration); - setReturns("GetConfigurations", returns); + registerMethod("GetConfigurations", description, params, returns); params.clear(); returns.clear(); - setDescription("SetServerName", "Set the name of the server. Default is nymea."); - params.insert("serverName", JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("SetServerName", params); - returns.insert("configurationError", JsonTypes::configurationErrorRef()); - setReturns("SetServerName", returns); + description = "Set the name of the server. Default is nymea."; + params.insert("serverName", enumValueName(String)); + returns.insert("configurationError", enumRef()); + registerMethod("SetServerName", description, params, returns); params.clear(); returns.clear(); - setDescription("SetTimeZone", "Set the time zone of the server. See also: \"GetTimeZones\""); - params.insert("timeZone", JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("SetTimeZone", params); - returns.insert("configurationError", JsonTypes::configurationErrorRef()); - setReturns("SetTimeZone", returns); + description = "Set the time zone of the server. See also: \"GetTimeZones\""; + params.insert("timeZone", enumValueName(String)); + returns.insert("configurationError", enumRef()); + registerMethod("SetTimeZone", description, params, returns); params.clear(); returns.clear(); - setDescription("SetLanguage", "DEPRECATED - Use the locale property in the Handshake message instead - Sets the server language to the given language. See also: \"GetAvailableLanguages\""); - params.insert("language", JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("SetLanguage", params); - returns.insert("configurationError", JsonTypes::configurationErrorRef()); - setReturns("SetLanguage", returns); + description = "DEPRECATED - Use the locale property in the Handshake message instead - Sets the server language to the given language. See also: \"GetAvailableLanguages\""; + params.insert("language", enumValueName(String)); + returns.insert("configurationError", enumRef()); + registerMethod("SetLanguage", description, params, returns); params.clear(); returns.clear(); - setDescription("SetDebugServerEnabled", "Enable or disable the debug server."); - params.insert("enabled", JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("SetDebugServerEnabled", params); - returns.insert("configurationError", JsonTypes::configurationErrorRef()); - setReturns("SetDebugServerEnabled", returns); + description = "Enable or disable the debug server."; + params.insert("enabled", enumValueName(String)); + returns.insert("configurationError", enumRef()); + registerMethod("SetDebugServerEnabled", description, params, returns); params.clear(); returns.clear(); - setDescription("SetTcpServerConfiguration", "Configure a TCP interface of the server. If the ID is an existing one, the existing config will be modified, otherwise a new one will be added. Note: if you are changing the configuration for the interface you are currently connected to, the connection will be dropped."); - params.insert("configuration", JsonTypes::serverConfigurationRef()); - setParams("SetTcpServerConfiguration", params); - returns.insert("configurationError", JsonTypes::configurationErrorRef()); - setReturns("SetTcpServerConfiguration", returns); + description = "Configure a TCP interface of the server. If the ID is an existing one, the existing config will be modified, otherwise a new one will be added. Note: if you are changing the configuration for the interface you are currently connected to, the connection will be dropped."; + params.insert("configuration", objectRef()); + returns.insert("configurationError", enumRef()); + registerMethod("SetTcpServerConfiguration", description, params, returns); params.clear(); returns.clear(); - setDescription("DeleteTcpServerConfiguration", "Delete a TCP interface of the server. Note: if you are deleting the configuration for the interface you are currently connected to, the connection will be dropped."); - params.insert("id", JsonTypes::basicTypeToString(QVariant::String)); - setParams("DeleteTcpServerConfiguration", params); - returns.insert("configurationError", JsonTypes::configurationErrorRef()); - setReturns("DeleteTcpServerConfiguration", returns); + description = "Delete a TCP interface of the server. Note: if you are deleting the configuration for the interface you are currently connected to, the connection will be dropped."; + params.insert("id", enumValueName(String)); + returns.insert("configurationError", enumRef()); + registerMethod("DeleteTcpServerConfiguration", description, params, returns); params.clear(); returns.clear(); - setDescription("SetWebSocketServerConfiguration", "Configure a WebSocket Server interface of the server. If the ID is an existing one, the existing config will be modified, otherwise a new one will be added. Note: if you are changing the configuration for the interface you are currently connected to, the connection will be dropped."); - params.insert("configuration", JsonTypes::serverConfigurationRef()); - setParams("SetWebSocketServerConfiguration", params); - returns.insert("configurationError", JsonTypes::configurationErrorRef()); - setReturns("SetWebSocketServerConfiguration", returns); + description = "Configure a WebSocket Server interface of the server. If the ID is an existing one, the existing config will be modified, otherwise a new one will be added. Note: if you are changing the configuration for the interface you are currently connected to, the connection will be dropped."; + params.insert("configuration", objectRef()); + returns.insert("configurationError", enumRef()); + registerMethod("SetWebSocketServerConfiguration", description, params, returns); params.clear(); returns.clear(); - setDescription("DeleteWebSocketServerConfiguration", "Delete a WebSocket Server interface of the server. Note: if you are deleting the configuration for the interface you are currently connected to, the connection will be dropped."); - params.insert("id", JsonTypes::basicTypeToString(QVariant::String)); - setParams("DeleteWebSocketServerConfiguration", params); - returns.insert("configurationError", JsonTypes::configurationErrorRef()); - setReturns("DeleteWebSocketServerConfiguration", returns); + description = "Delete a WebSocket Server interface of the server. Note: if you are deleting the configuration for the interface you are currently connected to, the connection will be dropped."; + params.insert("id", enumValueName(String)); + returns.insert("configurationError", enumRef()); + registerMethod("DeleteWebSocketServerConfiguration", description, params, returns); params.clear(); returns.clear(); - setDescription("SetWebServerConfiguration", "Configure a WebServer interface of the server. If the ID is an existing one, the existing config will be modified, otherwise a new one will be added."); - params.insert("configuration", JsonTypes::webServerConfigurationRef()); - setParams("SetWebServerConfiguration", params); - returns.insert("configurationError", JsonTypes::configurationErrorRef()); - setReturns("SetWebServerConfiguration", returns); + description = "Configure a WebServer interface of the server. If the ID is an existing one, the existing config will be modified, otherwise a new one will be added."; + params.insert("configuration", objectRef()); + returns.insert("configurationError", enumRef()); + registerMethod("SetWebServerConfiguration", description, params, returns); params.clear(); returns.clear(); - setDescription("DeleteWebServerConfiguration", "Delete a WebServer interface of the server."); - params.insert("id", JsonTypes::basicTypeToString(QVariant::String)); - setParams("DeleteWebServerConfiguration", params); - returns.insert("configurationError", JsonTypes::configurationErrorRef()); - setReturns("DeleteWebServerConfiguration", returns); + description = "Delete a WebServer interface of the server."; + params.insert("id", enumValueName(String)); + returns.insert("configurationError", enumRef()); + registerMethod("DeleteWebServerConfiguration", description, params, returns); params.clear(); returns.clear(); - setDescription("SetCloudEnabled", "Sets whether the cloud connection is enabled or disabled in the settings."); - params.insert("enabled", JsonTypes::basicTypeToString(QVariant::Bool)); - setParams("SetCloudEnabled", params); - returns.insert("configurationError", JsonTypes::configurationErrorRef()); - setReturns("SetCloudEnabled", returns); + description = "Sets whether the cloud connection is enabled or disabled in the settings."; + params.insert("enabled", enumValueName(Bool)); + returns.insert("configurationError", enumRef()); + registerMethod("SetCloudEnabled", description, params, returns); // MQTT params.clear(); returns.clear(); - setDescription("GetMqttServerConfigurations", "Get all MQTT Server configurations."); - setParams("GetMqttServerConfigurations", params); - returns.insert("mqttServerConfigurations", QVariantList() << JsonTypes::serverConfigurationRef()); - setReturns("GetMqttServerConfigurations", returns); + description = "Get all MQTT Server configurations."; + returns.insert("mqttServerConfigurations", QVariantList() << objectRef()); + registerMethod("GetMqttServerConfigurations", description, params, returns); params.clear(); returns.clear(); - setDescription("SetMqttServerConfiguration", "Configure a MQTT Server interface on the MQTT broker. If the ID is an existing one, the existing config will be modified, otherwise a new one will be added. Setting authenticationEnabled to true will require MQTT clients to use credentials set in the MQTT broker policies."); - params.insert("configuration", JsonTypes::serverConfigurationRef()); - setParams("SetMqttServerConfiguration", params); - returns.insert("configurationError", JsonTypes::configurationErrorRef()); - setReturns("SetMqttServerConfiguration", returns); + description = "Configure a MQTT Server interface on the MQTT broker. If the ID is an existing one, the existing config will be modified, otherwise a new one will be added. Setting authenticationEnabled to true will require MQTT clients to use credentials set in the MQTT broker policies."; + params.insert("configuration", objectRef()); + returns.insert("configurationError", enumRef()); + registerMethod("SetMqttServerConfiguration", description, params, returns); params.clear(); returns.clear(); - setDescription("DeleteMqttServerConfiguration", "Delete a MQTT Server interface of the server."); - params.insert("id", JsonTypes::basicTypeToString(QVariant::String)); - setParams("DeleteMqttServerConfiguration", params); - returns.insert("configurationError", JsonTypes::configurationErrorRef()); - setReturns("DeleteMqttServerConfiguration", returns); + description = "Delete a MQTT Server interface of the server."; + params.insert("id", enumValueName(String)); + returns.insert("configurationError", enumRef()); + registerMethod("DeleteMqttServerConfiguration", description, params, returns); params.clear(); returns.clear(); - setDescription("GetMqttPolicies", "Get all MQTT broker policies."); - setParams("GetMqttPolicies", params); - returns.insert("mqttPolicies", QVariantList() << JsonTypes::mqttPolicyRef()); - setReturns("GetMqttPolicies", returns); + description = "Get all MQTT broker policies."; + returns.insert("mqttPolicies", QVariantList() << objectRef()); + registerMethod("GetMqttPolicies", description, params, returns); params.clear(); returns.clear(); - setDescription("SetMqttPolicy", "Configure a MQTT broker policy. If the ID is an existing one, the existing policy will be modified, otherwise a new one will be added."); - params.insert("policy", JsonTypes::mqttPolicyRef()); - setParams("SetMqttPolicy", params); - returns.insert("configurationError", JsonTypes::configurationErrorRef()); - setReturns("SetMqttPolicy", returns); + description = "Configure a MQTT broker policy. If the ID is an existing one, the existing policy will be modified, otherwise a new one will be added."; + params.insert("policy", objectRef()); + returns.insert("configurationError", enumRef()); + registerMethod("SetMqttPolicy", description, params, returns); params.clear(); returns.clear(); - setDescription("DeleteMqttPolicy", "Delete a MQTT policy from the broker."); - params.insert("clientId", JsonTypes::basicTypeToString(QVariant::String)); - setParams("DeleteMqttPolicy", params); - returns.insert("configurationError", JsonTypes::configurationErrorRef()); - setReturns("DeleteMqttPolicy", returns); + description = "Delete a MQTT policy from the broker."; + params.insert("clientId", enumValueName(String)); + returns.insert("configurationError", enumRef()); + registerMethod("DeleteMqttPolicy", description, params, returns); // Notifications params.clear(); returns.clear(); - setDescription("BasicConfigurationChanged", "Emitted whenever the basic configuration of this server changes."); + description = "Emitted whenever the basic configuration of this server changes."; params.insert("basicConfiguration", basicConfiguration); - setParams("BasicConfigurationChanged", params); + registerNotification("BasicConfigurationChanged", description, params); params.clear(); returns.clear(); - setDescription("LanguageChanged", "Emitted whenever the language of the server changed. The Plugins, Vendors and DeviceClasses have to be reloaded to get the translated data."); - params.insert("language", JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("LanguageChanged", params); + description = "Emitted whenever the language of the server changed. The Plugins, Vendors and DeviceClasses have to be reloaded to get the translated data."; + params.insert("language", enumValueName(String)); + registerNotification("LanguageChanged", description, params); params.clear(); returns.clear(); - setDescription("TcpServerConfigurationChanged", "Emitted whenever the TCP server configuration changes."); - params.insert("tcpServerConfiguration", JsonTypes::serverConfigurationRef()); - setParams("TcpServerConfigurationChanged", params); + description = "Emitted whenever the TCP server configuration changes."; + params.insert("tcpServerConfiguration", objectRef()); + registerNotification("TcpServerConfigurationChanged", description, params); params.clear(); returns.clear(); - setDescription("TcpServerConfigurationRemoved", "Emitted whenever a TCP server configuration is removed."); - params.insert("id", JsonTypes::basicTypeToString(QVariant::String)); - setParams("TcpServerConfigurationRemoved", params); + description = "Emitted whenever a TCP server configuration is removed."; + params.insert("id", enumValueName(String)); + registerNotification("TcpServerConfigurationRemoved", description, params); params.clear(); returns.clear(); - setDescription("WebSocketServerConfigurationChanged", "Emitted whenever the web socket server configuration changes."); - params.insert("webSocketServerConfiguration", JsonTypes::serverConfigurationRef()); - setParams("WebSocketServerConfigurationChanged", params); + description = "Emitted whenever the web socket server configuration changes."; + params.insert("webSocketServerConfiguration", objectRef()); + registerNotification("WebSocketServerConfigurationChanged", description, params); params.clear(); returns.clear(); - setDescription("WebSocketServerConfigurationRemoved", "Emitted whenever a WebSocket server configuration is removed."); - params.insert("id", JsonTypes::basicTypeToString(QVariant::String)); - setParams("WebSocketServerConfigurationRemoved", params); + description = "Emitted whenever a WebSocket server configuration is removed."; + params.insert("id", enumValueName(String)); + registerNotification("WebSocketServerConfigurationRemoved", description, params); params.clear(); returns.clear(); - setDescription("MqttServerConfigurationChanged", "Emitted whenever the MQTT broker configuration is changed."); - params.insert("mqttServerConfiguration", JsonTypes::serverConfigurationRef()); - setParams("MqttServerConfigurationChanged", params); + description = "Emitted whenever the MQTT broker configuration is changed."; + params.insert("mqttServerConfiguration", objectRef()); + registerNotification("MqttServerConfigurationChanged", description, params); params.clear(); returns.clear(); - setDescription("MqttServerConfigurationRemoved", "Emitted whenever a MQTT server configuration is removed."); - params.insert("id", JsonTypes::basicTypeToString(QVariant::String)); - setParams("MqttServerConfigurationRemoved", params); + description = "Emitted whenever a MQTT server configuration is removed."; + params.insert("id", enumValueName(String)); + registerNotification("MqttServerConfigurationRemoved", description, params); params.clear(); returns.clear(); - setDescription("WebServerConfigurationChanged", "Emitted whenever the web server configuration changes."); - params.insert("webServerConfiguration", JsonTypes::webServerConfigurationRef()); - setParams("WebServerConfigurationChanged", params); + description = "Emitted whenever the web server configuration changes."; + params.insert("webServerConfiguration", objectRef()); + registerNotification("WebServerConfigurationChanged", description, params); params.clear(); returns.clear(); - setDescription("WebServerConfigurationRemoved", "Emitted whenever a Web server configuration is removed."); - params.insert("id", JsonTypes::basicTypeToString(QVariant::String)); - setParams("WebServerConfigurationRemoved", params); + description = "Emitted whenever a Web server configuration is removed."; + params.insert("id", enumValueName(String)); + registerNotification("WebServerConfigurationRemoved", description, params); params.clear(); returns.clear(); - setDescription("CloudConfigurationChanged", "Emitted whenever the cloud configuration is changed."); + description = "Emitted whenever the cloud configuration is changed."; params.insert("cloudConfiguration", cloudConfiguration); - setParams("CloudConfigurationChanged", params); + registerNotification("CloudConfigurationChanged", description, params); params.clear(); returns.clear(); - setDescription("MqttPolicyChanged", "Emitted whenever a MQTT broker policy is changed."); - params.insert("policy", JsonTypes::mqttPolicyRef()); - setParams("MqttPolicyChanged", params); + description = "Emitted whenever a MQTT broker policy is changed."; + params.insert("policy", objectRef()); + registerNotification("MqttPolicyChanged", description, params); params.clear(); returns.clear(); - setDescription("MqttPolicyRemoved", "Emitted whenever a MQTT broker policy is removed."); - params.insert("clientId", JsonTypes::basicTypeToString(QVariant::String)); - setParams("MqttPolicyRemoved", params); + description = "Emitted whenever a MQTT broker policy is removed."; + params.insert("clientId", enumValueName(String)); + registerNotification("MqttPolicyRemoved", description, params); connect(NymeaCore::instance()->configuration(), &NymeaConfiguration::serverNameChanged, this, &ConfigurationHandler::onBasicConfigurationChanged); connect(NymeaCore::instance()->configuration(), &NymeaConfiguration::timeZoneChanged, this, &ConfigurationHandler::onBasicConfigurationChanged); @@ -319,23 +308,23 @@ JsonReply *ConfigurationHandler::GetConfigurations(const QVariantMap ¶ms) co { Q_UNUSED(params) QVariantMap returns; - returns.insert("basicConfiguration", JsonTypes::packBasicConfiguration()); + returns.insert("basicConfiguration", packBasicConfiguration()); QVariantList tcpServerConfigs; foreach (const ServerConfiguration &config, NymeaCore::instance()->configuration()->tcpServerConfigurations()) { - tcpServerConfigs.append(JsonTypes::packServerConfiguration(config)); + tcpServerConfigs.append(pack(config)); } returns.insert("tcpServerConfigurations", tcpServerConfigs); QVariantList webServerConfigs; foreach (const WebServerConfiguration &config, NymeaCore::instance()->configuration()->webServerConfigurations()) { - webServerConfigs.append(JsonTypes::packWebServerConfiguration(config)); + webServerConfigs.append(pack(config)); } returns.insert("webServerConfigurations", webServerConfigs); QVariantList webSocketServerConfigs; foreach (const ServerConfiguration &config, NymeaCore::instance()->configuration()->webSocketServerConfigurations()) { - webSocketServerConfigs.append(JsonTypes::packServerConfiguration(config)); + webSocketServerConfigs.append(pack(config)); } returns.insert("webSocketServerConfigurations", webSocketServerConfigs); @@ -402,7 +391,7 @@ JsonReply *ConfigurationHandler::SetLanguage(const QVariantMap ¶ms) const JsonReply *ConfigurationHandler::SetTcpServerConfiguration(const QVariantMap ¶ms) const { - ServerConfiguration config = JsonTypes::unpackServerConfiguration(params.value("configuration").toMap()); + ServerConfiguration config = unpack(params.value("configuration").toMap()); if (config.id.isEmpty()) { return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidId)); } @@ -432,7 +421,7 @@ JsonReply *ConfigurationHandler::DeleteTcpServerConfiguration(const QVariantMap JsonReply *ConfigurationHandler::SetWebServerConfiguration(const QVariantMap ¶ms) const { - WebServerConfiguration config = JsonTypes::unpackWebServerConfiguration(params.value("configuration").toMap()); + WebServerConfiguration config = unpack(params.value("configuration").toMap()); if (config.id.isEmpty()) { return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidId)); @@ -463,7 +452,7 @@ JsonReply *ConfigurationHandler::DeleteWebServerConfiguration(const QVariantMap JsonReply *ConfigurationHandler::SetWebSocketServerConfiguration(const QVariantMap ¶ms) const { - ServerConfiguration config = JsonTypes::unpackServerConfiguration(params.value("configuration").toMap()); + ServerConfiguration config = unpack(params.value("configuration").toMap()); if (config.id.isEmpty()) { return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidId)); } @@ -498,7 +487,7 @@ JsonReply *ConfigurationHandler::GetMqttServerConfigurations(const QVariantMap & QVariantMap ret; QVariantList mqttServerConfigs; foreach (const ServerConfiguration &config, NymeaCore::instance()->configuration()->mqttServerConfigurations()) { - mqttServerConfigs << JsonTypes::packServerConfiguration(config); + mqttServerConfigs << pack(config); } ret.insert("mqttServerConfigurations", mqttServerConfigs); return createReply(ret); @@ -506,7 +495,7 @@ JsonReply *ConfigurationHandler::GetMqttServerConfigurations(const QVariantMap & JsonReply *ConfigurationHandler::SetMqttServerConfiguration(const QVariantMap ¶ms) const { - ServerConfiguration config = JsonTypes::unpackServerConfiguration(params.value("configuration").toMap()); + ServerConfiguration config = unpack(params.value("configuration").toMap()); if (config.id.isEmpty()) { return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidId)); } @@ -540,7 +529,7 @@ JsonReply *ConfigurationHandler::GetMqttPolicies(const QVariantMap ¶ms) cons Q_UNUSED(params) QVariantList mqttPolicies; foreach (const MqttPolicy &policy, NymeaCore::instance()->configuration()->mqttPolicies()) { - mqttPolicies << JsonTypes::packMqttPolicy(policy); + mqttPolicies << pack(policy); } QVariantMap ret; ret.insert("mqttPolicies", mqttPolicies); @@ -549,7 +538,7 @@ JsonReply *ConfigurationHandler::GetMqttPolicies(const QVariantMap ¶ms) cons JsonReply *ConfigurationHandler::SetMqttPolicy(const QVariantMap ¶ms) const { - MqttPolicy policy = JsonTypes::unpackMqttPolicy(params.value("policy").toMap()); + MqttPolicy policy = unpack(params.value("policy").toMap()); NymeaCore::instance()->configuration()->updateMqttPolicy(policy); return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorNoError)); } @@ -579,7 +568,7 @@ void ConfigurationHandler::onBasicConfigurationChanged() { qCDebug(dcJsonRpc()) << "Notification: Basic configuration changed"; QVariantMap params; - params.insert("basicConfiguration", JsonTypes::packBasicConfiguration()); + params.insert("basicConfiguration", packBasicConfiguration()); emit BasicConfigurationChanged(params); } @@ -587,7 +576,7 @@ void ConfigurationHandler::onTcpServerConfigurationChanged(const QString &id) { qCDebug(dcJsonRpc()) << "Notification: TCP server configuration changed"; QVariantMap params; - params.insert("tcpServerConfiguration", JsonTypes::packServerConfiguration(NymeaCore::instance()->configuration()->tcpServerConfigurations().value(id))); + params.insert("tcpServerConfiguration", pack(NymeaCore::instance()->configuration()->tcpServerConfigurations().value(id))); emit TcpServerConfigurationChanged(params); } @@ -603,7 +592,7 @@ void ConfigurationHandler::onWebServerConfigurationChanged(const QString &id) { qCDebug(dcJsonRpc()) << "Notification: web server configuration changed"; QVariantMap params; - params.insert("webServerConfiguration", JsonTypes::packWebServerConfiguration(NymeaCore::instance()->configuration()->webServerConfigurations().value(id))); + params.insert("webServerConfiguration", pack(NymeaCore::instance()->configuration()->webServerConfigurations().value(id))); emit WebServerConfigurationChanged(params); } @@ -619,7 +608,7 @@ void ConfigurationHandler::onWebSocketServerConfigurationChanged(const QString & { qCDebug(dcJsonRpc()) << "Notification: web socket server configuration changed"; QVariantMap params; - params.insert("webSocketServerConfiguration", JsonTypes::packServerConfiguration(NymeaCore::instance()->configuration()->webSocketServerConfigurations().value(id))); + params.insert("webSocketServerConfiguration", pack(NymeaCore::instance()->configuration()->webSocketServerConfigurations().value(id))); emit WebSocketServerConfigurationChanged(params); } @@ -635,7 +624,7 @@ void ConfigurationHandler::onMqttServerConfigurationChanged(const QString &id) { qCDebug(dcJsonRpc()) << "Notification: MQTT server configuration changed"; QVariantMap params; - params.insert("mqttServerConfiguration", JsonTypes::packServerConfiguration(NymeaCore::instance()->configuration()->mqttServerConfigurations().value(id))); + params.insert("mqttServerConfiguration", pack(NymeaCore::instance()->configuration()->mqttServerConfigurations().value(id))); emit MqttServerConfigurationChanged(params); } @@ -651,7 +640,7 @@ void ConfigurationHandler::onMqttPolicyChanged(const QString &clientId) { qCDebug(dcJsonRpc()) << "Notification: MQTT policy changed"; QVariantMap params; - params.insert("policy", JsonTypes::packMqttPolicy(NymeaCore::instance()->configuration()->mqttPolicies().value(clientId))); + params.insert("policy", pack(NymeaCore::instance()->configuration()->mqttPolicies().value(clientId))); emit MqttPolicyChanged(params); } @@ -663,6 +652,25 @@ void ConfigurationHandler::onMqttPolicyRemoved(const QString &clientId) emit MqttPolicyRemoved(params); } +QVariantMap ConfigurationHandler::packBasicConfiguration() +{ + QVariantMap basicConfiguration; + basicConfiguration.insert("serverName", NymeaCore::instance()->configuration()->serverName()); + basicConfiguration.insert("serverUuid", NymeaCore::instance()->configuration()->serverUuid().toString()); + basicConfiguration.insert("serverTime", NymeaCore::instance()->timeManager()->currentDateTime().toTime_t()); + basicConfiguration.insert("timeZone", QString::fromUtf8(NymeaCore::instance()->timeManager()->timeZone())); + basicConfiguration.insert("language", NymeaCore::instance()->configuration()->locale().name()); + basicConfiguration.insert("debugServerEnabled", NymeaCore::instance()->configuration()->debugServerEnabled()); + return basicConfiguration; +} + +QVariantMap ConfigurationHandler::statusToReply(NymeaConfiguration::ConfigurationError status) const +{ + QVariantMap returns; + returns.insert("configurationError", enumValueName(status)); + return returns; +} + void ConfigurationHandler::onCloudConfigurationChanged(bool enabled) { qCDebug(dcJsonRpc()) << "Notification: cloud configuration changed"; diff --git a/libnymea-core/jsonrpc/configurationhandler.h b/libnymea-core/jsonrpc/configurationhandler.h index e5ef0e07..d2fc4667 100644 --- a/libnymea-core/jsonrpc/configurationhandler.h +++ b/libnymea-core/jsonrpc/configurationhandler.h @@ -23,7 +23,8 @@ #include -#include "jsonhandler.h" +#include "jsonrpc/jsonhandler.h" +#include "nymeaconfiguration.h" namespace nymeaserver { @@ -88,6 +89,11 @@ private slots: void onMqttServerConfigurationRemoved(const QString &id); void onMqttPolicyChanged(const QString &clientId); void onMqttPolicyRemoved(const QString &clientId); + +private: + static QVariantMap packBasicConfiguration(); + QVariantMap statusToReply(NymeaConfiguration::ConfigurationError status) const; + }; } diff --git a/libnymea-core/jsonrpc/devicehandler.cpp b/libnymea-core/jsonrpc/devicehandler.cpp index ea06a221..367b0c88 100644 --- a/libnymea-core/jsonrpc/devicehandler.cpp +++ b/libnymea-core/jsonrpc/devicehandler.cpp @@ -60,6 +60,8 @@ #include "devices/deviceplugin.h" #include "loggingcategories.h" #include "types/deviceclass.h" +#include "types/browseritem.h" +#include "types/mediabrowseritem.h" #include "devices/translator.h" #include "devices/devicediscoveryinfo.h" #include "devices/devicepairinginfo.h" @@ -75,74 +77,96 @@ namespace nymeaserver { DeviceHandler::DeviceHandler(QObject *parent) : JsonHandler(parent) { - QVariantMap returns; - QVariantMap params; + // Enums + registerEnum(); + registerEnum(); + registerEnum(); + registerEnum(); + registerEnum(); + registerEnum(); + registerEnum(); + registerEnum(); + + // Objects + registerObject(); + registerObject(); + registerUncreatableObject(); + registerObject(); + registerObject(); + registerObject(); + registerObject(); + registerObject(); + registerObject(); + registerObject(); + registerObject(); + registerObject(); + registerUncreatableObject(); + + // Regsitering browseritem manually for now. Not sure how to deal with the + // polymorphism in int (e.g MediaBrowserItem) + QVariantMap browserItem; + browserItem.insert("id", enumValueName(String)); + browserItem.insert("displayName", enumValueName(String)); + browserItem.insert("description", enumValueName(String)); + browserItem.insert("icon", enumRef()); + browserItem.insert("thumbnail", enumValueName(String)); + browserItem.insert("executable", enumValueName(Bool)); + browserItem.insert("browsable", enumValueName(Bool)); + browserItem.insert("disabled", enumValueName(Bool)); + browserItem.insert("actionTypeIds", QVariantList() << enumValueName(Uuid)); + browserItem.insert("o:mediaIcon", enumRef()); + registerObject("BrowserItem", browserItem); + + + // Methods + QString description; QVariantMap returns; QVariantMap params; + description = "Returns a list of supported Vendors."; + returns.insert("vendors", objectRef()); + registerMethod("GetSupportedVendors", description, params, returns); params.clear(); returns.clear(); - setDescription("GetSupportedVendors", "Returns a list of supported Vendors."); - setParams("GetSupportedVendors", params); - QVariantList vendors; - vendors.append(JsonTypes::vendorRef()); - returns.insert("vendors", vendors); - setReturns("GetSupportedVendors", returns); + description = "Returns a list of supported Device classes, optionally filtered by vendorId."; + params.insert("o:vendorId", enumValueName(Uuid)); + returns.insert("deviceClasses", objectRef()); + registerMethod("GetSupportedDevices", description, params, returns); params.clear(); returns.clear(); - setDescription("GetSupportedDevices", "Returns a list of supported Device classes, optionally filtered by vendorId."); - params.insert("o:vendorId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setParams("GetSupportedDevices", params); - QVariantList deviceClasses; - deviceClasses.append(JsonTypes::deviceClassRef()); - returns.insert("deviceClasses", deviceClasses); - setReturns("GetSupportedDevices", returns); + description = "Returns a list of loaded plugins."; + returns.insert("plugins", objectRef()); + registerMethod("GetPlugins", description, params, returns); params.clear(); returns.clear(); - setDescription("GetPlugins", "Returns a list of loaded plugins."); - setParams("GetPlugins", params); - QVariantList plugins; - plugins.append(JsonTypes::pluginRef()); - returns.insert("plugins", plugins); - setReturns("GetPlugins", returns); + description = "Get a plugin's params."; + params.insert("pluginId", enumValueName(Uuid)); + returns.insert("deviceError", enumRef()); + returns.insert("o:configuration", objectRef()); + registerMethod("GetPluginConfiguration", description, params, returns); params.clear(); returns.clear(); - setDescription("GetPluginConfiguration", "Get a plugin's params."); - params.insert("pluginId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setParams("GetPluginConfiguration", params); - QVariantList pluginParams; - pluginParams.append(JsonTypes::paramRef()); - returns.insert("deviceError", JsonTypes::deviceErrorRef()); - returns.insert("o:configuration", pluginParams); - setReturns("GetPluginConfiguration", returns); + description = "Set a plugin's params."; + params.insert("pluginId", enumValueName(Uuid)); + params.insert("configuration", objectRef()); + returns.insert("deviceError", enumRef()); + registerMethod("SetPluginConfiguration", description, params, returns); params.clear(); returns.clear(); - setDescription("SetPluginConfiguration", "Set a plugin's params."); - params.insert("pluginId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("configuration", pluginParams); - setParams("SetPluginConfiguration", params); - returns.insert("deviceError", JsonTypes::deviceErrorRef()); - setReturns("SetPluginConfiguration", returns); - - params.clear(); returns.clear(); - setDescription("AddConfiguredDevice", "Add a configured device with a setupMethod of SetupMethodJustAdd. " + description = "Add a configured device with a setupMethod of SetupMethodJustAdd. " "For devices with a setupMethod different than SetupMethodJustAdd, use PairDevice. " "Devices with CreateMethodJustAdd require all parameters to be supplied here. " "Devices with CreateMethodDiscovery require the use of a deviceDescriptorId. For discovered " "devices params are not required and will be taken from the DeviceDescriptor, however, they " - "may be overridden by supplying deviceParams." - ); - params.insert("deviceClassId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("name", JsonTypes::basicTypeToString(JsonTypes::String)); - params.insert("o:deviceDescriptorId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - QVariantList deviceParams; - deviceParams.append(JsonTypes::paramRef()); - params.insert("o:deviceParams", deviceParams); - setParams("AddConfiguredDevice", params); - returns.insert("deviceError", JsonTypes::deviceErrorRef()); - returns.insert("o:deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - returns.insert("o:displayMessage", JsonTypes::basicTypeToString(JsonTypes::String)); - setReturns("AddConfiguredDevice", returns); + "may be overridden by supplying deviceParams."; + params.insert("deviceClassId", enumValueName(Uuid)); + params.insert("name", enumValueName(String)); + params.insert("o:deviceDescriptorId", enumValueName(Uuid)); + params.insert("o:deviceParams", objectRef()); + returns.insert("deviceError", enumRef()); + returns.insert("o:deviceId", enumValueName(Uuid)); + returns.insert("o:displayMessage", enumValueName(String)); + registerMethod("AddConfiguredDevice", description, params, returns); params.clear(); returns.clear(); - setDescription("PairDevice", "Pair a device. " + description = "Pair a device. " "Use this to set up or reconfigure devices for DeviceClasses with a setupMethod different than SetupMethodJustAdd. " "Depending on the CreateMethod and whether a new devices is set up or an existing one is reconfigured, different parameters " "are required:\n" @@ -158,215 +182,215 @@ DeviceHandler::DeviceHandler(QObject *parent) : "mask for a user and password login should be presented to the user. In case of SetupMethodOAuth, an OAuth URL will be returned " "which shall be opened in a web view to allow the user logging in.\n" "Once the login procedure has completed, the application shall proceed with ConfirmPairing, providing the results of the pairing " - "procedure." - ); - params.insert("o:deviceClassId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("o:name", JsonTypes::basicTypeToString(JsonTypes::String)); - params.insert("o:deviceDescriptorId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("o:deviceParams", deviceParams); - params.insert("o:deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setParams("PairDevice", params); - returns.insert("deviceError", JsonTypes::deviceErrorRef()); - returns.insert("o:setupMethod", JsonTypes::setupMethodRef()); - returns.insert("o:pairingTransactionId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - returns.insert("o:displayMessage", JsonTypes::basicTypeToString(JsonTypes::String)); - returns.insert("o:oAuthUrl", JsonTypes::basicTypeToString(JsonTypes::String)); - returns.insert("o:pin", JsonTypes::basicTypeToString(JsonTypes::String)); - setReturns("PairDevice", returns); + "procedure."; + params.insert("o:deviceClassId", enumValueName(Uuid)); + params.insert("o:name", enumValueName(String)); + params.insert("o:deviceDescriptorId", enumValueName(Uuid)); + params.insert("o:deviceParams", objectRef()); + params.insert("o:deviceId", enumValueName(Uuid)); + returns.insert("deviceError", enumRef()); + returns.insert("o:setupMethod", enumRef()); + returns.insert("o:pairingTransactionId", enumValueName(Uuid)); + returns.insert("o:displayMessage", enumValueName(String)); + returns.insert("o:oAuthUrl", enumValueName(String)); + returns.insert("o:pin", enumValueName(String)); + registerMethod("PairDevice", description, params, returns); params.clear(); returns.clear(); - setDescription("ConfirmPairing", "Confirm an ongoing pairing. For SetupMethodUserAndPassword, provide the username in the \"username\" field " + description = "Confirm an ongoing pairing. For SetupMethodUserAndPassword, provide the username in the \"username\" field " "and the password in the \"secret\" field. For SetupMethodEnterPin and provide the PIN in the \"secret\" " "field. In case of SetupMethodOAuth, the previously opened web view will eventually be redirected to http://128.0.0.1:8888 " - "and the OAuth code as query parameters to this url. Provide the entire unmodified URL in the secret field."); - params.insert("pairingTransactionId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("o:username", JsonTypes::basicTypeToString(JsonTypes::String)); - params.insert("o:secret", JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("ConfirmPairing", params); - returns.insert("deviceError", JsonTypes::deviceErrorRef()); - returns.insert("o:displayMessage", JsonTypes::basicTypeToString(JsonTypes::String)); - returns.insert("o:deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setReturns("ConfirmPairing", returns); + "and the OAuth code as query parameters to this url. Provide the entire unmodified URL in the secret field."; + params.insert("pairingTransactionId", enumValueName(Uuid)); + params.insert("o:username", enumValueName(String)); + params.insert("o:secret", enumValueName(String)); + returns.insert("deviceError", enumRef()); + returns.insert("o:displayMessage", enumValueName(String)); + returns.insert("o:deviceId", enumValueName(Uuid)); + registerMethod("ConfirmPairing", description, params, returns); params.clear(); returns.clear(); - setDescription("GetConfiguredDevices", "Returns a list of configured devices, optionally filtered by deviceId."); - params.insert("o:deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setParams("GetConfiguredDevices", params); - QVariantList devices; - devices.append(JsonTypes::deviceRef()); - returns.insert("devices", devices); - setReturns("GetConfiguredDevices", returns); + description = "Returns a list of configured devices, optionally filtered by deviceId."; + params.insert("o:deviceId", enumValueName(Uuid)); + returns.insert("devices", objectRef()); + registerMethod("GetConfiguredDevices", description, params, returns); params.clear(); returns.clear(); - setDescription("GetDiscoveredDevices", "Performs a device discovery and returns the results. This function may take a while to return. " + description = "Performs a device discovery and returns the results. This function may take a while to return. " "Note that this method will include all the found devices, that is, including devices that may " "already have been added. Those devices will have deviceId set to the device id of the already " "added device. Such results may be used to reconfigure existing devices and might be filtered " - "in cases where only unknown devices are of interest."); - params.insert("deviceClassId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - QVariantList discoveryParams; - discoveryParams.append(JsonTypes::paramRef()); - params.insert("o:discoveryParams", discoveryParams); - setParams("GetDiscoveredDevices", params); - returns.insert("deviceError", JsonTypes::deviceErrorRef()); - returns.insert("o:displayMessage", JsonTypes::basicTypeToString(JsonTypes::String)); - QVariantList deviceDescriptors; - deviceDescriptors.append(JsonTypes::deviceDescriptorRef()); - returns.insert("o:deviceDescriptors", deviceDescriptors); - setReturns("GetDiscoveredDevices", returns); + "in cases where only unknown devices are of interest."; + params.insert("deviceClassId", enumValueName(Uuid)); + params.insert("o:discoveryParams", objectRef()); + returns.insert("deviceError", enumRef()); + returns.insert("o:displayMessage", enumValueName(String)); + returns.insert("o:deviceDescriptors", objectRef()); + registerMethod("GetDiscoveredDevices", description, params, returns); params.clear(); returns.clear(); - setDescription("ReconfigureDevice", "Reconfigure a device. This comes down to removing and recreating a device with new parameters " - "but keeping its device id the same (and with that keeping rules, tags etc). For devices with " - "create method CreateMethodDiscovery, a discovery (GetDiscoveredDevices) shall be performed first " - "and this method is to be called with a deviceDescriptorId of the re-discovered device instead of " - "the deviceId directly. Device parameters will be taken from the discovery, but can be overridden " - "individually here by providing them in the deviceParams parameter. Only writable parameters can " - "be changed."); - params.insert("o:deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("o:deviceDescriptorId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - QVariantList newDeviceParams; - newDeviceParams.append(JsonTypes::paramRef()); - params.insert("o:deviceParams", newDeviceParams); - setParams("ReconfigureDevice", params); - returns.insert("deviceError", JsonTypes::deviceErrorRef()); - returns.insert("o:displayMessage", JsonTypes::basicTypeToString(JsonTypes::String)); - setReturns("ReconfigureDevice", returns); + description = "Reconfigure a device. This comes down to removing and recreating a device with new parameters " + "but keeping its device id the same (and with that keeping rules, tags etc). For devices with " + "create method CreateMethodDiscovery, a discovery (GetDiscoveredDevices) shall be performed first " + "and this method is to be called with a deviceDescriptorId of the re-discovered device instead of " + "the deviceId directly. Device parameters will be taken from the discovery, but can be overridden " + "individually here by providing them in the deviceParams parameter. Only writable parameters can " + "be changed."; + params.insert("o:deviceId", enumValueName(Uuid)); + params.insert("o:deviceDescriptorId", enumValueName(Uuid)); + params.insert("o:deviceParams", objectRef()); + returns.insert("deviceError", enumRef()); + returns.insert("o:displayMessage", enumValueName(String)); + registerMethod("ReconfigureDevice", description, params, returns); params.clear(); returns.clear(); - setDescription("EditDevice", "Edit the name of a device. This method does not change the " - "configuration of the device."); - params.insert("deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("name", JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("EditDevice", params); - returns.insert("deviceError", JsonTypes::deviceErrorRef()); - setReturns("EditDevice", returns); + description = "Edit the name of a device. This method does not change the " + "configuration of the device."; + params.insert("deviceId", enumValueName(Uuid)); + params.insert("name", enumValueName(String)); + returns.insert("deviceError", enumRef()); + registerMethod("EditDevice", description, params, returns); params.clear(); returns.clear(); - setDescription("SetDeviceSettings", "Change the settings of a device."); - params.insert("deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("settings", QVariantList() << JsonTypes::paramRef()); - setParams("SetDeviceSettings", params); - returns.insert("deviceError", JsonTypes::deviceErrorRef()); - setReturns("SetDeviceSettings", returns); + description = "Change the settings of a device."; + params.insert("deviceId", enumValueName(Uuid)); + params.insert("settings", objectRef()); + returns.insert("deviceError", enumRef()); + registerMethod("SetDeviceSettings", description, params, returns); params.clear(); returns.clear(); - setDescription("RemoveConfiguredDevice", "Remove a device from the system."); - params.insert("deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - QVariantList removePolicyList; + description = "Remove a device from the system."; + params.insert("deviceId", enumValueName(Uuid)); + params.insert("o:removePolicy", enumRef()); QVariantMap policy; - policy.insert("ruleId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - policy.insert("policy", JsonTypes::removePolicyRef()); + policy.insert("ruleId", enumValueName(Uuid)); + policy.insert("policy", enumRef()); + QVariantList removePolicyList; removePolicyList.append(policy); - params.insert("o:removePolicy", JsonTypes::removePolicyRef()); params.insert("o:removePolicyList", removePolicyList); - setParams("RemoveConfiguredDevice", params); - returns.insert("deviceError", JsonTypes::deviceErrorRef()); - returns.insert("o:ruleIds", QVariantList() << JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setReturns("RemoveConfiguredDevice", returns); + returns.insert("deviceError", enumRef()); + returns.insert("o:ruleIds", QVariantList() << enumValueName(Uuid)); + registerMethod("RemoveConfiguredDevice", description, params, returns); params.clear(); returns.clear(); - setDescription("GetEventTypes", "Get event types for a specified deviceClassId."); - params.insert("deviceClassId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setParams("GetEventTypes", params); - QVariantList events; - events.append(JsonTypes::eventTypeRef()); - returns.insert("eventTypes", events); - setReturns("GetEventTypes", returns); + description = "Get event types for a specified deviceClassId."; + params.insert("deviceClassId", enumValueName(Uuid)); + returns.insert("eventTypes", objectRef()); + registerMethod("GetEventTypes", description, params, returns); params.clear(); returns.clear(); - setDescription("GetActionTypes", "Get action types for a specified deviceClassId."); - params.insert("deviceClassId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setParams("GetActionTypes", params); - QVariantList actions; - actions.append(JsonTypes::actionTypeRef()); - returns.insert("actionTypes", actions); - setReturns("GetActionTypes", returns); + description = "Get action types for a specified deviceClassId."; + params.insert("deviceClassId", enumValueName(Uuid)); + returns.insert("actionTypes", objectRef()); + registerMethod("GetActionTypes", description, params, returns); params.clear(); returns.clear(); - setDescription("GetStateTypes", "Get state types for a specified deviceClassId."); - params.insert("deviceClassId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setParams("GetStateTypes", params); - QVariantList states; - states.append(JsonTypes::stateTypeRef()); - returns.insert("stateTypes", states); - setReturns("GetStateTypes", returns); + description = "Get state types for a specified deviceClassId."; + params.insert("deviceClassId", enumValueName(Uuid)); + returns.insert("stateTypes", objectRef()); + registerMethod("GetStateTypes", description, params, returns); params.clear(); returns.clear(); - setDescription("GetStateValue", "Get the value of the given device and the given stateType"); - params.insert("deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("stateTypeId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setParams("GetStateValue", params); - returns.insert("deviceError", JsonTypes::deviceErrorRef()); - returns.insert("o:value", JsonTypes::basicTypeToString(JsonTypes::Variant)); - setReturns("GetStateValue", returns); + description = "Get the value of the given device and the given stateType"; + params.insert("deviceId", enumValueName(Uuid)); + params.insert("stateTypeId", enumValueName(Uuid)); + returns.insert("deviceError", enumRef()); + returns.insert("o:value", enumValueName(Variant)); + registerMethod("GetStateValue", description, params, returns); params.clear(); returns.clear(); - setDescription("GetStateValues", "Get all the state values of the given device."); - params.insert("deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setParams("GetStateValues", params); - returns.insert("deviceError", JsonTypes::deviceErrorRef()); - states.clear(); - QVariantMap state; - state.insert("stateTypeId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - state.insert("value", JsonTypes::basicTypeToString(JsonTypes::Variant)); - states.append(state); - returns.insert("o:values", states); - setReturns("GetStateValues", returns); + description = "Get all the state values of the given device."; + params.insert("deviceId", enumValueName(Uuid)); + returns.insert("deviceError", enumRef()); + returns.insert("o:values", objectRef()); + registerMethod("GetStateValues", description, params, returns); params.clear(); returns.clear(); - setDescription("BrowseDevice", "Browse a device. If a DeviceClass indicates a device is browsable, this method will return the BrowserItems. If no parameter besides the deviceId is used, the root node of this device will be returned. Any returned item which is browsable can be passed as node. Results will be children of the given node."); - params.insert("deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("o:itemId", JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("BrowseDevice", params); - returns.insert("deviceError", JsonTypes::deviceErrorRef()); - returns.insert("items", QVariantList() << JsonTypes::browserItemRef()); - setReturns("BrowseDevice", returns); + description = "Browse a device. If a DeviceClass indicates a device is browsable, this method will return the BrowserItems. If no parameter besides the deviceId is used, the root node of this device will be returned. Any returned item which is browsable can be passed as node. Results will be children of the given node."; + params.insert("deviceId", enumValueName(Uuid)); + params.insert("o:itemId", enumValueName(String)); + returns.insert("deviceError", enumRef()); + returns.insert("items", QVariantList() << objectRef("BrowserItem")); + registerMethod("BrowseDevice", description, params, returns); params.clear(); returns.clear(); - setDescription("GetBrowserItem", "Get a single item from the browser. This won't give any more info on an item than a regular browseDevice call, but it allows to fetch details of an item if only the ID is known."); - params.insert("deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("o:itemId", JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("GetBrowserItem", params); - returns.insert("deviceError", JsonTypes::deviceErrorRef()); - returns.insert("o:item", JsonTypes::browserItemRef()); - setReturns("GetBrowserItem", returns); + description = "Get a single item from the browser. This won't give any more info on an item than a regular browseDevice call, but it allows to fetch details of an item if only the ID is known."; + params.insert("deviceId", enumValueName(Uuid)); + params.insert("o:itemId", enumValueName(String)); + returns.insert("deviceError", enumRef()); + returns.insert("o:item", objectRef("BrowserItem")); + registerMethod("GetBrowserItem", description, params, returns); + + params.clear(); returns.clear(); + description = "Execute a single action."; + params.insert("actionTypeId", enumValueName(Uuid)); + params.insert("deviceId", enumValueName(Uuid)); + params.insert("o:params", objectRef()); + returns.insert("deviceError", enumRef()); + returns.insert("o:displayMessage", enumValueName(String)); + registerMethod("ExecuteAction", description, params, returns); + + params.clear(); returns.clear(); + description = "Execute the item identified by itemId on the given device."; + params.insert("deviceId", enumValueName(Uuid)); + params.insert("itemId", enumValueName(String)); + returns.insert("deviceError", enumRef()); + registerMethod("ExecuteBrowserItem", description, params, returns); + + params.clear(); returns.clear(); + description = "Execute the action for the browser item identified by actionTypeId and the itemId on the given device."; + params.insert("deviceId", enumValueName(Uuid)); + params.insert("itemId", enumValueName(String)); + params.insert("actionTypeId", enumValueName(Uuid)); + params.insert("o:params", objectRef()); + returns.insert("deviceError", enumRef()); + registerMethod("ExecuteBrowserItemAction", description, params, returns); // Notifications params.clear(); returns.clear(); - setDescription("StateChanged", "Emitted whenever a State of a device changes."); - params.insert("deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("stateTypeId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("value", JsonTypes::basicTypeToString(JsonTypes::Variant)); - setParams("StateChanged", params); + description = "Emitted whenever a State of a device changes."; + params.insert("deviceId", enumValueName(Uuid)); + params.insert("stateTypeId", enumValueName(Uuid)); + params.insert("value", enumValueName(Variant)); + registerNotification("StateChanged", description, params); params.clear(); returns.clear(); - setDescription("DeviceRemoved", "Emitted whenever a Device was removed."); - params.insert("deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setParams("DeviceRemoved", params); + description = "Emitted whenever a Device was removed."; + params.insert("deviceId", enumValueName(Uuid)); + registerNotification("DeviceRemoved", description, params); params.clear(); returns.clear(); - setDescription("DeviceAdded", "Emitted whenever a Device was added."); - params.insert("device", JsonTypes::deviceRef()); - setParams("DeviceAdded", params); + description = "Emitted whenever a Device was added."; + params.insert("device", objectRef()); + registerNotification("DeviceAdded", description, params); params.clear(); returns.clear(); - setDescription("DeviceChanged", "Emitted whenever the params or name of a Device are changed (by EditDevice or ReconfigureDevice)."); - params.insert("device", JsonTypes::deviceRef()); - setParams("DeviceChanged", params); + description = "Emitted whenever the params or name of a Device are changed (by EditDevice or ReconfigureDevice)."; + params.insert("device", objectRef()); + registerNotification("DeviceChanged", description, params); params.clear(); returns.clear(); - setDescription("DeviceSettingChanged", "Emitted whenever the setting of a Device is changed."); - params.insert("deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("paramTypeId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("value", JsonTypes::basicTypeToString(JsonTypes::Variant)); - setParams("DeviceSettingChanged", params); + description = "Emitted whenever the setting of a Device is changed."; + params.insert("deviceId", enumValueName(Uuid)); + params.insert("paramTypeId", enumValueName(Uuid)); + params.insert("value", enumValueName(Variant)); + registerNotification("DeviceSettingChanged", description, params); params.clear(); returns.clear(); - setDescription("PluginConfigurationChanged", "Emitted whenever a plugin's configuration is changed."); - params.insert("pluginId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("configuration", QVariantList() << JsonTypes::paramRef()); - setParams("PluginConfigurationChanged", params); + description = "Emitted whenever a plugin's configuration is changed."; + params.insert("pluginId", enumValueName(Uuid)); + params.insert("configuration", objectRef()); + registerNotification("PluginConfigurationChanged", description, params); + + params.clear(); returns.clear(); + description = "Emitted whenever an Event is triggered."; + params.insert("event", objectRef()); + registerNotification("EventTriggered", description, params); + connect(NymeaCore::instance(), &NymeaCore::eventTriggered, this, [this](const Event &event){ + QVariantMap params; + params.insert("event", pack(event)); + emit EventTriggered(params); + }); connect(NymeaCore::instance(), &NymeaCore::pluginConfigChanged, this, &DeviceHandler::pluginConfigChanged); connect(NymeaCore::instance(), &NymeaCore::deviceStateChanged, this, &DeviceHandler::deviceStateChanged); @@ -384,17 +408,31 @@ QString DeviceHandler::name() const JsonReply* DeviceHandler::GetSupportedVendors(const QVariantMap ¶ms) const { - Q_UNUSED(params) + QLocale locale = params.value("locale").toLocale(); + + QVariantList vendors; + foreach (const Vendor &vendor, NymeaCore::instance()->deviceManager()->supportedVendors()) { + Vendor translatedVendor = NymeaCore::instance()->deviceManager()->translateVendor(vendor, locale); + vendors.append(pack(translatedVendor)); + } QVariantMap returns; - returns.insert("vendors", JsonTypes::packSupportedVendors(params.value("locale").toLocale())); + returns.insert("vendors", vendors); return createReply(returns); } JsonReply* DeviceHandler::GetSupportedDevices(const QVariantMap ¶ms) const { + QLocale locale = params.value("locale").toLocale(); + VendorId vendorId = VendorId(params.value("vendorId").toString()); QVariantMap returns; - returns.insert("deviceClasses", JsonTypes::packSupportedDevices(VendorId(params.value("vendorId").toString()), params.value("locale").toLocale())); + QVariantList deviceClasses; + foreach (const DeviceClass &deviceClass, NymeaCore::instance()->deviceManager()->supportedDevices(vendorId)) { + DeviceClass translatedDeviceClass = NymeaCore::instance()->deviceManager()->translateDeviceClass(deviceClass, locale); + deviceClasses.append(pack(translatedDeviceClass)); + } + + returns.insert("deviceClasses", deviceClasses); return createReply(returns); } @@ -405,17 +443,20 @@ JsonReply *DeviceHandler::GetDiscoveredDevices(const QVariantMap ¶ms) const QVariantMap returns; DeviceClassId deviceClassId = DeviceClassId(params.value("deviceClassId").toString()); - - ParamList discoveryParams = JsonTypes::unpackParams(params.value("discoveryParams").toList()); + ParamList discoveryParams = unpack(params.value("discoveryParams")); JsonReply *reply = createAsyncReply("GetDiscoveredDevices"); DeviceDiscoveryInfo *info = NymeaCore::instance()->deviceManager()->discoverDevices(deviceClassId, discoveryParams); - connect(info, &DeviceDiscoveryInfo::finished, reply, [reply, info, locale](){ + connect(info, &DeviceDiscoveryInfo::finished, reply, [this, reply, info, locale](){ QVariantMap returns; - returns.insert("deviceError", JsonTypes::deviceErrorToString(info->status())); + returns.insert("deviceError", enumValueName(info->status())); if (info->status() == Device::DeviceErrorNoError) { - returns.insert("deviceDescriptors", JsonTypes::packDeviceDescriptors(info->deviceDescriptors())); + QVariantList deviceDescriptorList; + foreach (const DeviceDescriptor &deviceDescriptor, info->deviceDescriptors()) { + deviceDescriptorList.append(pack(deviceDescriptor)); + } + returns.insert("deviceDescriptors", deviceDescriptorList); } if (!info->displayMessage().isEmpty()) { @@ -431,10 +472,17 @@ JsonReply *DeviceHandler::GetDiscoveredDevices(const QVariantMap ¶ms) const JsonReply* DeviceHandler::GetPlugins(const QVariantMap ¶ms) const { - Q_UNUSED(params) + QLocale locale = params.value("locale").toLocale(); + + QVariantList plugins; + foreach (DevicePlugin* plugin, NymeaCore::instance()->deviceManager()->plugins()) { + QVariantMap packedPlugin = pack(*plugin).toMap(); + packedPlugin["displayName"] = NymeaCore::instance()->deviceManager()->translate(plugin->pluginId(), plugin->pluginDisplayName(), locale); + plugins.append(packedPlugin); + } QVariantMap returns; - returns.insert("plugins", JsonTypes::packPlugins(params.value("locale").toLocale())); + returns.insert("plugins", plugins); return createReply(returns); } @@ -444,16 +492,16 @@ JsonReply *DeviceHandler::GetPluginConfiguration(const QVariantMap ¶ms) cons DevicePlugin *plugin = NymeaCore::instance()->deviceManager()->plugins().findById(PluginId(params.value("pluginId").toString())); if (!plugin) { - returns.insert("deviceError", JsonTypes::deviceErrorToString(Device::DeviceErrorPluginNotFound)); + returns.insert("deviceError", enumValueName(Device::DeviceErrorPluginNotFound)); return createReply(returns); } QVariantList paramVariantList; foreach (const Param ¶m, plugin->configuration()) { - paramVariantList.append(JsonTypes::packParam(param)); + paramVariantList.append(pack(param)); } returns.insert("configuration", paramVariantList); - returns.insert("deviceError", JsonTypes::deviceErrorToString(Device::DeviceErrorNoError)); + returns.insert("deviceError", enumValueName(Device::DeviceErrorNoError)); return createReply(returns); } @@ -461,9 +509,9 @@ JsonReply* DeviceHandler::SetPluginConfiguration(const QVariantMap ¶ms) { QVariantMap returns; PluginId pluginId = PluginId(params.value("pluginId").toString()); - ParamList pluginParams = JsonTypes::unpackParams(params.value("configuration").toList()); + ParamList pluginParams = unpack(params.value("configuration")); Device::DeviceError result = NymeaCore::instance()->deviceManager()->setPluginConfig(pluginId, pluginParams); - returns.insert("deviceError", JsonTypes::deviceErrorToString(result)); + returns.insert("deviceError",enumValueName(result)); return createReply(returns); } @@ -471,7 +519,7 @@ JsonReply* DeviceHandler::AddConfiguredDevice(const QVariantMap ¶ms) { DeviceClassId deviceClassId(params.value("deviceClassId").toString()); QString deviceName = params.value("name").toString(); - ParamList deviceParams = JsonTypes::unpackParams(params.value("deviceParams").toList()); + ParamList deviceParams = unpack(params.value("deviceParams")); DeviceDescriptorId deviceDescriptorId(params.value("deviceDescriptorId").toString()); QLocale locale = params.value("locale").toLocale(); @@ -485,7 +533,7 @@ JsonReply* DeviceHandler::AddConfiguredDevice(const QVariantMap ¶ms) } connect(info, &DeviceSetupInfo::finished, jsonReply, [info, jsonReply, locale](){ QVariantMap returns; - returns.insert("deviceError", JsonTypes::deviceErrorToString(info->status())); + returns.insert("deviceError", enumValueName(info->status())); if (!info->displayMessage().isEmpty()) { returns.insert("displayMessage", info->translatedDisplayMessage(locale)); @@ -504,7 +552,7 @@ JsonReply* DeviceHandler::AddConfiguredDevice(const QVariantMap ¶ms) JsonReply *DeviceHandler::PairDevice(const QVariantMap ¶ms) { QString deviceName = params.value("name").toString(); - ParamList deviceParams = JsonTypes::unpackParams(params.value("deviceParams").toList()); + ParamList deviceParams = unpack(params.value("deviceParams")); QLocale locale = params.value("locale").toLocale(); DevicePairingInfo *info; @@ -523,12 +571,12 @@ JsonReply *DeviceHandler::PairDevice(const QVariantMap ¶ms) connect(info, &DevicePairingInfo::finished, jsonReply, [jsonReply, info, locale](){ QVariantMap returns; - returns.insert("deviceError", JsonTypes::deviceErrorToString(info->status())); + returns.insert("deviceError", enumValueName(info->status())); returns.insert("pairingTransactionId", info->transactionId().toString()); if (info->status() == Device::DeviceErrorNoError) { DeviceClass deviceClass = NymeaCore::instance()->deviceManager()->findDeviceClass(info->deviceClassId()); - returns.insert("setupMethod", JsonTypes::setupMethodToString(deviceClass.setupMethod())); + returns.insert("setupMethod", enumValueName(deviceClass.setupMethod())); } if (!info->displayMessage().isEmpty()) { @@ -559,7 +607,7 @@ JsonReply *DeviceHandler::ConfirmPairing(const QVariantMap ¶ms) connect(info, &DevicePairingInfo::finished, jsonReply, [info, jsonReply, locale](){ QVariantMap returns; - returns.insert("deviceError", JsonTypes::deviceErrorToString(info->status())); + returns.insert("deviceError", enumValueName(info->status())); if (!info->displayMessage().isEmpty()) { returns.insert("displayMessage", info->translatedDisplayMessage(locale)); } @@ -580,14 +628,14 @@ JsonReply* DeviceHandler::GetConfiguredDevices(const QVariantMap ¶ms) const if (params.contains("deviceId")) { Device *device = NymeaCore::instance()->deviceManager()->findConfiguredDevice(DeviceId(params.value("deviceId").toString())); if (!device) { - returns.insert("deviceError", JsonTypes::deviceErrorToString(Device::DeviceErrorDeviceNotFound)); + returns.insert("deviceError", enumValueName(Device::DeviceErrorDeviceNotFound)); return createReply(returns); } else { - configuredDeviceList.append(JsonTypes::packDevice(device)); + configuredDeviceList.append(pack(device)); } } else { foreach (Device *device, NymeaCore::instance()->deviceManager()->configuredDevices()) { - configuredDeviceList.append(JsonTypes::packDevice(device)); + configuredDeviceList.append(pack(device)); } } returns.insert("devices", configuredDeviceList); @@ -597,7 +645,7 @@ JsonReply* DeviceHandler::GetConfiguredDevices(const QVariantMap ¶ms) const JsonReply *DeviceHandler::ReconfigureDevice(const QVariantMap ¶ms) { DeviceId deviceId = DeviceId(params.value("deviceId").toString()); - ParamList deviceParams = JsonTypes::unpackParams(params.value("deviceParams").toList()); + ParamList deviceParams = unpack(params.value("deviceParams")); DeviceDescriptorId deviceDescriptorId(params.value("deviceDescriptorId").toString()); QLocale locale = params.value("locale").toLocale(); @@ -611,14 +659,14 @@ JsonReply *DeviceHandler::ReconfigureDevice(const QVariantMap ¶ms) } else { qCWarning(dcJsonRpc()) << "Either deviceId or deviceDescriptorId are required"; QVariantMap ret; - ret.insert("deviceError", JsonTypes::deviceErrorToString(Device::DeviceErrorMissingParameter)); + ret.insert("deviceError", enumValueName(Device::DeviceErrorMissingParameter)); return createReply(ret); } connect(info, &DeviceSetupInfo::finished, jsonReply, [info, jsonReply, locale](){ QVariantMap returns; - returns.insert("deviceError", JsonTypes::deviceErrorToString(info->status())); + returns.insert("deviceError", enumValueName(info->status())); returns.insert("displayMessage", info->translatedDisplayMessage(locale)); jsonReply->setData(returns); jsonReply->finished(); @@ -637,9 +685,7 @@ JsonReply *DeviceHandler::EditDevice(const QVariantMap ¶ms) Device::DeviceError status = NymeaCore::instance()->deviceManager()->editDevice(deviceId, name); - QVariantMap returns; - returns.insert("deviceError", JsonTypes::deviceErrorToString(status)); - return createReply(returns); + return createReply(statusToReply(status)); } JsonReply* DeviceHandler::RemoveConfiguredDevice(const QVariantMap ¶ms) @@ -651,7 +697,7 @@ JsonReply* DeviceHandler::RemoveConfiguredDevice(const QVariantMap ¶ms) if (params.contains("removePolicy")) { RuleEngine::RemovePolicy removePolicy = params.value("removePolicy").toString() == "RemovePolicyCascade" ? RuleEngine::RemovePolicyCascade : RuleEngine::RemovePolicyUpdate; Device::DeviceError status = NymeaCore::instance()->removeConfiguredDevice(deviceId, removePolicy); - returns.insert("deviceError", JsonTypes::deviceErrorToString(status)); + returns.insert("deviceError", enumValueName(status)); return createReply(returns); } @@ -663,7 +709,7 @@ JsonReply* DeviceHandler::RemoveConfiguredDevice(const QVariantMap ¶ms) } QPair > status = NymeaCore::instance()->removeConfiguredDevice(deviceId, removePolicyList); - returns.insert("deviceError", JsonTypes::deviceErrorToString(status.first)); + returns.insert("deviceError", enumValueName(status.first)); if (!status.second.isEmpty()) { QVariantList ruleIdList; @@ -678,85 +724,73 @@ JsonReply* DeviceHandler::RemoveConfiguredDevice(const QVariantMap ¶ms) JsonReply *DeviceHandler::SetDeviceSettings(const QVariantMap ¶ms) { - QVariantMap returns; DeviceId deviceId = DeviceId(params.value("deviceId").toString()); - ParamList settings = JsonTypes::unpackParams(params.value("settings").toList()); + ParamList settings = unpack(params.value("settings")); Device::DeviceError status = NymeaCore::instance()->deviceManager()->setDeviceSettings(deviceId, settings); - returns.insert("deviceError", JsonTypes::deviceErrorToString(status)); - return createReply(returns); + return createReply(statusToReply(status)); } JsonReply* DeviceHandler::GetEventTypes(const QVariantMap ¶ms) const { - QVariantMap returns; + QLocale locale = params.value("locale").toLocale(); - QVariantList eventList; DeviceClass deviceClass = NymeaCore::instance()->deviceManager()->findDeviceClass(DeviceClassId(params.value("deviceClassId").toString())); - foreach (const EventType &eventType, deviceClass.eventTypes()) { - eventList.append(JsonTypes::packEventType(eventType, deviceClass.pluginId(), params.value("locale").toLocale())); - } - returns.insert("eventTypes", eventList); + DeviceClass translatedDeviceClass = NymeaCore::instance()->deviceManager()->translateDeviceClass(deviceClass, locale); + + QVariantMap returns; + returns.insert("eventTypes", pack(translatedDeviceClass.eventTypes())); return createReply(returns); } JsonReply* DeviceHandler::GetActionTypes(const QVariantMap ¶ms) const { - QVariantMap returns; + QLocale locale = params.value("locale").toLocale(); - QVariantList actionList; DeviceClass deviceClass = NymeaCore::instance()->deviceManager()->findDeviceClass(DeviceClassId(params.value("deviceClassId").toString())); - foreach (const ActionType &actionType, deviceClass.actionTypes()) { - actionList.append(JsonTypes::packActionType(actionType, deviceClass.pluginId(), params.value("locale").toLocale())); - } - returns.insert("actionTypes", actionList); + DeviceClass translatedDeviceClass = NymeaCore::instance()->deviceManager()->translateDeviceClass(deviceClass, locale); + + QVariantMap returns; + returns.insert("actionTypes", pack(translatedDeviceClass.actionTypes())); return createReply(returns); } JsonReply* DeviceHandler::GetStateTypes(const QVariantMap ¶ms) const { - QVariantMap returns; + QLocale locale = params.value("locale").toLocale(); - QVariantList stateList; DeviceClass deviceClass = NymeaCore::instance()->deviceManager()->findDeviceClass(DeviceClassId(params.value("deviceClassId").toString())); - foreach (const StateType &stateType, deviceClass.stateTypes()) { - stateList.append(JsonTypes::packStateType(stateType, deviceClass.pluginId(), NymeaCore::instance()->configuration()->locale())); - } - returns.insert("stateTypes", stateList); + DeviceClass translatedDeviceClass = NymeaCore::instance()->deviceManager()->translateDeviceClass(deviceClass, locale); + + QVariantMap returns; + returns.insert("stateTypes", pack(translatedDeviceClass.stateTypes())); return createReply(returns); } JsonReply* DeviceHandler::GetStateValue(const QVariantMap ¶ms) const { - QVariantMap returns; - Device *device = NymeaCore::instance()->deviceManager()->findConfiguredDevice(DeviceId(params.value("deviceId").toString())); if (!device) { - returns.insert("deviceError", JsonTypes::deviceErrorToString(Device::DeviceErrorDeviceNotFound)); - return createReply(returns); + return createReply(statusToReply(Device::DeviceErrorDeviceNotFound)); } StateTypeId stateTypeId = StateTypeId(params.value("stateTypeId").toString()); if (!device->hasState(stateTypeId)) { - returns.insert("deviceError", JsonTypes::deviceErrorToString(Device::DeviceErrorStateTypeNotFound)); - return createReply(returns); + return createReply(statusToReply(Device::DeviceErrorStateTypeNotFound)); } - returns.insert("deviceError", JsonTypes::deviceErrorToString(Device::DeviceErrorNoError)); + QVariantMap returns = statusToReply(Device::DeviceErrorNoError); returns.insert("value", device->state(stateTypeId).value()); return createReply(returns); } JsonReply *DeviceHandler::GetStateValues(const QVariantMap ¶ms) const { - QVariantMap returns; - Device *device = NymeaCore::instance()->deviceManager()->findConfiguredDevice(DeviceId(params.value("deviceId").toString())); if (!device) { - returns.insert("deviceError", JsonTypes::deviceErrorToString(Device::DeviceErrorDeviceNotFound)); - return createReply(returns); + return createReply(statusToReply(Device::DeviceErrorDeviceNotFound)); } - returns.insert("deviceError", JsonTypes::deviceErrorToString(Device::DeviceErrorNoError)); - returns.insert("values", JsonTypes::packDeviceStates(device)); + QVariantMap returns = statusToReply(Device::DeviceErrorNoError); + returns.insert("values", pack(device->states())); return createReply(returns); } @@ -768,11 +802,14 @@ JsonReply *DeviceHandler::BrowseDevice(const QVariantMap ¶ms) const JsonReply *jsonReply = createAsyncReply("BrowseDevice"); BrowseResult *result = NymeaCore::instance()->deviceManager()->browseDevice(deviceId, itemId, params.value("locale").toLocale()); - connect(result, &BrowseResult::finished, jsonReply, [jsonReply, result](){ + connect(result, &BrowseResult::finished, jsonReply, [this, jsonReply, result](){ - QVariantMap returns; - returns.insert("deviceError", JsonTypes::deviceErrorToString(result->status())); - returns.insert("items", JsonTypes::packBrowserItems(result->items())); + QVariantMap returns = statusToReply(result->status()); + QVariantList list; + foreach (const BrowserItem &item, result->items()) { + list.append(packBrowserItem(item)); + } + returns.insert("items", list); jsonReply->setData(returns); jsonReply->finished(); }); @@ -789,12 +826,11 @@ JsonReply *DeviceHandler::GetBrowserItem(const QVariantMap ¶ms) const JsonReply *jsonReply = createAsyncReply("GetBrowserItem"); BrowserItemResult *result = NymeaCore::instance()->deviceManager()->browserItemDetails(deviceId, itemId, params.value("locale").toLocale()); - connect(result, &BrowserItemResult::finished, jsonReply, [jsonReply, result](){ - QVariantMap params; + connect(result, &BrowserItemResult::finished, jsonReply, [this, jsonReply, result](){ + QVariantMap params = statusToReply(result->status()); if (result->status() == Device::DeviceErrorNoError) { - params.insert("item", JsonTypes::packBrowserItem(result->item())); + params.insert("item", packBrowserItem(result->item())); } - params.insert("deviceError", JsonTypes::deviceErrorToString(result->status())); jsonReply->setData(params); jsonReply->finished(); }); @@ -802,13 +838,101 @@ JsonReply *DeviceHandler::GetBrowserItem(const QVariantMap ¶ms) const return jsonReply; } +JsonReply *DeviceHandler::ExecuteAction(const QVariantMap ¶ms) +{ + DeviceId deviceId(params.value("deviceId").toString()); + ActionTypeId actionTypeId(params.value("actionTypeId").toString()); + ParamList actionParams = unpack(params.value("params")); + QLocale locale = params.value("locale").toLocale(); + + Action action(actionTypeId, deviceId); + action.setParams(actionParams); + + JsonReply *jsonReply = createAsyncReply("ExecuteAction"); + + DeviceActionInfo *info = NymeaCore::instance()->executeAction(action); + connect(info, &DeviceActionInfo::finished, jsonReply, [info, jsonReply, locale](){ + QVariantMap data; + data.insert("deviceError", enumValueName(info->status())); + if (!info->displayMessage().isEmpty()) { + data.insert("displayMessage", info->translatedDisplayMessage(locale)); + } + jsonReply->setData(data); + jsonReply->finished(); + }); + + return jsonReply; +} + +JsonReply *DeviceHandler::ExecuteBrowserItem(const QVariantMap ¶ms) +{ + DeviceId deviceId = DeviceId(params.value("deviceId").toString()); + QString itemId = params.value("itemId").toString(); + BrowserAction action(deviceId, itemId); + + JsonReply *jsonReply = createAsyncReply("ExecuteBrowserItem"); + + BrowserActionInfo *info = NymeaCore::instance()->executeBrowserItem(action); + connect(info, &BrowserActionInfo::finished, jsonReply, [info, jsonReply](){ + QVariantMap data; + data.insert("deviceError", enumValueName(info->status())); + jsonReply->setData(data); + jsonReply->finished(); + }); + + return jsonReply; +} + +JsonReply *DeviceHandler::ExecuteBrowserItemAction(const QVariantMap ¶ms) +{ + DeviceId deviceId = DeviceId(params.value("deviceId").toString()); + QString itemId = params.value("itemId").toString(); + ActionTypeId actionTypeId = ActionTypeId(params.value("actionTypeId").toString()); + ParamList paramList = unpack(params.value("params")); + BrowserItemAction browserItemAction(deviceId, itemId, actionTypeId, paramList); + + JsonReply *jsonReply = createAsyncReply("ExecuteBrowserItemAction"); + + BrowserItemActionInfo *info = NymeaCore::instance()->executeBrowserItemAction(browserItemAction); + connect(info, &BrowserItemActionInfo::finished, jsonReply, [info, jsonReply](){ + QVariantMap data; + data.insert("deviceError", enumValueName(info->status())); + jsonReply->setData(data); + jsonReply->finished(); + }); + + return jsonReply; +} + +QVariantMap DeviceHandler::packBrowserItem(const BrowserItem &item) +{ + QVariantMap ret; + ret.insert("id", item.id()); + ret.insert("displayName", item.displayName()); + ret.insert("description", item.description()); + ret.insert("icon", enumValueName(item.icon())); + if (item.extendedPropertiesFlags().testFlag(BrowserItem::ExtendedPropertiesMedia)) { + ret.insert("mediaIcon", enumValueName(static_cast(item.extendedProperty("mediaIcon").toInt()))); + } + ret.insert("thumbnail", item.thumbnail()); + ret.insert("executable", item.executable()); + ret.insert("browsable", item.browsable()); + ret.insert("disabled", item.disabled()); + QVariantList actionTypeIds; + foreach (const ActionTypeId &id, item.actionTypeIds()) { + actionTypeIds.append(id.toString()); + } + ret.insert("actionTypeIds", actionTypeIds); + return ret; +} + void DeviceHandler::pluginConfigChanged(const PluginId &id, const ParamList &config) { QVariantMap params; params.insert("pluginId", id); QVariantList configList; foreach (const Param ¶m, config) { - configList << JsonTypes::packParam(param); + configList << pack(param); } params.insert("configuration", configList); emit PluginConfigurationChanged(params); @@ -820,7 +944,6 @@ void DeviceHandler::deviceStateChanged(Device *device, const QUuid &stateTypeId, params.insert("deviceId", device->id()); params.insert("stateTypeId", stateTypeId); params.insert("value", value); - emit StateChanged(params); } @@ -828,23 +951,20 @@ void DeviceHandler::deviceRemovedNotification(const QUuid &deviceId) { QVariantMap params; params.insert("deviceId", deviceId); - emit DeviceRemoved(params); } void DeviceHandler::deviceAddedNotification(Device *device) { QVariantMap params; - params.insert("device", JsonTypes::packDevice(device)); - + params.insert("device", pack(device)); emit DeviceAdded(params); } void DeviceHandler::deviceChangedNotification(Device *device) { QVariantMap params; - params.insert("device", JsonTypes::packDevice(device)); - + params.insert("device", pack(device)); emit DeviceChanged(params); } @@ -857,4 +977,11 @@ void DeviceHandler::deviceSettingChangedNotification(const DeviceId deviceId, co emit DeviceSettingChanged(params); } +QVariantMap DeviceHandler::statusToReply(Device::DeviceError status) const +{ + QVariantMap returns; + returns.insert("deviceError", enumValueName(status)); + return returns; +} + } diff --git a/libnymea-core/jsonrpc/devicehandler.h b/libnymea-core/jsonrpc/devicehandler.h index a73d22ed..d95a0727 100644 --- a/libnymea-core/jsonrpc/devicehandler.h +++ b/libnymea-core/jsonrpc/devicehandler.h @@ -22,7 +22,7 @@ #ifndef DEVICEHANDLER_H #define DEVICEHANDLER_H -#include "jsonhandler.h" +#include "jsonrpc/jsonhandler.h" #include "devices/devicemanager.h" namespace nymeaserver { @@ -60,6 +60,12 @@ public: Q_INVOKABLE JsonReply *BrowseDevice(const QVariantMap ¶ms) const; Q_INVOKABLE JsonReply *GetBrowserItem(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *ExecuteAction(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *ExecuteBrowserItem(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *ExecuteBrowserItemAction(const QVariantMap ¶ms); + + static QVariantMap packBrowserItem(const BrowserItem &item); + signals: void PluginConfigurationChanged(const QVariantMap ¶ms); void StateChanged(const QVariantMap ¶ms); @@ -67,6 +73,7 @@ signals: void DeviceAdded(const QVariantMap ¶ms); void DeviceChanged(const QVariantMap ¶ms); void DeviceSettingChanged(const QVariantMap ¶ms); + void EventTriggered(const QVariantMap ¶ms); private slots: void pluginConfigChanged(const PluginId &id, const ParamList &config); @@ -80,6 +87,9 @@ private slots: void deviceChangedNotification(Device *device); void deviceSettingChangedNotification(const DeviceId deviceId, const ParamTypeId ¶mTypeId, const QVariant &value); + +private: + QVariantMap statusToReply(Device::DeviceError status) const; }; } diff --git a/libnymea-core/jsonrpc/eventhandler.cpp b/libnymea-core/jsonrpc/eventhandler.cpp index 12c784a5..f1e8a93e 100644 --- a/libnymea-core/jsonrpc/eventhandler.cpp +++ b/libnymea-core/jsonrpc/eventhandler.cpp @@ -47,23 +47,27 @@ namespace nymeaserver { EventHandler::EventHandler(QObject *parent) : JsonHandler(parent) { - QVariantMap params; - QVariantMap returns; + registerEnum(); + registerEnum(); + // Objects + registerObject(); + registerObject(); + registerObject(); + registerObject(); + + // Methods + QString description; QVariantMap params; QVariantMap returns; + description = "Get the EventType for the given eventTypeId."; + params.insert("eventTypeId", enumValueName(Uuid)); + returns.insert("deviceError", enumRef()); + returns.insert("o:eventType", objectRef()); + registerMethod("GetEventType", description, params, returns, "Please use the Devices namespace instead."); // Notifications params.clear(); returns.clear(); - setDescription("EventTriggered", "Emitted whenever an Event is triggered."); - params.insert("event", JsonTypes::eventRef()); - setParams("EventTriggered", params); - - params.clear(); returns.clear(); - setDescription("GetEventType", "Get the EventType for the given eventTypeId."); - params.insert("eventTypeId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setParams("GetEventType", params); - returns.insert("deviceError", JsonTypes::deviceErrorRef()); - returns.insert("o:eventType", JsonTypes::eventTypeRef()); - setReturns("GetEventType", returns); - + description = "Emitted whenever an Event is triggered."; + params.insert("event", objectRef()); + registerNotification("EventTriggered", description, params, "Please use Devices.EventTriggered instead."); connect(NymeaCore::instance(), &NymeaCore::eventTriggered, this, &EventHandler::eventTriggered); } @@ -76,24 +80,30 @@ QString EventHandler::name() const void EventHandler::eventTriggered(const Event &event) { QVariantMap params; - params.insert("event", JsonTypes::packEvent(event)); + params.insert("event", pack(event)); emit EventTriggered(params); } JsonReply* EventHandler::GetEventType(const QVariantMap ¶ms) const { + QLocale locale = params.value("locale").toLocale(); qCDebug(dcJsonRpc) << "asked for event type" << params; EventTypeId eventTypeId(params.value("eventTypeId").toString()); foreach (const DeviceClass &deviceClass, NymeaCore::instance()->deviceManager()->supportedDevices()) { foreach (const EventType &eventType, deviceClass.eventTypes()) { if (eventType.id() == eventTypeId) { - QVariantMap data = statusToReply(Device::DeviceErrorNoError); - data.insert("eventType", JsonTypes::packEventType(eventType, deviceClass.pluginId(), params.value("locale").toLocale())); + EventType translatedEventType = eventType; + translatedEventType.setDisplayName(NymeaCore::instance()->deviceManager()->translate(deviceClass.pluginId(), eventType.displayName(), locale)); + QVariantMap data; + data.insert("deviceError", enumValueName(Device::DeviceErrorNoError)); + data.insert("eventType", pack(translatedEventType)); return createReply(data); } } } - return createReply(statusToReply(Device::DeviceErrorEventTypeNotFound)); + QVariantMap data; + data.insert("deviceError", enumValueName(Device::DeviceErrorEventTypeNotFound)); + return createReply(data); } } diff --git a/libnymea-core/jsonrpc/eventhandler.h b/libnymea-core/jsonrpc/eventhandler.h index deeffe69..6758ace7 100644 --- a/libnymea-core/jsonrpc/eventhandler.h +++ b/libnymea-core/jsonrpc/eventhandler.h @@ -22,7 +22,9 @@ #ifndef EVENTHANDLER_H #define EVENTHANDLER_H -#include "jsonhandler.h" +#include "jsonrpc/jsonhandler.h" + +#include "types/event.h" namespace nymeaserver { @@ -30,7 +32,7 @@ class EventHandler : public JsonHandler { Q_OBJECT public: - explicit EventHandler(QObject *parent = 0); + explicit EventHandler(QObject *parent = nullptr); QString name() const override; Q_INVOKABLE JsonReply *GetEventType(const QVariantMap ¶ms) const; diff --git a/libnymea-core/jsonrpc/jsonhandler.cpp b/libnymea-core/jsonrpc/jsonhandler.cpp deleted file mode 100644 index 81093f90..00000000 --- a/libnymea-core/jsonrpc/jsonhandler.cpp +++ /dev/null @@ -1,354 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2015 Simon Stürz * - * Copyright (C) 2014 Michael Zanetti * - * * - * This file is part of nymea. * - * * - * nymea 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. * - * * - * nymea 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 nymea. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/*! - \class nymeaserver::JsonHandler - \brief This class represents an interface for developing a handler for the JSON-RPC API. - - \ingroup json - \inmodule core - - \sa JsonRPCServer, JsonReply -*/ - -/*! \fn QString nymeaserver::JsonHandler::name() const; - Pure virtual method for a JSON RPC handler. Returns the namespace of the handler. -*/ - -/*! \fn void nymeaserver::JsonHandler::asyncReply(int id, const QVariantMap ¶ms); - This signal will be emitted when a reply with the given \a id and \a params is finished. -*/ - - -#include "jsonhandler.h" -#include "loggingcategories.h" - -#include -#include -#include - -namespace nymeaserver { - -/*! Constructs a new \l JsonHandler with the given \a parent. */ -JsonHandler::JsonHandler(QObject *parent) : - QObject(parent) -{ -} - -/*! Returns a map with all supported methods, notifications and types for the given meta \a type. */ -QVariantMap JsonHandler::introspect(QMetaMethod::MethodType type) -{ - QVariantMap data; - for (int i = 0; i < metaObject()->methodCount(); ++i) { - QMetaMethod method = metaObject()->method(i); - - if (method.methodType() != type) { - continue; - } - - switch (method.methodType()) { - case QMetaMethod::Method: { - if (!m_descriptions.contains(method.name()) || !m_params.contains(method.name()) || !m_returns.contains(method.name())) { - continue; - } - qCDebug(dcJsonRpc) << "got method" << method.name(); - QVariantMap methodData; - methodData.insert("description", m_descriptions.value(method.name())); - methodData.insert("params", m_params.value(method.name())); - methodData.insert("returns", m_returns.value(method.name())); - data.insert(name() + "." + method.name(), methodData); - break; - } - case QMetaMethod::Signal: { - if (!m_descriptions.contains(method.name()) || !m_params.contains(method.name())) { - continue; - } - if (QString(method.name()).contains(QRegExp("^[A-Z]"))) { - qCDebug(dcJsonRpc) << "got signal" << method.name(); - QVariantMap methodData; - methodData.insert("description", m_descriptions.value(method.name())); - methodData.insert("params", m_params.value(method.name())); - data.insert(name() + "." + method.name(), methodData); - } - break; - default: - ;;// Nothing to do for slots - } - } - } - return data; -} - -/*! Returns true if this \l JsonHandler has a method with the given \a methodName.*/ -bool JsonHandler::hasMethod(const QString &methodName) -{ - return m_descriptions.contains(methodName) && m_params.contains(methodName) && m_returns.contains(methodName); -} - -/*! Validates the given \a params for the given \a methodName. Returns the error string and false if - the params are not valid. */ -QPair JsonHandler::validateParams(const QString &methodName, const QVariantMap ¶ms) -{ - QVariantMap paramTemplate = m_params.value(methodName); - return JsonTypes::validateMap(paramTemplate, params); -} - -/*! Validates the given \a returns for the given \a methodName. Returns the error string and false if - the params are not valid. */ -QPair JsonHandler::validateReturns(const QString &methodName, const QVariantMap &returns) -{ - QVariantMap returnsTemplate = m_returns.value(methodName); - return JsonTypes::validateMap(returnsTemplate, returns); -} - - -/*! Sets the \a description of the method with the given \a methodName. */ -void JsonHandler::setDescription(const QString &methodName, const QString &description) -{ - for(int i = 0; i < metaObject()->methodCount(); ++i) { - QMetaMethod method = metaObject()->method(i); - if (method.name() == methodName) { - m_descriptions.insert(methodName, description); - return; - } - } - qCWarning(dcJsonRpc) << "Cannot set description. No such method:" << methodName; -} - -/*! Sets the \a params of the method with the given \a methodName. */ -void JsonHandler::setParams(const QString &methodName, const QVariantMap ¶ms) -{ - for(int i = 0; i < metaObject()->methodCount(); ++i) { - QMetaMethod method = metaObject()->method(i); - if (method.name() == methodName) { - m_params.insert(methodName, params); - return; - } - } - qCWarning(dcJsonRpc) << "Cannot set params. No such method:" << methodName; -} - -/*! Sets the \a returns of the method with the given \a methodName. */ -void JsonHandler::setReturns(const QString &methodName, const QVariantMap &returns) -{ - for(int i = 0; i < metaObject()->methodCount(); ++i) { - QMetaMethod method = metaObject()->method(i); - if (method.name() == methodName) { - m_returns.insert(methodName, returns); - return; - } - } - qCWarning(dcJsonRpc) << "Cannot set returns. No such method:" << methodName; -} - -/*! Returns the pointer to a new \l{JsonReply} with the given \a data. */ -JsonReply *JsonHandler::createReply(const QVariantMap &data) const -{ - return JsonReply::createReply(const_cast(this), data); -} - -/*! Returns the pointer to an asynchronous new \l{JsonReply} with the given \a method. */ -JsonReply* JsonHandler::createAsyncReply(const QString &method) const -{ - return JsonReply::createAsyncReply(const_cast(this), method); -} - -/*! Returns the formated error map for the given \a status. - * - * \sa Device::DeviceError - */ -QVariantMap JsonHandler::statusToReply(Device::DeviceError status) const -{ - QVariantMap returns; - returns.insert("deviceError", JsonTypes::deviceErrorToString(status)); - return returns; -} - -/*! Returns the formated error map for the given \a status. - * - * \sa RuleEngine::RuleError - */ -QVariantMap JsonHandler::statusToReply(RuleEngine::RuleError status) const -{ - QVariantMap returns; - returns.insert("ruleError", JsonTypes::ruleErrorToString(status)); - return returns; -} - -/*! Returns the formated error map for the given \a status. - * - * \sa Logging::LoggingError - */ -QVariantMap JsonHandler::statusToReply(Logging::LoggingError status) const -{ - QVariantMap returns; - returns.insert("loggingError", JsonTypes::loggingErrorToString(status)); - return returns; -} - -/*! Returns the formated error map for the given \a status. */ -QVariantMap JsonHandler::statusToReply(NymeaConfiguration::ConfigurationError status) const -{ - QVariantMap returns; - returns.insert("configurationError", JsonTypes::configurationErrorToString(status)); - return returns; -} - -/*! Returns the formated error map for the given \a status. */ -QVariantMap JsonHandler::statusToReply(NetworkManager::NetworkManagerError status) const -{ - QVariantMap returns; - returns.insert("networkManagerError", JsonTypes::networkManagerErrorToString(status)); - return returns; -} - -/*! Returns the formated error map for the given \a status. */ -QVariantMap JsonHandler::statusToReply(TagsStorage::TagError status) const -{ - QVariantMap returns; - returns.insert("tagError", JsonTypes::tagErrorToString(status)); - return returns; -} - - -/*! - \class nymeaserver::JsonReply - \brief This class represents a reply for the JSON-RPC API request. - - \ingroup json - \inmodule core - - \sa JsonHandler, JsonRPCServer -*/ - -/*! \enum nymeaserver::JsonReply::Type - - This enum type specifies the type of a JsonReply. - - \value TypeSync - The response is synchronous. - \value TypeAsync - The response is asynchronous. -*/ - -/*! \fn void nymeaserver::JsonReply::finished(); - This signal will be emitted when a JsonReply is finished. A JsonReply is finished when - the response is ready or then the reply timed out. -*/ - - - -/*! Constructs a new \l JsonReply with the given \a type, \a handler, \a method and \a data. */ -JsonReply::JsonReply(Type type, JsonHandler *handler, const QString &method, const QVariantMap &data): - m_type(type), - m_data(data), - m_handler(handler), - m_method(method), - m_timedOut(false) -{ - connect(&m_timeout, &QTimer::timeout, this, &JsonReply::timeout); -} - -/*! Returns the pointer to a new \l{JsonReply} for the given \a handler and \a data. */ -JsonReply *JsonReply::createReply(JsonHandler *handler, const QVariantMap &data) -{ - return new JsonReply(TypeSync, handler, QString(), data); -} - -/*! Returns the pointer to a new asynchronous \l{JsonReply} for the given \a handler and \a method. */ -JsonReply *JsonReply::createAsyncReply(JsonHandler *handler, const QString &method) -{ - return new JsonReply(TypeAsync, handler, method); -} - -/*! Returns the type of this \l{JsonReply}.*/ -JsonReply::Type JsonReply::type() const -{ - return m_type; -} - -/*! Returns the data of this \l{JsonReply}.*/ -QVariantMap JsonReply::data() const -{ - return m_data; -} - -/*! Sets the \a data of this \l{JsonReply}.*/ -void JsonReply::setData(const QVariantMap &data) -{ - m_data = data; -} - -/*! Returns the handler of this \l{JsonReply}.*/ -JsonHandler *JsonReply::handler() const -{ - return m_handler; -} - -/*! Returns the method of this \l{JsonReply}.*/ -QString JsonReply::method() const -{ - return m_method; -} - -/*! Returns the client ID of this \l{JsonReply}.*/ -QUuid JsonReply::clientId() const -{ - return m_clientId; -} - -/*! Sets the \a clientId of this \l{JsonReply}.*/ -void JsonReply::setClientId(const QUuid &clientId) -{ - m_clientId = clientId; -} - -/*! Returns the command ID of this \l{JsonReply}.*/ -int JsonReply::commandId() const -{ - return m_commandId; -} - -/*! Returns the \a commandId of this \l{JsonReply}.*/ -void JsonReply::setCommandId(int commandId) -{ - m_commandId = commandId; -} - -/*! Start the timeout timer for this \l{JsonReply}. The default timeout is 15 seconds. */ -void JsonReply::startWait() -{ - m_timeout.start(30000); -} - -void JsonReply::timeout() -{ - m_timedOut = true; - emit finished(); -} - -/*! Returns true if this \l{JsonReply} timed out.*/ -bool JsonReply::timedOut() const -{ - return m_timedOut; -} - -} diff --git a/libnymea-core/jsonrpc/jsonrpcserver.cpp b/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp similarity index 57% rename from libnymea-core/jsonrpc/jsonrpcserver.cpp rename to libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp index 6736f9ef..8aded8dc 100644 --- a/libnymea-core/jsonrpc/jsonrpcserver.cpp +++ b/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp @@ -36,9 +36,9 @@ */ -#include "jsonrpcserver.h" -#include "jsontypes.h" -#include "jsonhandler.h" +#include "jsonrpcserverimplementation.h" +#include "jsonrpc/jsonhandler.h" +#include "jsonvalidator.h" #include "nymeacore.h" #include "devices/devicemanager.h" #include "devices/deviceplugin.h" @@ -67,17 +67,29 @@ namespace nymeaserver { /*! Constructs a \l{JsonRPCServer} with the given \a sslConfiguration and \a parent. */ -JsonRPCServer::JsonRPCServer(const QSslConfiguration &sslConfiguration, QObject *parent): +JsonRPCServerImplementation::JsonRPCServerImplementation(const QSslConfiguration &sslConfiguration, QObject *parent): JsonHandler(parent), m_notificationId(0) { Q_UNUSED(sslConfiguration) - // First, define our own JSONRPC methods - QVariantMap returns; - QVariantMap params; + // First, define our own JSONRPC API - params.clear(); returns.clear(); - setDescription("Hello", "Initiates a connection. Use this method to perform an initial handshake of the " + // Enums + registerEnum(); + registerEnum(); + registerEnum(); + + // Objects + registerObject(); + + QVariantMap experiece; + experiece.insert("name", enumValueName(String)); + experiece.insert("version", enumValueName(String)); + registerObject("Experience", experiece); + + // Methods + QString description; QVariantMap returns; QVariantMap params; + description = "Initiates a connection. Use this method to perform an initial handshake of the " "connection. Optionally, a parameter \"locale\" is can be passed to set up the used " "locale for this connection. Strings such as DeviceClass displayNames etc will be " "localized to this locale. If this parameter is omitted, the default system locale " @@ -85,75 +97,70 @@ JsonRPCServer::JsonRPCServer(const QSslConfiguration &sslConfiguration, QObject "about this core instance such as version information, uuid and its name. The locale value" "indicates the locale used for this connection. Note: This method can be called multiple " "times. The locale used in the last call for this connection will be used. Other values, " - "like initialSetupRequired might change if the setup has been performed in the meantime."); - params.insert("o:locale", JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("Hello", params); - returns.insert("server", JsonTypes::basicTypeToString(JsonTypes::String)); - returns.insert("name", JsonTypes::basicTypeToString(JsonTypes::String)); - returns.insert("version", JsonTypes::basicTypeToString(JsonTypes::String)); - returns.insert("uuid", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - returns.insert("language", JsonTypes::basicTypeToString(JsonTypes::String)); - returns.insert("locale", JsonTypes::basicTypeToString(JsonTypes::String)); - returns.insert("protocol version", JsonTypes::basicTypeToString(JsonTypes::String)); - returns.insert("initialSetupRequired", JsonTypes::basicTypeToString(JsonTypes::Bool)); - returns.insert("authenticationRequired", JsonTypes::basicTypeToString(JsonTypes::Bool)); - returns.insert("pushButtonAuthAvailable", JsonTypes::basicTypeToString(JsonTypes::Bool)); - setReturns("Hello", returns); + "like initialSetupRequired might change if the setup has been performed in the meantime."; + params.insert("o:locale", enumValueName(String)); + returns.insert("server", enumValueName(String)); + returns.insert("name", enumValueName(String)); + returns.insert("version", enumValueName(String)); + returns.insert("uuid", enumValueName(Uuid)); + returns.insert("language", enumValueName(String)); + returns.insert("locale", enumValueName(String)); + returns.insert("protocol version", enumValueName(String)); + returns.insert("initialSetupRequired", enumValueName(Bool)); + returns.insert("authenticationRequired", enumValueName(Bool)); + returns.insert("pushButtonAuthAvailable", enumValueName(Bool)); + returns.insert("o:experiences", QVariantList() << objectRef("Experience")); + registerMethod("Hello", description, params, returns); params.clear(); returns.clear(); - setDescription("Introspect", "Introspect this API."); - setParams("Introspect", params); - returns.insert("methods", JsonTypes::basicTypeToString(JsonTypes::Object)); - returns.insert("notifications", JsonTypes::basicTypeToString(JsonTypes::Object)); - returns.insert("types", JsonTypes::basicTypeToString(JsonTypes::Object)); - setReturns("Introspect", returns); + description = "Introspect this API."; + returns.insert("methods", enumValueName(Object)); + returns.insert("notifications", enumValueName(Object)); + returns.insert("types", enumValueName(Object)); + registerMethod("Introspect", description, params, returns); params.clear(); returns.clear(); - setDescription("Version", "Version of this nymea/JSONRPC interface."); - setParams("Version", params); - returns.insert("version", JsonTypes::basicTypeToString(JsonTypes::String)); - returns.insert("protocol version", JsonTypes::basicTypeToString(JsonTypes::String)); - setReturns("Version", returns); + description = "Version of this nymea/JSONRPC interface."; + returns.insert("version", enumValueName(String)); + returns.insert("protocol version", enumValueName(String)); + registerMethod("Version", description, params, returns); params.clear(); returns.clear(); - setDescription("SetNotificationStatus", "Enable/Disable notifications for this connections. Either \"enabled\" or """ + description = "Enable/Disable notifications for this connections. Either \"enabled\" or """ "\"namespaces\" needs to be given but not both of them. The boolean based " "\"enabled\" parameter will enable/disable all notifications at once. If " "instead the list-based \"namespaces\" parameter is provided, all given namespaces" "will be enabled, the others will be disabled. The return value of \"success\" will " "indicate success of the operation. The \"enabled\" property in the return value is " "deprecated and used for legacy compatibilty only. It will be set to true if at least " - "one namespace has been enabled."); - params.insert("o:enabled", JsonTypes::basicTypeToString(JsonTypes::Bool)); - params.insert("o:namespaces", QVariantList() << QStringLiteral("$ref:Namespace")); - setParams("SetNotificationStatus", params); - returns.insert("namespaces", QVariantList() << QStringLiteral("$ref:Namespace")); - returns.insert("enabled", JsonTypes::basicTypeToString(JsonTypes::Bool)); - setReturns("SetNotificationStatus", returns); + "one namespace has been enabled."; + params.insert("o:namespaces", enumValueName(StringList)); + params.insert("o:enabled", enumValueName(Bool)); + returns.insert("namespaces", enumValueName(StringList)); + returns.insert("enabled", enumValueName(Bool)); + registerMethod("SetNotificationStatus", description, params, returns); params.clear(); returns.clear(); - setDescription("CreateUser", "Create a new user in the API. Currently this is only allowed to be called once when a new nymea instance is set up. Call Authenticate after this to obtain a device token for this user."); - params.insert("username", JsonTypes::basicTypeToString(JsonTypes::String)); - params.insert("password", JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("CreateUser", params); - returns.insert("error", JsonTypes::userErrorRef()); - setReturns("CreateUser", returns); + description = "Create a new user in the API. Currently this is only allowed to be called once when a new nymea instance is set up. Call Authenticate after this to obtain a device token for this user."; + params.insert("username", enumValueName(String)); + params.insert("password", enumValueName(String)); + returns.insert("error", enumRef()); + registerMethod("CreateUser", description, params, returns); params.clear(); returns.clear(); - setDescription("Authenticate", "Authenticate a client to the api via user & password challenge. Provide " + description = "Authenticate a client to the api via user & password challenge. Provide " "a device name which allows the user to identify the client and revoke the token in case " "the device is lost or stolen. This will return a new token to be used to authorize a " - "client at the API."); - params.insert("username", JsonTypes::basicTypeToString(JsonTypes::String)); - params.insert("password", JsonTypes::basicTypeToString(JsonTypes::String)); - params.insert("deviceName", JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("Authenticate", params); - returns.insert("success", JsonTypes::basicTypeToString(JsonTypes::Bool)); - returns.insert("o:token", JsonTypes::basicTypeToString(JsonTypes::String)); - setReturns("Authenticate", returns); + "client at the API."; + params.insert("username", enumValueName(String)); + params.insert("password", enumValueName(String)); + params.insert("deviceName", enumValueName(String)); + returns.insert("success", enumValueName(Bool)); + returns.insert("o:token", enumValueName(String)); + registerMethod("Authenticate", description, params, returns); params.clear(); returns.clear(); - setDescription("RequestPushButtonAuth", "Authenticate a client to the api via Push Button method. " + description = "Authenticate a client to the api via Push Button method. " "Provide a device name which allows the user to identify the client and revoke the " "token in case the device is lost or stolen. If push button hardware is available, " "this will return with success and start listening for push button presses. When the " @@ -165,89 +172,81 @@ JsonRPCServer::JsonRPCServer(const QSslConfiguration &sslConfiguration, QObject "to the user to not press the button when the procedure fails as this can happen for 2 " "reasons: a) a second user is trying to auth at the same time and only the currently " "active user should press the button or b) it might indicate an attacker trying to take " - "over and snooping in for tokens."); - params.insert("deviceName", JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("RequestPushButtonAuth", params); - returns.insert("success", JsonTypes::basicTypeToString(JsonTypes::Bool)); - returns.insert("transactionId", JsonTypes::basicTypeToString(JsonTypes::Int)); - setReturns("RequestPushButtonAuth", returns); + "over and snooping in for tokens."; + params.insert("deviceName", enumValueName(String)); + returns.insert("success", enumValueName(Bool)); + returns.insert("transactionId", enumValueName(Int)); + registerMethod("RequestPushButtonAuth", description, params, returns); params.clear(); returns.clear(); - setDescription("Tokens", "Return a list of TokenInfo objects of all the tokens for the current user."); - setParams("Tokens", params); - returns.insert("tokenInfoList", QVariantList() << JsonTypes::tokenInfoRef()); - setReturns("Tokens", returns); + description = "Return a list of TokenInfo objects of all the tokens for the current user."; + returns.insert("tokenInfoList", QVariantList() << objectRef("TokenInfo")); + registerMethod("Tokens", description, params, returns); params.clear(); returns.clear(); - setDescription("RemoveToken", "Revoke access for a given token."); - params.insert("tokenId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setParams("RemoveToken", params); - returns.insert("error", JsonTypes::userErrorRef()); - setReturns("RemoveToken", returns); + description = "Revoke access for a given token."; + params.insert("tokenId", enumValueName(Uuid)); + returns.insert("error", enumRef()); + registerMethod("RemoveToken", description, params, returns); params.clear(); returns.clear(); - setDescription("SetupCloudConnection", "Sets up the cloud connection by deploying a certificate and its configuration."); - params.insert("rootCA", JsonTypes::basicTypeToString(JsonTypes::String)); - params.insert("certificatePEM", JsonTypes::basicTypeToString(JsonTypes::String)); - params.insert("publicKey", JsonTypes::basicTypeToString(JsonTypes::String)); - params.insert("privateKey", JsonTypes::basicTypeToString(JsonTypes::String)); - params.insert("endpoint", JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("SetupCloudConnection", params); - returns.insert("success", JsonTypes::basicTypeToString(JsonTypes::Bool)); - setReturns("SetupCloudConnection", returns); + description = "Sets up the cloud connection by deploying a certificate and its configuration."; + params.insert("rootCA", enumValueName(String)); + params.insert("certificatePEM", enumValueName(String)); + params.insert("publicKey", enumValueName(String)); + params.insert("privateKey", enumValueName(String)); + params.insert("endpoint", enumValueName(String)); + returns.insert("success", enumValueName(Bool)); + registerMethod("SetupCloudConnection", description, params, returns); params.clear(); returns.clear(); - setDescription("SetupRemoteAccess", "Setup the remote connection by providing AWS token information. This requires the cloud to be connected."); - params.insert("idToken", JsonTypes::basicTypeToString(JsonTypes::String)); - params.insert("userId", JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("SetupRemoteAccess", params); - returns.insert("status", JsonTypes::basicTypeToString(JsonTypes::Int)); - returns.insert("message", JsonTypes::basicTypeToString(JsonTypes::String)); - setReturns("SetupRemoteAccess", returns); + description = "Setup the remote connection by providing AWS token information. This requires the cloud to be connected."; + params.insert("idToken", enumValueName(String)); + params.insert("userId", enumValueName(String)); + returns.insert("status", enumValueName(Int)); + returns.insert("message", enumValueName(String)); + registerMethod("SetupRemoteAccess", description, params, returns); params.clear(); returns.clear(); - setDescription("IsCloudConnected", "Check whether the cloud is currently connected. \"connected\" will be true whenever connectionState equals CloudConnectionStateConnected and is deprecated. Please use the connectionState value instead."); - setParams("IsCloudConnected", params); - returns.insert("connected", JsonTypes::basicTypeToString(JsonTypes::Bool)); - returns.insert("connectionState", JsonTypes::cloudConnectionStateRef()); - setReturns("IsCloudConnected", returns); + description = "Check whether the cloud is currently connected. \"connected\" will be true whenever connectionState equals CloudConnectionStateConnected and is deprecated. Please use the connectionState value instead."; + returns.insert("connected", enumValueName(Bool)); + returns.insert("connectionState", enumRef()); + registerMethod("IsCloudConnected", description, params, returns); params.clear(); returns.clear(); - setDescription("KeepAlive", "This is basically a Ping/Pong mechanism a client app may use to check server connectivity. Currently, the server does not actually do anything with this information and will return the call providing the given sessionId back to the caller. It is up to the client whether to use this or not and not required by the server to keep the connection alive."); - params.insert("sessionId", JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("KeepAlive", params); - returns.insert("success", JsonTypes::basicTypeToString(JsonTypes::Bool)); - returns.insert("sessionId", JsonTypes::basicTypeToString(JsonTypes::String)); - setReturns("KeepAlive", returns); + description = "This is basically a Ping/Pong mechanism a client app may use to check server connectivity. Currently, the server does not actually do anything with this information and will return the call providing the given sessionId back to the caller. It is up to the client whether to use this or not and not required by the server to keep the connection alive."; + params.insert("sessionId", enumValueName(String)); + returns.insert("success", enumValueName(Bool)); + returns.insert("sessionId", enumValueName(String)); + registerMethod("KeepAlive", description, params, returns); // Notifications params.clear(); returns.clear(); - setDescription("CloudConnectedChanged", "Emitted whenever the cloud connection status changes."); - params.insert("connected", JsonTypes::basicTypeToString(JsonTypes::Bool)); - params.insert("connectionState", JsonTypes::cloudConnectionStateRef()); - setParams("CloudConnectedChanged", params); + description = "Emitted whenever the cloud connection status changes."; + params.insert("connected", enumValueName(Bool)); + params.insert("connectionState", enumRef()); + registerNotification("CloudConnectedChanged", description, params); params.clear(); - setDescription("PushButtonAuthFinished", "Emitted when a push button authentication reaches final state. NOTE: This notification is special. It will only be emitted to connections that did actively request a push button authentication, but also it will be emitted regardless of the notification settings. "); - params.insert("success", JsonTypes::basicTypeToString(JsonTypes::Bool)); - params.insert("transactionId", JsonTypes::basicTypeToString(JsonTypes::Int)); - params.insert("o:token", JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("PushButtonAuthFinished", params); + description = "Emitted when a push button authentication reaches final state. NOTE: This notification is special. It will only be emitted to connections that did actively request a push button authentication, but also it will be emitted regardless of the notification settings. "; + params.insert("success", enumValueName(Bool)); + params.insert("transactionId", enumValueName(Int)); + params.insert("o:token", enumValueName(String)); + registerNotification("PushButtonAuthFinished", description, params); QMetaObject::invokeMethod(this, "setup", Qt::QueuedConnection); - connect(NymeaCore::instance()->userManager(), &UserManager::pushButtonAuthFinished, this, &JsonRPCServer::onPushButtonAuthFinished); + connect(NymeaCore::instance()->userManager(), &UserManager::pushButtonAuthFinished, this, &JsonRPCServerImplementation::onPushButtonAuthFinished); } /*! Returns the \e namespace of \l{JsonHandler}. */ -QString JsonRPCServer::name() const +QString JsonRPCServerImplementation::name() const { return QStringLiteral("JSONRPC"); } -JsonReply *JsonRPCServer::Hello(const QVariantMap ¶ms) +JsonReply *JsonRPCServerImplementation::Hello(const QVariantMap ¶ms) { - Q_UNUSED(params); TransportInterface *interface = reinterpret_cast(property("transportInterface").toLongLong()); qCDebug(dcJsonRpc()) << params; @@ -266,38 +265,13 @@ JsonReply *JsonRPCServer::Hello(const QVariantMap ¶ms) return createReply(createWelcomeMessage(interface, clientId)); } -JsonReply* JsonRPCServer::Introspect(const QVariantMap ¶ms) const +JsonReply* JsonRPCServerImplementation::Introspect(const QVariantMap ¶ms) const { Q_UNUSED(params) - - // We need to add dynamic stuff ourselves - QVariantMap allTypes = JsonTypes::allTypes(); - QStringList namespaces; - foreach (const QString &namespaceString, m_handlers.keys()) { - namespaces.append(namespaceString); - } - // We need to sort them to have a predictable ordering - std::sort(namespaces.begin(), namespaces.end()); - allTypes.insert("Namespace", namespaces); - - QVariantMap data; - data.insert("types", allTypes); - QVariantMap methods; - foreach (JsonHandler *handler, m_handlers) - methods.unite(handler->introspect(QMetaMethod::Method)); - - data.insert("methods", methods); - - QVariantMap signalsMap; - foreach (JsonHandler *handler, m_handlers) - signalsMap.unite(handler->introspect(QMetaMethod::Signal)); - - data.insert("notifications", signalsMap); - - return createReply(data); + return createReply(m_api); } -JsonReply* JsonRPCServer::Version(const QVariantMap ¶ms) const +JsonReply* JsonRPCServerImplementation::Version(const QVariantMap ¶ms) const { Q_UNUSED(params) @@ -307,7 +281,7 @@ JsonReply* JsonRPCServer::Version(const QVariantMap ¶ms) const return createReply(data); } -JsonReply* JsonRPCServer::SetNotificationStatus(const QVariantMap ¶ms) +JsonReply* JsonRPCServerImplementation::SetNotificationStatus(const QVariantMap ¶ms) { QUuid clientId = this->property("clientId").toUuid(); Q_ASSERT_X(m_clientTransports.contains(clientId), "JsonRPCServer", "Invalid client ID."); @@ -334,7 +308,7 @@ JsonReply* JsonRPCServer::SetNotificationStatus(const QVariantMap ¶ms) return createReply(returns); } -JsonReply *JsonRPCServer::CreateUser(const QVariantMap ¶ms) +JsonReply *JsonRPCServerImplementation::CreateUser(const QVariantMap ¶ms) { QString username = params.value("username").toString(); QString password = params.value("password").toString(); @@ -342,11 +316,11 @@ JsonReply *JsonRPCServer::CreateUser(const QVariantMap ¶ms) UserManager::UserError status = NymeaCore::instance()->userManager()->createUser(username, password); QVariantMap returns; - returns.insert("error", JsonTypes::userErrorToString(status)); + returns.insert("error", enumValueName(status)); return createReply(returns); } -JsonReply *JsonRPCServer::Authenticate(const QVariantMap ¶ms) +JsonReply *JsonRPCServerImplementation::Authenticate(const QVariantMap ¶ms) { QString username = params.value("username").toString(); QString password = params.value("password").toString(); @@ -361,7 +335,7 @@ JsonReply *JsonRPCServer::Authenticate(const QVariantMap ¶ms) return createReply(ret); } -JsonReply *JsonRPCServer::RequestPushButtonAuth(const QVariantMap ¶ms) +JsonReply *JsonRPCServerImplementation::RequestPushButtonAuth(const QVariantMap ¶ms) { QString deviceName = params.value("deviceName").toString(); QUuid clientId = this->property("clientId").toUuid(); @@ -376,36 +350,32 @@ JsonReply *JsonRPCServer::RequestPushButtonAuth(const QVariantMap ¶ms) return createReply(data); } -JsonReply *JsonRPCServer::Tokens(const QVariantMap ¶ms) const +JsonReply *JsonRPCServerImplementation::Tokens(const QVariantMap ¶ms) const { Q_UNUSED(params) QByteArray token = property("token").toByteArray(); QString username = NymeaCore::instance()->userManager()->userForToken(token); - if (username.isEmpty()) { - // There *really* should be a user for the token in the DB - Q_ASSERT(false); - } QList tokens = NymeaCore::instance()->userManager()->tokens(username); QVariantList retList; foreach (const TokenInfo &tokenInfo, tokens) { - retList << JsonTypes::packTokenInfo(tokenInfo); + retList << pack(tokenInfo); } QVariantMap retMap; retMap.insert("tokenInfoList", retList); return createReply(retMap); } -JsonReply *JsonRPCServer::RemoveToken(const QVariantMap ¶ms) +JsonReply *JsonRPCServerImplementation::RemoveToken(const QVariantMap ¶ms) { QUuid tokenId = params.value("tokenId").toUuid(); UserManager::UserError error = NymeaCore::instance()->userManager()->removeToken(tokenId); QVariantMap ret; - ret.insert("error", JsonTypes::userErrorToString(error)); + ret.insert("error", enumValueName(error)); return createReply(ret); } -JsonReply *JsonRPCServer::SetupCloudConnection(const QVariantMap ¶ms) +JsonReply *JsonRPCServerImplementation::SetupCloudConnection(const QVariantMap ¶ms) { if (NymeaCore::instance()->cloudManager()->connectionState() != CloudManager::CloudConnectionStateUnconfigured) { qCDebug(dcCloud) << "Cloud already configured. Not changing configuration as it won't work anyways. If you want to reconfigure this instance to a different cloud, change the system UUID and wipe the cloud settings from the config."; @@ -424,7 +394,7 @@ JsonReply *JsonRPCServer::SetupCloudConnection(const QVariantMap ¶ms) return createReply(ret); } -JsonReply *JsonRPCServer::SetupRemoteAccess(const QVariantMap ¶ms) +JsonReply *JsonRPCServerImplementation::SetupRemoteAccess(const QVariantMap ¶ms) { QString idToken = params.value("idToken").toString(); QString userId = params.value("userId").toString(); @@ -437,18 +407,18 @@ JsonReply *JsonRPCServer::SetupRemoteAccess(const QVariantMap ¶ms) return reply; } -JsonReply *JsonRPCServer::IsCloudConnected(const QVariantMap ¶ms) +JsonReply *JsonRPCServerImplementation::IsCloudConnected(const QVariantMap ¶ms) { Q_UNUSED(params) bool connected = NymeaCore::instance()->cloudManager()->connectionState() == CloudManager::CloudConnectionStateConnected; QVariantMap data; data.insert("connected", connected); - data.insert("connectionState", JsonTypes::cloudConnectionStateToString(NymeaCore::instance()->cloudManager()->connectionState())); + data.insert("connectionState", enumValueName(NymeaCore::instance()->cloudManager()->connectionState())); return createReply(data); } /*! A client may use this as a ping/pong mechanism to check server connectivity. */ -JsonReply *JsonRPCServer::KeepAlive(const QVariantMap ¶ms) +JsonReply *JsonRPCServerImplementation::KeepAlive(const QVariantMap ¶ms) { QString sessionId = params.value("sessionId").toString(); qCDebug(dcJsonRpc()) << "KeepAlive received" << sessionId; @@ -459,42 +429,55 @@ JsonReply *JsonRPCServer::KeepAlive(const QVariantMap ¶ms) } /*! Returns the list of registered \l{JsonHandler}{JsonHandlers} and their name.*/ -QHash JsonRPCServer::handlers() const +QHash JsonRPCServerImplementation::handlers() const { return m_handlers; } /*! Register a new \l{TransportInterface} to the JSON server. If the given interface is already registered, just the authenticationRequired flag will be updated. */ -void JsonRPCServer::registerTransportInterface(TransportInterface *interface, bool authenticationRequired) +void JsonRPCServerImplementation::registerTransportInterface(TransportInterface *interface, bool authenticationRequired) { if (!m_interfaces.contains(interface)) { - connect(interface, &TransportInterface::clientConnected, this, &JsonRPCServer::clientConnected); - connect(interface, &TransportInterface::clientDisconnected, this, &JsonRPCServer::clientDisconnected); - connect(interface, &TransportInterface::dataAvailable, this, &JsonRPCServer::processData); + connect(interface, &TransportInterface::clientConnected, this, &JsonRPCServerImplementation::clientConnected); + connect(interface, &TransportInterface::clientDisconnected, this, &JsonRPCServerImplementation::clientDisconnected); + connect(interface, &TransportInterface::dataAvailable, this, &JsonRPCServerImplementation::processData); m_interfaces.insert(interface, authenticationRequired); } else { m_interfaces[interface] = authenticationRequired; } } -void JsonRPCServer::unregisterTransportInterface(TransportInterface *interface) +void JsonRPCServerImplementation::unregisterTransportInterface(TransportInterface *interface) { - disconnect(interface, &TransportInterface::clientConnected, this, &JsonRPCServer::clientConnected); - disconnect(interface, &TransportInterface::clientDisconnected, this, &JsonRPCServer::clientDisconnected); - disconnect(interface, &TransportInterface::dataAvailable, this, &JsonRPCServer::processData); + disconnect(interface, &TransportInterface::clientConnected, this, &JsonRPCServerImplementation::clientConnected); + disconnect(interface, &TransportInterface::clientDisconnected, this, &JsonRPCServerImplementation::clientDisconnected); + disconnect(interface, &TransportInterface::dataAvailable, this, &JsonRPCServerImplementation::processData); m_interfaces.take(interface); } +bool JsonRPCServerImplementation::registerExperienceHandler(JsonHandler *handler, int majorVersion, int minorVersion) +{ + bool ret = registerHandler(handler); + if (ret) { + m_experiences.insert(handler, QString("%1.%2").arg(majorVersion).arg(minorVersion)); + } + return ret; +} + /*! Send a JSON success response to the client with the given \a clientId, * \a commandId and \a params to the inerted \l{TransportInterface}. */ -void JsonRPCServer::sendResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QVariantMap ¶ms) +void JsonRPCServerImplementation::sendResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QVariantMap ¶ms, const QString &deprecationWarning) { QVariantMap response; response.insert("id", commandId); response.insert("status", "success"); response.insert("params", params); + if (!deprecationWarning.isEmpty()) { + response.insert("deprecationWarning", deprecationWarning); + } + QByteArray data = QJsonDocument::fromVariant(response).toJson(QJsonDocument::Compact); qCDebug(dcJsonRpcTraffic()) << "Sending data:" << data; interface->sendData(clientId, data); @@ -503,7 +486,7 @@ void JsonRPCServer::sendResponse(TransportInterface *interface, const QUuid &cli /*! Send a JSON error response to the client with the given \a clientId, * \a commandId and \a error to the inerted \l{TransportInterface}. */ -void JsonRPCServer::sendErrorResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QString &error) +void JsonRPCServerImplementation::sendErrorResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QString &error) { QVariantMap errorResponse; errorResponse.insert("id", commandId); @@ -515,7 +498,7 @@ void JsonRPCServer::sendErrorResponse(TransportInterface *interface, const QUuid interface->sendData(clientId, data); } -void JsonRPCServer::sendUnauthorizedResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QString &error) +void JsonRPCServerImplementation::sendUnauthorizedResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QString &error) { QVariantMap errorResponse; errorResponse.insert("id", commandId); @@ -527,7 +510,7 @@ void JsonRPCServer::sendUnauthorizedResponse(TransportInterface *interface, cons interface->sendData(clientId, data); } -QVariantMap JsonRPCServer::createWelcomeMessage(TransportInterface *interface, const QUuid &clientId) const +QVariantMap JsonRPCServerImplementation::createWelcomeMessage(TransportInterface *interface, const QUuid &clientId) const { QVariantMap handshake; handshake.insert("server", "nymea"); @@ -541,10 +524,20 @@ QVariantMap JsonRPCServer::createWelcomeMessage(TransportInterface *interface, c handshake.insert("initialSetupRequired", (interface->configuration().authenticationEnabled ? NymeaCore::instance()->userManager()->initRequired() : false)); handshake.insert("authenticationRequired", interface->configuration().authenticationEnabled); handshake.insert("pushButtonAuthAvailable", NymeaCore::instance()->userManager()->pushButtonAuthAvailable()); + if (!m_experiences.isEmpty()) { + QVariantList experiences; + foreach (JsonHandler* handler, m_experiences.keys()) { + QVariantMap experience; + experience.insert("name", handler->name()); + experience.insert("version", m_experiences.value(handler)); + experiences.append(experience); + } + handshake.insert("experiences", experiences); + } return handshake; } -void JsonRPCServer::setup() +void JsonRPCServerImplementation::setup() { registerHandler(this); registerHandler(new DeviceHandler(this)); @@ -558,11 +551,11 @@ void JsonRPCServer::setup() registerHandler(new TagsHandler(this)); registerHandler(new SystemHandler(NymeaCore::instance()->platform(), this)); - connect(NymeaCore::instance()->cloudManager(), &CloudManager::pairingReply, this, &JsonRPCServer::pairingFinished); - connect(NymeaCore::instance()->cloudManager(), &CloudManager::connectionStateChanged, this, &JsonRPCServer::onCloudConnectionStateChanged); + connect(NymeaCore::instance()->cloudManager(), &CloudManager::pairingReply, this, &JsonRPCServerImplementation::pairingFinished); + connect(NymeaCore::instance()->cloudManager(), &CloudManager::connectionStateChanged, this, &JsonRPCServerImplementation::onCloudConnectionStateChanged); } -void JsonRPCServer::processData(const QUuid &clientId, const QByteArray &data) +void JsonRPCServerImplementation::processData(const QUuid &clientId, const QByteArray &data) { qCDebug(dcJsonRpcTraffic()) << "Incoming data:" << data; @@ -589,7 +582,7 @@ void JsonRPCServer::processData(const QUuid &clientId, const QByteArray &data) } } -void JsonRPCServer::processJsonPacket(TransportInterface *interface, const QUuid &clientId, const QByteArray &data) +void JsonRPCServerImplementation::processJsonPacket(TransportInterface *interface, const QUuid &clientId, const QByteArray &data) { QJsonParseError error; QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); @@ -646,19 +639,26 @@ void JsonRPCServer::processJsonPacket(TransportInterface *interface, const QUuid JsonHandler *handler = m_handlers.value(targetNamespace); if (!handler) { + qCWarning(dcJsonRpc()) << "JSON RPC method called for invalid namespace:" << targetNamespace; sendErrorResponse(interface, clientId, commandId, "No such namespace"); return; } - if (!handler->hasMethod(method)) { + if (!handler->jsonMethods().contains(method)) { + qCWarning(dcJsonRpc()) << QString("JSON RPC method called for invalid method: %1.%2").arg(targetNamespace).arg(method); sendErrorResponse(interface, clientId, commandId, "No such method"); return; } QVariantMap params = message.value("params").toMap(); - QPair validationResult = handler->validateParams(method, params); - if (!validationResult.first) { - sendErrorResponse(interface, clientId, commandId, "Invalid params: " + validationResult.second); + QVariantMap definition = handler->jsonMethods().value(method).toMap().value("params").toMap(); + JsonValidator validator; + JsonValidator::Result validationResult = validator.validateParams(params, targetNamespace + '.' + method, m_api); + if (!validationResult.success()) { + qCWarning(dcJsonRpc()) << "JSON RPC parameter verification failed for method" << targetNamespace + '.' + method; + qCWarning(dcJsonRpc()) << validationResult.errorString() << "in" << validationResult.where(); + qCWarning(dcJsonRpc()) << "Call params:" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson()); + sendErrorResponse(interface, clientId, commandId, "Invalid params: " + validationResult.errorString() + " in " + validationResult.where()); return; } @@ -691,49 +691,68 @@ void JsonRPCServer::processJsonPacket(TransportInterface *interface, const QUuid m_asyncReplies.insert(reply, interface); reply->setClientId(clientId); reply->setCommandId(commandId); - connect(reply, &JsonReply::finished, this, &JsonRPCServer::asyncReplyFinished); + connect(reply, &JsonReply::finished, this, &JsonRPCServerImplementation::asyncReplyFinished); reply->startWait(); } else { - Q_ASSERT_X((targetNamespace == "JSONRPC" && method == "Introspect") || handler->validateReturns(method, reply->data()).first - ,"validating return value", formatAssertion(targetNamespace, method, QMetaMethod::Method, handler, reply->data()).toLatin1().data()); - sendResponse(interface, clientId, commandId, reply->data()); + JsonValidator validator; + Q_ASSERT_X((targetNamespace == "JSONRPC" && method == "Introspect") || validator.validateReturns(reply->data(), targetNamespace + '.' + method, m_api).success(), + validator.result().where().toUtf8(), + validator.result().errorString().toUtf8() + "\nReturn value:\n" + QJsonDocument::fromVariant(reply->data()).toJson()); + + QString deprecationWarning; + if (m_api.value("methods").toMap().value(targetNamespace + '.' + method).toMap().contains("deprecated")) { + deprecationWarning = m_api.value("methods").toMap().value(targetNamespace + '.' + method).toMap().value("deprecated").toString(); + qCWarning(dcJsonRpc()) << "Client uses deprecated API. Please update client implementation!"; + qCWarning(dcJsonRpc()) << targetNamespace + '.' + method + ':' << deprecationWarning; + } + + sendResponse(interface, clientId, commandId, reply->data(), deprecationWarning); reply->deleteLater(); } } -QString JsonRPCServer::formatAssertion(const QString &targetNamespace, const QString &method, QMetaMethod::MethodType methodType, JsonHandler *handler, const QVariantMap &data) const -{ - QJsonDocument doc = QJsonDocument::fromVariant(handler->introspect(methodType).value(targetNamespace + "." + method)); - QJsonDocument doc2 = QJsonDocument::fromVariant(data); - return QString("\nMethod: %1\nTemplate: %2\nValue: %3") - .arg(targetNamespace + "." + method) - .arg(QString(doc.toJson(QJsonDocument::Indented))) - .arg(QString(doc2.toJson(QJsonDocument::Indented))); -} - -void JsonRPCServer::sendNotification(const QVariantMap ¶ms) +void JsonRPCServerImplementation::sendNotification(const QVariantMap ¶ms) { JsonHandler *handler = qobject_cast(sender()); QMetaMethod method = handler->metaObject()->method(senderSignalIndex()); + QList clientsToBeNotified; + foreach (const QUuid &clientId, m_clientNotifications.keys()) { + if (m_clientNotifications.value(clientId).contains(handler->name())) { + clientsToBeNotified.append(clientId); + } + } + if (clientsToBeNotified.isEmpty()) { + return; + } + QVariantMap notification; notification.insert("id", m_notificationId++); notification.insert("notification", handler->name() + "." + method.name()); notification.insert("params", params); - Q_ASSERT_X(handler->validateParams(method.name(), params).first, "validating return value", formatAssertion(handler->name(), method.name(), QMetaMethod::Signal, handler, notification).toLatin1().data()); + JsonValidator validator; + Q_ASSERT_X(validator.validateNotificationParams(params, handler->name() + '.' + method.name(), m_api).success(), + validator.result().where().toUtf8(), + validator.result().errorString().toUtf8()); + + if (m_api.value("notifications").toMap().value(handler->name() + '.' + method.name()).toMap().contains("deprecated")) { + QString deprecationMessage = m_api.value("notifications").toMap().value(handler->name() + '.' + method.name()).toMap().value("deprecated").toString(); + qCWarning(dcJsonRpc()) << "Client uses deprecated API. Please update client implementation!"; + qCWarning(dcJsonRpc()) << handler->name() + '.' + method.name() + ':' << deprecationMessage; + notification.insert("deprecationWarning", deprecationMessage); + } + QByteArray data = QJsonDocument::fromVariant(notification).toJson(QJsonDocument::Compact); - qCDebug(dcJsonRpc()) << "Sending notification:" << handler->name() + "." + method.name(); qCDebug(dcJsonRpcTraffic()) << "Notification content:" << data; - foreach (const QUuid &clientId, m_clientNotifications.keys()) { - if (m_clientNotifications.value(clientId).contains(handler->name())) { - m_clientTransports.value(clientId)->sendData(clientId, data); - } + foreach (const QUuid &clientId, clientsToBeNotified) { + qCDebug(dcJsonRpc()) << "Sending notification:" << handler->name() + "." + method.name(); + m_clientTransports.value(clientId)->sendData(clientId, data); } } -void JsonRPCServer::asyncReplyFinished() +void JsonRPCServerImplementation::asyncReplyFinished() { JsonReply *reply = qobject_cast(sender()); TransportInterface *interface = m_asyncReplies.take(reply); @@ -743,9 +762,20 @@ void JsonRPCServer::asyncReplyFinished() return; } if (!reply->timedOut()) { - Q_ASSERT_X(reply->handler()->validateReturns(reply->method(), reply->data()).first - ,"validating return value", formatAssertion(reply->handler()->name(), reply->method(), QMetaMethod::Method, reply->handler(), reply->data()).toLatin1().data()); - sendResponse(interface, reply->clientId(), reply->commandId(), reply->data()); + JsonValidator validator; + QString method = reply->handler()->name() + '.' + reply->method(); + Q_ASSERT_X(validator.validateReturns(reply->data(), method, m_api).success() + ,validator.result().where().toUtf8() + ,validator.result().errorString().toUtf8() + "\nReturn value:\n" + QJsonDocument::fromVariant(reply->data()).toJson()); + + QString deprecationWarning; + if (m_api.value("methods").toMap().value(method).toMap().contains("deprecated")) { + deprecationWarning = m_api.value("methods").toMap().value(method).toMap().value("deprecated").toString(); + qCWarning(dcJsonRpc()) << "Client uses deprecated API. Please update client implementation!"; + qCWarning(dcJsonRpc()) << method + ':' << deprecationWarning; + } + + sendResponse(interface, reply->clientId(), reply->commandId(), reply->data(), deprecationWarning); } else { qCWarning(dcJsonRpc()) << "RPC call timed out:" << reply->handler()->name() << ":" << reply->method(); sendErrorResponse(interface, reply->clientId(), reply->commandId(), "Command timed out"); @@ -754,7 +784,7 @@ void JsonRPCServer::asyncReplyFinished() reply->deleteLater(); } -void JsonRPCServer::pairingFinished(QString cognitoUserId, int status, const QString &message) +void JsonRPCServerImplementation::pairingFinished(QString cognitoUserId, int status, const QString &message) { JsonReply *reply = m_pairingRequests.take(cognitoUserId); if (!reply) { @@ -767,15 +797,15 @@ void JsonRPCServer::pairingFinished(QString cognitoUserId, int status, const QSt reply->finished(); } -void JsonRPCServer::onCloudConnectionStateChanged() +void JsonRPCServerImplementation::onCloudConnectionStateChanged() { QVariantMap params; params.insert("connected", NymeaCore::instance()->cloudManager()->connectionState() == CloudManager::CloudConnectionStateConnected); - params.insert("connectionState", JsonTypes::cloudConnectionStateToString(NymeaCore::instance()->cloudManager()->connectionState())); + params.insert("connectionState", enumValueName(NymeaCore::instance()->cloudManager()->connectionState())); emit CloudConnectedChanged(params); } -void JsonRPCServer::onPushButtonAuthFinished(int transactionId, bool success, const QByteArray &token) +void JsonRPCServerImplementation::onPushButtonAuthFinished(int transactionId, bool success, const QByteArray &token) { QUuid clientId = m_pushButtonTransactions.take(transactionId); if (clientId.isNull()) { @@ -804,8 +834,99 @@ void JsonRPCServer::onPushButtonAuthFinished(int transactionId, bool success, co transport->sendData(clientId, QJsonDocument::fromVariant(notification).toJson(QJsonDocument::Compact)); } -void JsonRPCServer::registerHandler(JsonHandler *handler) +bool JsonRPCServerImplementation::registerHandler(JsonHandler *handler) { + // Sanity checks on API: + // * Make sure all $ref: entries are valid. + // * A handler must not register a type name that is already registered by a previously loaded handler with different content. + QVariantMap methods = m_api.value("methods").toMap(); + QVariantMap notifications = m_api.value("notifications").toMap(); + QVariantMap apiIncludingThis = m_api; + + // Verify enums name clash + QVariantMap enums = m_api.value("enums").toMap(); + foreach (const QString &enumName, handler->jsonEnums().keys()) { + QVariantList list = handler->jsonEnums().value(enumName).toList(); + if (enums.contains(enumName) && enums.value(enumName) != list) { + qCWarning(dcJsonRpc()) << "Enum type" << enumName << "is already registered. Not registering handler" << handler->name(); + return false; + } + enums.insert(enumName, list); + } + apiIncludingThis["enums"] = enums; + + QVariantMap flags = m_api.value("flags").toMap(); + foreach (const QString &flagName, handler->jsonFlags().keys()) { + QVariant flagDescription = handler->jsonFlags().value(flagName); + if (enums.contains(flagName)) { + qCWarning(dcJsonRpc()) << "Enum with name" << flagName << "is already registered. Not registering handler" << handler->name(); + return false; + } + if (flags.contains(flagName) && flags.value(flagName) != handler->jsonFlags().value(flagName)) { + qCWarning(dcJsonRpc()) << "Flags with name" << flagName << "is already registered. Not registering handler" << handler->name(); + return false; + } + flags.insert(flagName, flagDescription); + } + apiIncludingThis["flags"] = flags; + + // Verify objects + QVariantMap existingTypes = m_api.value("types").toMap(); + QVariantMap typesIncludingThis = existingTypes; + typesIncludingThis.unite(handler->jsonObjects()); + apiIncludingThis["types"] = typesIncludingThis; + foreach (const QString &objectName, handler->jsonObjects().keys()) { + QVariantMap object = handler->jsonObjects().value(objectName).toMap(); + // Check for name clashes + if (existingTypes.contains(objectName) && existingTypes.value(objectName) != handler->jsonObjects().value(objectName)) { + qCWarning(dcJsonRpc()) << "Object type" << objectName << "is already registered. Not registering handler" << handler->name(); + return false; + } + // Check for invalid $ref: entries + if (!JsonValidator::checkRefs(object, apiIncludingThis)) { + qCWarning(dcJsonRpc()).nospace() << "Invalid reference in object type " << objectName << ". Not registering handler " << handler->name(); + return false; + } + } + + // Verify methods + QVariantMap newMethods; + foreach (const QString &methodName, handler->jsonMethods().keys()) { + QVariantMap method = handler->jsonMethods().value(methodName).toMap(); + if (handler->metaObject()->indexOfMethod(methodName.toUtf8() + "(QVariantMap)") < 0) { + qCWarning(dcJsonRpc()).nospace().noquote() << "Invalid method \"" << methodName << "\". Method \"JsonReply* " + methodName + "(QVariantMap)\" does not exist. Not registering handler " << handler->name(); + return false; + } + if (!JsonValidator::checkRefs(method.value("params").toMap(), apiIncludingThis)) { + qCWarning(dcJsonRpc()).nospace() << "Invalid reference in params of method " << methodName << ". Not registering handler " << handler->name(); + return false; + } + if (!JsonValidator::checkRefs(method.value("returns").toMap(), apiIncludingThis)) { + qCWarning(dcJsonRpc()).nospace() << "Invalid reference in return value of method " << methodName << ". Not registering handler " << handler->name(); + return false; + } + newMethods.insert(handler->name() + '.' + methodName, method); + } + methods.unite(newMethods); + apiIncludingThis["methods"] = methods; + + // Verify notifications + QVariantMap newNotifications; + foreach (const QString ¬ificationName, handler->jsonNotifications().keys()) { + QVariantMap notification = handler->jsonNotifications().value(notificationName).toMap(); + if (!JsonValidator::checkRefs(notification.value("params").toMap(), apiIncludingThis)) { + qCWarning(dcJsonRpc()).nospace() << "Invalid reference in params of notification " << notificationName << ". Not registering handler " << handler->name(); + return false; + } + newNotifications.insert(handler->name() + '.' + notificationName, notification); + } + notifications.unite(newNotifications); + apiIncludingThis["notifications"] = notifications; + + // Checks completed. Store new API + qCDebug(dcJsonRpc()) << "Registering JSON RPC handler:" << handler->name(); + m_api = apiIncludingThis; + m_handlers.insert(handler->name(), handler); for (int i = 0; i < handler->metaObject()->methodCount(); ++i) { QMetaMethod method = handler->metaObject()->method(i); @@ -813,9 +934,10 @@ void JsonRPCServer::registerHandler(JsonHandler *handler) QObject::connect(handler, method, this, metaObject()->method(metaObject()->indexOfSlot("sendNotification(QVariantMap)"))); } } + return true; } -void JsonRPCServer::clientConnected(const QUuid &clientId) +void JsonRPCServerImplementation::clientConnected(const QUuid &clientId) { qCDebug(dcJsonRpc()) << "Client connected with uuid" << clientId.toString(); TransportInterface *interface = qobject_cast(sender()); @@ -836,7 +958,7 @@ void JsonRPCServer::clientConnected(const QUuid &clientId) timer->start(10000); } -void JsonRPCServer::clientDisconnected(const QUuid &clientId) +void JsonRPCServerImplementation::clientDisconnected(const QUuid &clientId) { qCDebug(dcJsonRpc()) << "Client disconnected:" << clientId; m_clientTransports.remove(clientId); diff --git a/libnymea-core/jsonrpc/jsonrpcserver.h b/libnymea-core/jsonrpc/jsonrpcserverimplementation.h similarity index 88% rename from libnymea-core/jsonrpc/jsonrpcserver.h rename to libnymea-core/jsonrpc/jsonrpcserverimplementation.h index 09fc0d21..097066e7 100644 --- a/libnymea-core/jsonrpc/jsonrpcserver.h +++ b/libnymea-core/jsonrpc/jsonrpcserverimplementation.h @@ -19,10 +19,11 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef JSONRPCSERVER_H -#define JSONRPCSERVER_H +#ifndef JSONRPCSERVERIMPLEMENTATION_H +#define JSONRPCSERVERIMPLEMENTATION_H -#include "jsonhandler.h" +#include "jsonrpc/jsonrpcserver.h" +#include "jsonrpc/jsonhandler.h" #include "transportinterface.h" #include "usermanager/usermanager.h" @@ -39,11 +40,11 @@ class Device; namespace nymeaserver { -class JsonRPCServer: public JsonHandler +class JsonRPCServerImplementation: public JsonHandler, public JsonRPCServer { Q_OBJECT public: - JsonRPCServer(const QSslConfiguration &sslConfiguration = QSslConfiguration(), QObject *parent = nullptr); + JsonRPCServerImplementation(const QSslConfiguration &sslConfiguration = QSslConfiguration(), QObject *parent = nullptr); // JsonHandler API implementation QString name() const; @@ -71,10 +72,13 @@ public: void registerTransportInterface(TransportInterface *interface, bool authenticationRequired); void unregisterTransportInterface(TransportInterface *interface); + bool registerExperienceHandler(JsonHandler *handler, int majorVersion, int minorVersion) override; + private: + bool registerHandler(JsonHandler *handler); QHash handlers() const; - void sendResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QVariantMap ¶ms = QVariantMap()); + void sendResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QVariantMap ¶ms = QVariantMap(), const QString &deprecationWarning = QString()); void sendErrorResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QString &error); void sendUnauthorizedResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QString &error); QVariantMap createWelcomeMessage(TransportInterface *interface, const QUuid &clientId) const; @@ -98,6 +102,8 @@ private slots: void onPushButtonAuthFinished(int transactionId, bool success, const QByteArray &token); private: + QVariantMap m_api; + QHash m_experiences; QMap m_interfaces; // Interface, authenticationRequired QHash m_handlers; QHash m_asyncReplies; @@ -113,10 +119,10 @@ private: int m_notificationId; - void registerHandler(JsonHandler *handler); QString formatAssertion(const QString &targetNamespace, const QString &method, QMetaMethod::MethodType methodType, JsonHandler *handler, const QVariantMap &data) const; }; } -#endif // JSONRPCSERVER_H +#endif // JSONRPCSERVERIMPLEMENTATION_H + diff --git a/libnymea-core/jsonrpc/jsontypes.cpp b/libnymea-core/jsonrpc/jsontypes.cpp deleted file mode 100644 index 717d6f48..00000000 --- a/libnymea-core/jsonrpc/jsontypes.cpp +++ /dev/null @@ -1,2392 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2015 Simon Stürz * - * Copyright (C) 2014 Michael Zanetti * - * Copyright (C) 2017 Michael Zanetti * - * * - * This file is part of nymea. * - * * - * nymea 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. * - * * - * nymea 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 nymea. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -/*! - \class nymeaserver::JsonTypes - \brief This class represents the types for the JSON-RPC API. - - \ingroup json - \inmodule core - - This class represents all JSON-RPC API types and allows to transform Json - objects into c++ objects and vers visa. - -*/ - -/*! \enum nymeaserver::JsonTypes::BasicType - - This enum type specifies the basic types of a JSON RPC API. - - \value Uuid - \value String - \value Int - \value Uint - \value Double - \value Bool - \value Variant - \value Color - \value Time - \value Object -*/ - -#include "jsontypes.h" - -#include "devices/device.h" -#include "devices/devicemanager.h" -#include "devices/deviceplugin.h" -#include "nymeacore.h" -#include "ruleengine/ruleengine.h" -#include "loggingcategories.h" -#include "logging/logvaluetool.h" - -#include "types/mediabrowseritem.h" - -#include -#include -#include -#include - -namespace nymeaserver { - -bool JsonTypes::s_initialized = false; -QString JsonTypes::s_lastError; - -QVariantList JsonTypes::s_basicType; -QVariantList JsonTypes::s_stateOperator; -QVariantList JsonTypes::s_valueOperator; -QVariantList JsonTypes::s_inputType; -QVariantList JsonTypes::s_unit; -QVariantList JsonTypes::s_createMethod; -QVariantList JsonTypes::s_setupMethod; -QVariantList JsonTypes::s_removePolicy; -QVariantList JsonTypes::s_deviceError; -QVariantList JsonTypes::s_ruleError; -QVariantList JsonTypes::s_loggingError; -QVariantList JsonTypes::s_loggingSource; -QVariantList JsonTypes::s_loggingLevel; -QVariantList JsonTypes::s_loggingEventType; -QVariantList JsonTypes::s_repeatingMode; -QVariantList JsonTypes::s_configurationError; -QVariantList JsonTypes::s_networkManagerError; -QVariantList JsonTypes::s_networkManagerState; -QVariantList JsonTypes::s_networkDeviceState; -QVariantList JsonTypes::s_userError; -QVariantList JsonTypes::s_tagError; -QVariantList JsonTypes::s_cloudConnectionState; -QVariantList JsonTypes::s_browserIcon; -QVariantList JsonTypes::s_mediaBrowserIcon; - -QVariantMap JsonTypes::s_paramType; -QVariantMap JsonTypes::s_param; -QVariantMap JsonTypes::s_ruleAction; -QVariantMap JsonTypes::s_ruleActionParam; -QVariantMap JsonTypes::s_paramDescriptor; -QVariantMap JsonTypes::s_stateType; -QVariantMap JsonTypes::s_state; -QVariantMap JsonTypes::s_stateDescriptor; -QVariantMap JsonTypes::s_stateEvaluator; -QVariantMap JsonTypes::s_eventType; -QVariantMap JsonTypes::s_event; -QVariantMap JsonTypes::s_eventDescriptor; -QVariantMap JsonTypes::s_actionType; -QVariantMap JsonTypes::s_action; -QVariantMap JsonTypes::s_plugin; -QVariantMap JsonTypes::s_vendor; -QVariantMap JsonTypes::s_deviceClass; -QVariantMap JsonTypes::s_device; -QVariantMap JsonTypes::s_deviceDescriptor; -QVariantMap JsonTypes::s_rule; -QVariantMap JsonTypes::s_ruleDescription; -QVariantMap JsonTypes::s_logEntry; -QVariantMap JsonTypes::s_timeDescriptor; -QVariantMap JsonTypes::s_calendarItem; -QVariantMap JsonTypes::s_timeEventItem; -QVariantMap JsonTypes::s_repeatingOption; -QVariantMap JsonTypes::s_wirelessAccessPoint; -QVariantMap JsonTypes::s_wiredNetworkDevice; -QVariantMap JsonTypes::s_wirelessNetworkDevice; -QVariantMap JsonTypes::s_tokenInfo; -QVariantMap JsonTypes::s_serverConfiguration; -QVariantMap JsonTypes::s_webServerConfiguration; -QVariantMap JsonTypes::s_tag; -QVariantMap JsonTypes::s_mqttPolicy; -QVariantMap JsonTypes::s_package; -QVariantMap JsonTypes::s_repository; -QVariantMap JsonTypes::s_browserItem; - -void JsonTypes::init() -{ - // Enums - s_basicType = enumToStrings(JsonTypes::staticMetaObject, "BasicType"); - s_stateOperator = enumToStrings(Types::staticMetaObject, "StateOperator"); - s_valueOperator = enumToStrings(Types::staticMetaObject, "ValueOperator"); - s_inputType = enumToStrings(Types::staticMetaObject, "InputType"); - s_unit = enumToStrings(Types::staticMetaObject, "Unit"); - s_createMethod = enumToStrings(DeviceClass::staticMetaObject, "CreateMethod"); - s_setupMethod = enumToStrings(DeviceClass::staticMetaObject, "SetupMethod"); - s_removePolicy = enumToStrings(RuleEngine::staticMetaObject, "RemovePolicy"); - s_deviceError = enumToStrings(Device::staticMetaObject, "DeviceError"); - s_ruleError = enumToStrings(RuleEngine::staticMetaObject, "RuleError"); - s_loggingError = enumToStrings(Logging::staticMetaObject, "LoggingError"); - s_loggingSource = enumToStrings(Logging::staticMetaObject, "LoggingSource"); - s_loggingLevel = enumToStrings(Logging::staticMetaObject, "LoggingLevel"); - s_loggingEventType = enumToStrings(Logging::staticMetaObject, "LoggingEventType"); - s_repeatingMode = enumToStrings(RepeatingOption::staticMetaObject, "RepeatingMode"); - s_configurationError = enumToStrings(NymeaConfiguration::staticMetaObject, "ConfigurationError"); - s_networkManagerError = enumToStrings(NetworkManager::staticMetaObject, "NetworkManagerError"); - s_networkManagerState = enumToStrings(NetworkManager::staticMetaObject, "NetworkManagerState"); - s_networkDeviceState = enumToStrings(NetworkDevice::staticMetaObject, "NetworkDeviceState"); - s_userError = enumToStrings(UserManager::staticMetaObject, "UserError"); - s_tagError = enumToStrings(TagsStorage::staticMetaObject, "TagError"); - s_cloudConnectionState = enumToStrings(CloudManager::staticMetaObject, "CloudConnectionState"); - s_browserIcon = enumToStrings(BrowserItem::staticMetaObject, "BrowserIcon"); - s_mediaBrowserIcon = enumToStrings(MediaBrowserItem::staticMetaObject, "MediaBrowserIcon"); - - // ParamType - s_paramType.insert("id", basicTypeToString(Uuid)); - s_paramType.insert("name", basicTypeToString(String)); - s_paramType.insert("displayName", basicTypeToString(String)); - s_paramType.insert("type", basicTypeRef()); - s_paramType.insert("index", basicTypeToString(Int)); - s_paramType.insert("o:defaultValue", basicTypeToString(Variant)); - s_paramType.insert("o:minValue", basicTypeToString(Variant)); - s_paramType.insert("o:maxValue", basicTypeToString(Variant)); - s_paramType.insert("o:allowedValues", QVariantList() << basicTypeToString(Variant)); - s_paramType.insert("o:inputType", inputTypeRef()); - s_paramType.insert("o:unit", unitRef()); - s_paramType.insert("o:readOnly", basicTypeToString(Bool)); - - // Param - s_param.insert("paramTypeId", basicTypeToString(Uuid)); - s_param.insert("value", basicTypeRef()); - - // RuleAction - s_ruleAction.insert("o:deviceId", basicTypeToString(Uuid)); - s_ruleAction.insert("o:actionTypeId", basicTypeToString(Uuid)); - s_ruleAction.insert("o:interface", basicTypeToString(String)); - s_ruleAction.insert("o:interfaceAction", basicTypeToString(String)); - s_ruleAction.insert("o:browserItemId", basicTypeToString(String)); - s_ruleAction.insert("o:ruleActionParams", QVariantList() << ruleActionParamRef()); - - // RuleActionParam - s_ruleActionParam.insert("o:paramTypeId", basicTypeToString(Uuid)); - s_ruleActionParam.insert("o:paramName", basicTypeToString(String)); - s_ruleActionParam.insert("o:value", basicTypeRef()); - s_ruleActionParam.insert("o:eventTypeId", basicTypeToString(Uuid)); - s_ruleActionParam.insert("o:eventParamTypeId", basicTypeToString(Uuid)); - s_ruleActionParam.insert("o:stateDeviceId", basicTypeToString(Uuid)); - s_ruleActionParam.insert("o:stateTypeId", basicTypeToString(Uuid)); - - // ParamDescriptor - s_paramDescriptor.insert("o:paramTypeId", basicTypeToString(Uuid)); - s_paramDescriptor.insert("o:paramName", basicTypeToString(Uuid)); - s_paramDescriptor.insert("value", basicTypeRef()); - s_paramDescriptor.insert("operator", valueOperatorRef()); - - // StateType - s_stateType.insert("id", basicTypeToString(Uuid)); - s_stateType.insert("name", basicTypeToString(String)); - s_stateType.insert("displayName", basicTypeToString(String)); - s_stateType.insert("type", basicTypeRef()); - s_stateType.insert("index", basicTypeToString(Int)); - s_stateType.insert("defaultValue", basicTypeToString(Variant)); - s_stateType.insert("o:unit", unitRef()); - s_stateType.insert("o:minValue", basicTypeToString(Variant)); - s_stateType.insert("o:maxValue", basicTypeToString(Variant)); - s_stateType.insert("o:possibleValues", QVariantList() << basicTypeToString(Variant)); - - // State - s_state.insert("stateTypeId", basicTypeToString(Uuid)); - s_state.insert("deviceId", basicTypeToString(Uuid)); - s_state.insert("value", basicTypeToString(Variant)); - - // StateDescriptor - s_stateDescriptor.insert("o:stateTypeId", basicTypeToString(Uuid)); - s_stateDescriptor.insert("o:deviceId", basicTypeToString(Uuid)); - s_stateDescriptor.insert("o:interface", basicTypeToString(String)); - s_stateDescriptor.insert("o:interfaceState", basicTypeToString(String)); - s_stateDescriptor.insert("value", basicTypeToString(Variant)); - s_stateDescriptor.insert("operator", valueOperatorRef()); - - // StateEvaluator - s_stateEvaluator.insert("o:stateDescriptor", stateDescriptorRef()); - s_stateEvaluator.insert("o:childEvaluators", QVariantList() << stateEvaluatorRef()); - s_stateEvaluator.insert("o:operator", stateOperatorRef()); - - // EventType - s_eventType.insert("id", basicTypeToString(Uuid)); - s_eventType.insert("name", basicTypeToString(String)); - s_eventType.insert("displayName", basicTypeToString(String)); - s_eventType.insert("index", basicTypeToString(Int)); - s_eventType.insert("paramTypes", QVariantList() << paramTypeRef()); - - // Event - s_event.insert("eventTypeId", basicTypeToString(Uuid)); - s_event.insert("deviceId", basicTypeToString(Uuid)); - s_event.insert("o:params", QVariantList() << paramRef()); - - // EventDescriptor - s_eventDescriptor.insert("o:eventTypeId", basicTypeToString(Uuid)); - s_eventDescriptor.insert("o:deviceId", basicTypeToString(Uuid)); - s_eventDescriptor.insert("o:interface", basicTypeToString(String)); - s_eventDescriptor.insert("o:interfaceEvent", basicTypeToString(String)); - s_eventDescriptor.insert("o:paramDescriptors", QVariantList() << paramDescriptorRef()); - - // ActionType - s_actionType.insert("id", basicTypeToString(Uuid)); - s_actionType.insert("name", basicTypeToString(String)); - s_actionType.insert("displayName", basicTypeToString(String)); - s_actionType.insert("index", basicTypeToString(Int)); - s_actionType.insert("paramTypes", QVariantList() << paramTypeRef()); - - // Action - s_action.insert("actionTypeId", basicTypeToString(Uuid)); - s_action.insert("deviceId", basicTypeToString(Uuid)); - s_action.insert("o:params", QVariantList() << paramRef()); - - // Pugin - s_plugin.insert("id", basicTypeToString(Uuid)); - s_plugin.insert("name", basicTypeToString(String)); - s_plugin.insert("displayName", basicTypeToString(String)); - s_plugin.insert("paramTypes", QVariantList() << paramTypeRef()); - - // Vendor - s_vendor.insert("id", basicTypeToString(Uuid)); - s_vendor.insert("name", basicTypeToString(String)); - s_vendor.insert("displayName", basicTypeToString(String)); - - // DeviceClass - s_deviceClass.insert("id", basicTypeToString(Uuid)); - s_deviceClass.insert("vendorId", basicTypeToString(Uuid)); - s_deviceClass.insert("pluginId", basicTypeToString(Uuid)); - s_deviceClass.insert("name", basicTypeToString(String)); - s_deviceClass.insert("displayName", basicTypeToString(String)); - s_deviceClass.insert("interfaces", QVariantList() << basicTypeToString(String)); - s_deviceClass.insert("browsable", basicTypeToString(Bool)); - s_deviceClass.insert("setupMethod", setupMethodRef()); - s_deviceClass.insert("createMethods", QVariantList() << createMethodRef()); - s_deviceClass.insert("stateTypes", QVariantList() << stateTypeRef()); - s_deviceClass.insert("eventTypes", QVariantList() << eventTypeRef()); - s_deviceClass.insert("actionTypes", QVariantList() << actionTypeRef()); - s_deviceClass.insert("browserItemActionTypes", QVariantList() << actionTypeRef()); - s_deviceClass.insert("paramTypes", QVariantList() << paramTypeRef()); - s_deviceClass.insert("settingsTypes", QVariantList() << paramTypeRef()); - s_deviceClass.insert("discoveryParamTypes", QVariantList() << paramTypeRef()); - - // Device - s_device.insert("id", basicTypeToString(Uuid)); - s_device.insert("deviceClassId", basicTypeToString(Uuid)); - s_device.insert("name", basicTypeToString(String)); - s_device.insert("params", QVariantList() << paramRef()); - s_device.insert("settings", QVariantList() << paramRef()); - QVariantMap stateValues; - stateValues.insert("stateTypeId", basicTypeToString(Uuid)); - stateValues.insert("value", basicTypeToString(Variant)); - s_device.insert("states", QVariantList() << stateValues); - s_device.insert("setupComplete", basicTypeToString(Bool)); - s_device.insert("o:parentId", basicTypeToString(Uuid)); - - // DeviceDescriptor - s_deviceDescriptor.insert("id", basicTypeToString(Uuid)); - s_deviceDescriptor.insert("deviceId", basicTypeToString(Uuid)); - s_deviceDescriptor.insert("title", basicTypeToString(String)); - s_deviceDescriptor.insert("description", basicTypeToString(String)); - s_deviceDescriptor.insert("deviceParams", QVariantList() << paramRef()); - - // Rule - s_rule.insert("id", basicTypeToString(Uuid)); - s_rule.insert("name", basicTypeToString(String)); - s_rule.insert("enabled", basicTypeToString(Bool)); - s_rule.insert("executable", basicTypeToString(Bool)); - s_rule.insert("active", basicTypeToString(Bool)); - s_rule.insert("eventDescriptors", QVariantList() << eventDescriptorRef()); - s_rule.insert("actions", QVariantList() << ruleActionRef()); - s_rule.insert("exitActions", QVariantList() << ruleActionRef()); - s_rule.insert("stateEvaluator", stateEvaluatorRef()); - s_rule.insert("timeDescriptor", timeDescriptorRef()); - - // RuleDescription - s_ruleDescription.insert("id", basicTypeToString(Uuid)); - s_ruleDescription.insert("name", basicTypeToString(String)); - s_ruleDescription.insert("enabled", basicTypeToString(Bool)); - s_ruleDescription.insert("active", basicTypeToString(Bool)); - s_ruleDescription.insert("executable", basicTypeToString(Bool)); - - // LogEntry - s_logEntry.insert("timestamp", basicTypeToString(Int)); - s_logEntry.insert("loggingLevel", loggingLevelRef()); - s_logEntry.insert("source", loggingSourceRef()); - s_logEntry.insert("o:typeId", basicTypeToString(Uuid)); - s_logEntry.insert("o:deviceId", basicTypeToString(Uuid)); - s_logEntry.insert("o:itemId", basicTypeToString(String)); - s_logEntry.insert("o:value", basicTypeToString(String)); - s_logEntry.insert("o:active", basicTypeToString(Bool)); - s_logEntry.insert("o:eventType", loggingEventTypeRef()); - s_logEntry.insert("o:errorCode", basicTypeToString(String)); - - // TimeDescriptor - s_timeDescriptor.insert("o:calendarItems", QVariantList() << calendarItemRef()); - s_timeDescriptor.insert("o:timeEventItems", QVariantList() << timeEventItemRef()); - - // CalendarItem - s_calendarItem.insert("o:datetime", basicTypeToString(QVariant::UInt)); - s_calendarItem.insert("o:startTime", basicTypeToString(QVariant::Time)); - s_calendarItem.insert("duration", basicTypeToString(QVariant::UInt)); - s_calendarItem.insert("o:repeating", repeatingOptionRef()); - - // TimeEventItem - s_timeEventItem.insert("o:datetime", basicTypeToString(QVariant::UInt)); - s_timeEventItem.insert("o:time", basicTypeToString(QVariant::Time)); - s_timeEventItem.insert("o:repeating", repeatingOptionRef()); - - // RepeatingOption - s_repeatingOption.insert("mode", repeatingModeRef()); - s_repeatingOption.insert("o:weekDays", QVariantList() << basicTypeToString(Int)); - s_repeatingOption.insert("o:monthDays", QVariantList() << basicTypeToString(Int)); - - // WirelessAccessPoint - s_wirelessAccessPoint.insert("ssid", basicTypeToString(QVariant::String)); - s_wirelessAccessPoint.insert("macAddress", basicTypeToString(QVariant::String)); - s_wirelessAccessPoint.insert("frequency", basicTypeToString(QVariant::Double)); - s_wirelessAccessPoint.insert("signalStrength", basicTypeToString(QVariant::Int)); - s_wirelessAccessPoint.insert("protected", basicTypeToString(QVariant::Bool)); - - // WiredNetworkDevice - s_wiredNetworkDevice.insert("interface", basicTypeToString(QVariant::String)); - s_wiredNetworkDevice.insert("macAddress", basicTypeToString(QVariant::String)); - s_wiredNetworkDevice.insert("state", networkDeviceStateRef()); - s_wiredNetworkDevice.insert("bitRate", basicTypeToString(QVariant::String)); - s_wiredNetworkDevice.insert("pluggedIn", basicTypeToString(QVariant::Bool)); - - // WirelessNetworkDevice - s_wirelessNetworkDevice.insert("interface", basicTypeToString(QVariant::String)); - s_wirelessNetworkDevice.insert("macAddress", basicTypeToString(QVariant::String)); - s_wirelessNetworkDevice.insert("state", networkDeviceStateRef()); - s_wirelessNetworkDevice.insert("bitRate", basicTypeToString(QVariant::String)); - s_wirelessNetworkDevice.insert("o:currentAccessPoint", wirelessAccessPointRef()); - - // TokenInfo - s_tokenInfo.insert("id", basicTypeToString(QVariant::Uuid)); - s_tokenInfo.insert("userName", basicTypeToString(QVariant::String)); - s_tokenInfo.insert("deviceName", basicTypeToString(QVariant::String)); - s_tokenInfo.insert("creationTime", basicTypeToString(QVariant::UInt)); - - // ServerConfiguration - s_serverConfiguration.insert("id", basicTypeToString(QVariant::String)); - s_serverConfiguration.insert("address", basicTypeToString(QVariant::String)); - s_serverConfiguration.insert("port", basicTypeToString(QVariant::UInt)); - s_serverConfiguration.insert("sslEnabled", basicTypeToString(QVariant::Bool)); - s_serverConfiguration.insert("authenticationEnabled", basicTypeToString(QVariant::Bool)); - - s_webServerConfiguration = s_serverConfiguration; - s_webServerConfiguration.insert("publicFolder", basicTypeToString(QVariant::String)); - - // MQTT - s_mqttPolicy.insert("clientId", basicTypeToString(QVariant::String)); - s_mqttPolicy.insert("username", basicTypeToString(QVariant::String)); - s_mqttPolicy.insert("password", basicTypeToString(QVariant::String)); - s_mqttPolicy.insert("allowedPublishTopicFilters", basicTypeToString(QVariant::StringList)); - s_mqttPolicy.insert("allowedSubscribeTopicFilters", basicTypeToString(QVariant::StringList)); - - // Tag - s_tag.insert("o:deviceId", basicTypeToString(QVariant::Uuid)); - s_tag.insert("o:ruleId", basicTypeToString(QVariant::Uuid)); - s_tag.insert("appId", basicTypeToString(QVariant::String)); - s_tag.insert("tagId", basicTypeToString(QVariant::String)); - s_tag.insert("o:value", basicTypeToString(QVariant::String)); - - // Package - s_package.insert("id", basicTypeToString(QVariant::String)); - s_package.insert("displayName", basicTypeToString(QVariant::String)); - s_package.insert("summary", basicTypeToString(QVariant::String)); - s_package.insert("installedVersion", basicTypeToString(QVariant::String)); - s_package.insert("candidateVersion", basicTypeToString(QVariant::String)); - s_package.insert("changelog", basicTypeToString(QVariant::String)); - s_package.insert("updateAvailable", basicTypeToString(QVariant::Bool)); - s_package.insert("rollbackAvailable", basicTypeToString(QVariant::Bool)); - s_package.insert("canRemove", basicTypeToString(QVariant::Bool)); - - // Repository - s_repository.insert("id", basicTypeToString(QVariant::String)); - s_repository.insert("displayName", basicTypeToString(QVariant::String)); - s_repository.insert("enabled", basicTypeToString(QVariant::Bool)); - - // BrowserItem - s_browserItem.insert("id", basicTypeToString(QVariant::String)); - s_browserItem.insert("displayName", basicTypeToString(QVariant::String)); - s_browserItem.insert("description", basicTypeToString(QVariant::String)); - s_browserItem.insert("icon", browserIconRef()); - s_browserItem.insert("thumbnail", basicTypeToString(QVariant::String)); - s_browserItem.insert("executable", basicTypeToString(QVariant::Bool)); - s_browserItem.insert("browsable", basicTypeToString(QVariant::Bool)); - s_browserItem.insert("disabled", basicTypeToString(QVariant::Bool)); - s_browserItem.insert("actionTypeIds", QVariantList() << basicTypeToString(QVariant::Uuid)); - s_browserItem.insert("o:mediaIcon", mediaBrowserIconRef()); - - s_initialized = true; -} - -QPair JsonTypes::report(bool status, const QString &message) -{ - return qMakePair(status, message); -} - -QVariantList JsonTypes::enumToStrings(const QMetaObject &metaObject, const QString &enumName) -{ - int enumIndex = metaObject.indexOfEnumerator(enumName.toLatin1().data()); - Q_ASSERT_X(enumIndex >= 0, "JsonTypes", QString("Enumerator %1 not found in %2").arg(enumName).arg(metaObject.className()).toLocal8Bit()); - QMetaEnum metaEnum = metaObject.enumerator(enumIndex); - - QVariantList enumStrings; - for (int i = 0; i < metaEnum.keyCount(); i++) - enumStrings << metaEnum.valueToKey(metaEnum.value(i)); - - return enumStrings; -} - -/*! Returns a map containing all API types. */ -QVariantMap JsonTypes::allTypes() -{ - QVariantMap allTypes; - allTypes.insert("BasicType", basicType()); - allTypes.insert("ParamType", paramTypeDescription()); - allTypes.insert("InputType", inputType()); - allTypes.insert("Unit", unit()); - allTypes.insert("CreateMethod", createMethod()); - allTypes.insert("SetupMethod", setupMethod()); - allTypes.insert("ValueOperator", valueOperator()); - allTypes.insert("StateOperator", stateOperator()); - allTypes.insert("RemovePolicy", removePolicy()); - allTypes.insert("DeviceError", deviceError()); - allTypes.insert("RuleError", ruleError()); - allTypes.insert("LoggingError", loggingError()); - allTypes.insert("LoggingLevel", loggingLevel()); - allTypes.insert("LoggingSource", loggingSource()); - allTypes.insert("LoggingEventType", loggingEventType()); - allTypes.insert("RepeatingMode", repeatingMode()); - allTypes.insert("ConfigurationError", configurationError()); - allTypes.insert("NetworkManagerError", networkManagerError()); - allTypes.insert("NetworkManagerState", networkManagerState()); - allTypes.insert("NetworkDeviceState", networkDeviceState()); - allTypes.insert("UserError", userError()); - allTypes.insert("TagError", tagError()); - allTypes.insert("CloudConnectionState", cloudConnectionState()); - allTypes.insert("BrowserIcon", browserIcon()); - allTypes.insert("MediaBrowserIcon", mediaBrowserIcon()); - - allTypes.insert("StateType", stateTypeDescription()); - allTypes.insert("StateDescriptor", stateDescriptorDescription()); - allTypes.insert("StateEvaluator", stateEvaluatorDescription()); - allTypes.insert("Event", eventDescription()); - allTypes.insert("EventType", eventTypeDescription()); - allTypes.insert("EventDescriptor", eventDescriptorDescription()); - allTypes.insert("ActionType", actionTypeDescription()); - allTypes.insert("Vendor", vendorDescription()); - allTypes.insert("DeviceClass", deviceClassDescription()); - allTypes.insert("Plugin", pluginDescription()); - allTypes.insert("Param", paramDescription()); - allTypes.insert("RuleAction", ruleActionDescription()); - allTypes.insert("RuleActionParam", ruleActionParamDescription()); - allTypes.insert("ParamDescriptor", paramDescriptorDescription()); - allTypes.insert("State", stateDescription()); - allTypes.insert("Device", deviceDescription()); - allTypes.insert("DeviceDescriptor", deviceDescriptorDescription()); - allTypes.insert("Action", actionDescription()); - allTypes.insert("Rule", ruleDescription()); - allTypes.insert("RuleDescription", ruleDescriptionDescription()); - allTypes.insert("LogEntry", logEntryDescription()); - allTypes.insert("TimeDescriptor", timeDescriptorDescription()); - allTypes.insert("CalendarItem", calendarItemDescription()); - allTypes.insert("TimeEventItem", timeEventItemDescription()); - allTypes.insert("RepeatingOption", repeatingOptionDescription()); - allTypes.insert("WirelessAccessPoint", wirelessAccessPointDescription()); - allTypes.insert("WiredNetworkDevice", wiredNetworkDeviceDescription()); - allTypes.insert("WirelessNetworkDevice", wirelessNetworkDeviceDescription()); - allTypes.insert("TokenInfo", tokenInfoDescription()); - allTypes.insert("ServerConfiguration", serverConfigurationDescription()); - allTypes.insert("WebServerConfiguration", serverConfigurationDescription()); - allTypes.insert("Tag", tagDescription()); - allTypes.insert("MqttPolicy", mqttPolicyDescription()); - allTypes.insert("Package", packageDescription()); - allTypes.insert("Repository", repositoryDescription()); - allTypes.insert("BrowserItem", browserItemDescription()); - - return allTypes; -} - -/*! Returns a variant map of the given \a eventType. */ -QVariantMap JsonTypes::packEventType(const EventType &eventType, const PluginId &pluginId, const QLocale &locale) -{ - QVariantMap variant; - variant.insert("id", eventType.id().toString()); - variant.insert("name", eventType.name()); - variant.insert("displayName", NymeaCore::instance()->deviceManager()->translate(pluginId, eventType.displayName(), locale)); - variant.insert("index", eventType.index()); - - QVariantList paramTypes; - foreach (const ParamType ¶mType, eventType.paramTypes()) - paramTypes.append(packParamType(paramType, pluginId, locale)); - - variant.insert("paramTypes", paramTypes); - return variant; -} - -/*! Returns a variant map of the given \a event. */ -QVariantMap JsonTypes::packEvent(const Event &event) -{ - QVariantMap variant; - variant.insert("eventTypeId", event.eventTypeId().toString()); - variant.insert("deviceId", event.deviceId().toString()); - QVariantList params; - foreach (const Param ¶m, event.params()) - params.append(packParam(param)); - - variant.insert("params", params); - return variant; -} - -/*! Returns a variant map of the given \a eventDescriptor. */ -QVariantMap JsonTypes::packEventDescriptor(const EventDescriptor &eventDescriptor) -{ - QVariantMap variant; - if (eventDescriptor.type() == EventDescriptor::TypeDevice) { - variant.insert("eventTypeId", eventDescriptor.eventTypeId().toString()); - variant.insert("deviceId", eventDescriptor.deviceId().toString()); - } else { - variant.insert("interface", eventDescriptor.interface()); - variant.insert("interfaceEvent", eventDescriptor.interfaceEvent()); - } - QVariantList params; - foreach (const ParamDescriptor ¶mDescriptor, eventDescriptor.paramDescriptors()) - params.append(packParamDescriptor(paramDescriptor)); - - variant.insert("paramDescriptors", params); - return variant; -} - -/*! Returns a variant map of the given \a actionType. */ -QVariantMap JsonTypes::packActionType(const ActionType &actionType, const PluginId &pluginId, const QLocale &locale) -{ - QVariantMap variantMap; - variantMap.insert("id", actionType.id().toString()); - variantMap.insert("name", actionType.name()); - variantMap.insert("displayName", NymeaCore::instance()->deviceManager()->translate(pluginId, actionType.displayName(), locale)); - variantMap.insert("index", actionType.index()); - QVariantList paramTypes; - foreach (const ParamType ¶mType, actionType.paramTypes()) - paramTypes.append(packParamType(paramType, pluginId, locale)); - - variantMap.insert("paramTypes", paramTypes); - return variantMap; -} - -/*! Returns a variant map of the given \a action. */ -QVariantMap JsonTypes::packAction(const Action &action) -{ - QVariantMap variant; - variant.insert("actionTypeId", action.actionTypeId().toString()); - variant.insert("deviceId", action.deviceId().toString()); - QVariantList params; - foreach (const Param ¶m, action.params()) - params.append(packParam(param)); - - variant.insert("params", params); - return variant; -} - -/*! Returns a variant map of the given \a ruleAction. */ -QVariantMap JsonTypes::packRuleAction(const RuleAction &ruleAction) -{ - QVariantMap variant; - if (ruleAction.type() == RuleAction::TypeDevice) { - variant.insert("deviceId", ruleAction.deviceId().toString()); - variant.insert("actionTypeId", ruleAction.actionTypeId().toString()); - } else if (ruleAction.type() == RuleAction::TypeBrowser) { - variant.insert("deviceId", ruleAction.deviceId().toString()); - variant.insert("browserItemId", ruleAction.browserItemId()); - } else { - variant.insert("interface", ruleAction.interface()); - variant.insert("interfaceAction", ruleAction.interfaceAction()); - } - QVariantList params; - foreach (const RuleActionParam &ruleActionParam, ruleAction.ruleActionParams()) - params.append(packRuleActionParam(ruleActionParam)); - - variant.insert("ruleActionParams", params); - return variant; -} - -/*! Returns a variant map of the given \a ruleActionParam. */ -QVariantMap JsonTypes::packRuleActionParam(const RuleActionParam &ruleActionParam) -{ - QVariantMap variantMap; - if (!ruleActionParam.paramTypeId().isNull()) { - variantMap.insert("paramTypeId", ruleActionParam.paramTypeId().toString()); - } else { - variantMap.insert("paramName", ruleActionParam.paramName()); - } - - if (ruleActionParam.isEventBased()) { - variantMap.insert("eventTypeId", ruleActionParam.eventTypeId().toString()); - variantMap.insert("eventParamTypeId", ruleActionParam.eventParamTypeId().toString()); - } else if (ruleActionParam.isStateBased()) { - variantMap.insert("stateDeviceId", ruleActionParam.stateDeviceId().toString()); - variantMap.insert("stateTypeId", ruleActionParam.stateTypeId().toString()); - } else { - variantMap.insert("value", ruleActionParam.value()); - } - return variantMap; -} - -/*! Returns a variant map of the given \a state. */ -QVariantMap JsonTypes::packState(const State &state) -{ - QVariantMap stateMap; - stateMap.insert("stateTypeId", state.stateTypeId().toString()); - stateMap.insert("value", state.value()); - return stateMap; -} - -/*! Returns a variant map of the given \a stateType. */ -QVariantMap JsonTypes::packStateType(const StateType &stateType, const PluginId &pluginId, const QLocale &locale) -{ - QVariantMap variantMap; - variantMap.insert("id", stateType.id().toString()); - variantMap.insert("name", stateType.name()); - variantMap.insert("displayName", NymeaCore::instance()->deviceManager()->translate(pluginId, stateType.displayName(), locale)); - variantMap.insert("index", stateType.index()); - variantMap.insert("type", basicTypeToString(stateType.type())); - variantMap.insert("defaultValue", stateType.defaultValue()); - - if (stateType.maxValue().isValid()) - variantMap.insert("maxValue", stateType.maxValue()); - - if (stateType.minValue().isValid()) - variantMap.insert("minValue", stateType.minValue()); - - if (!stateType.possibleValues().isEmpty()) - variantMap.insert("possibleValues", stateType.possibleValues()); - - if(stateType.unit() != Types::UnitNone) - variantMap.insert("unit", s_unit.at(stateType.unit())); - - return variantMap; -} - -/*! Returns a variant map of the given \a stateDescriptor. */ -QVariantMap JsonTypes::packStateDescriptor(const StateDescriptor &stateDescriptor) -{ - QVariantMap variantMap; - if (stateDescriptor.type() == StateDescriptor::TypeDevice) { - variantMap.insert("stateTypeId", stateDescriptor.stateTypeId().toString()); - variantMap.insert("deviceId", stateDescriptor.deviceId().toString()); - } else { - variantMap.insert("interface", stateDescriptor.interface()); - variantMap.insert("interfaceState", stateDescriptor.interfaceState()); - } - variantMap.insert("value", stateDescriptor.stateValue()); - variantMap.insert("operator", s_valueOperator.at(stateDescriptor.operatorType())); - return variantMap; -} - -/*! Returns a variant map of the given \a stateEvaluator. */ -QVariantMap JsonTypes::packStateEvaluator(const StateEvaluator &stateEvaluator) -{ - QVariantMap variantMap; - if (stateEvaluator.stateDescriptor().isValid()) - variantMap.insert("stateDescriptor", packStateDescriptor(stateEvaluator.stateDescriptor())); - - QVariantList childEvaluators; - foreach (const StateEvaluator &childEvaluator, stateEvaluator.childEvaluators()) - childEvaluators.append(packStateEvaluator(childEvaluator)); - - if (!childEvaluators.isEmpty() || stateEvaluator.stateDescriptor().isValid()) - variantMap.insert("operator", s_stateOperator.at(stateEvaluator.operatorType())); - - if (childEvaluators.count() > 0) - variantMap.insert("childEvaluators", childEvaluators); - - return variantMap; -} - -/*! Returns a variant map of the given \a param. */ -QVariantMap JsonTypes::packParam(const Param ¶m) -{ - QVariantMap variantMap; - variantMap.insert("paramTypeId", param.paramTypeId().toString()); - variantMap.insert("value", param.value()); - return variantMap; -} - -QVariantMap JsonTypes::packBrowserItem(const BrowserItem &item) -{ - QVariantMap ret; - ret.insert("id", item.id()); - ret.insert("displayName", item.displayName()); - ret.insert("description", item.description()); - ret.insert("icon", browserIconToString(item.icon())); - if (item.extendedPropertiesFlags().testFlag(BrowserItem::ExtendedPropertiesMedia)) { - ret.insert("mediaIcon", mediaBrowserIconToString(static_cast(item.extendedProperty("mediaIcon").toInt()))); - } - ret.insert("thumbnail", item.thumbnail()); - ret.insert("executable", item.executable()); - ret.insert("browsable", item.browsable()); - ret.insert("disabled", item.disabled()); - QVariantList actionTypeIds; - foreach (const ActionTypeId &id, item.actionTypeIds()) { - actionTypeIds.append(id.toString()); - } - ret.insert("actionTypeIds", actionTypeIds); - return ret; -} - -QVariantList JsonTypes::packParams(const ParamList ¶mList) -{ - QVariantList ret; - foreach (const Param ¶m, paramList) { - ret << packParam(param); - } - return ret; -} - -/*! Returns a variant map of the given \a paramDescriptor. */ -QVariantMap JsonTypes::packParamDescriptor(const ParamDescriptor ¶mDescriptor) -{ - QVariantMap variantMap; - if (!paramDescriptor.paramTypeId().isNull()) { - variantMap.insert("paramTypeId", paramDescriptor.paramTypeId().toString()); - } else { - variantMap.insert("paramName", paramDescriptor.paramName()); - } - variantMap.insert("value", paramDescriptor.value()); - variantMap.insert("operator", s_valueOperator.at(paramDescriptor.operatorType())); - return variantMap; -} - -/*! Returns a variant map of the given \a paramType. */ -QVariantMap JsonTypes::packParamType(const ParamType ¶mType, const PluginId &pluginId, const QLocale &locale) -{ - QVariantMap variantMap; - variantMap.insert("id", paramType.id().toString()); - variantMap.insert("name", paramType.name()); - variantMap.insert("displayName", NymeaCore::instance()->deviceManager()->translate(pluginId, paramType.displayName(), locale)); - variantMap.insert("type", basicTypeToString(paramType.type())); - variantMap.insert("index", paramType.index()); - - // Optional values - if (paramType.defaultValue().isValid()) - variantMap.insert("defaultValue", paramType.defaultValue()); - - if (paramType.minValue().isValid()) - variantMap.insert("minValue", paramType.minValue()); - - if (paramType.maxValue().isValid()) - variantMap.insert("maxValue", paramType.maxValue()); - - if (!paramType.allowedValues().isEmpty()) - variantMap.insert("allowedValues", paramType.allowedValues()); - - if (paramType.inputType() != Types::InputTypeNone) - variantMap.insert("inputType", s_inputType.at(paramType.inputType())); - - if (paramType.unit() != Types::UnitNone) - variantMap.insert("unit", s_unit.at(paramType.unit())); - - if (paramType.readOnly()) - variantMap.insert("readOnly", paramType.readOnly()); - - return variantMap; -} - -/*! Returns a variant map of the given \a vendor. */ -QVariantMap JsonTypes::packVendor(const Vendor &vendor, const QLocale &locale) -{ - DevicePlugin *plugin = nullptr; - foreach (DevicePlugin *p, NymeaCore::instance()->deviceManager()->plugins()) { - if (p->supportedVendors().contains(vendor)) { - plugin = p; - } - } - QVariantMap variantMap; - variantMap.insert("id", vendor.id().toString()); - variantMap.insert("name", vendor.name()); - variantMap.insert("displayName", NymeaCore::instance()->deviceManager()->translate(plugin->pluginId(), vendor.displayName(), locale)); - return variantMap; -} - -/*! Returns a variant map of the given \a deviceClass. */ -QVariantMap JsonTypes::packDeviceClass(const DeviceClass &deviceClass, const QLocale &locale) -{ - QVariantMap variant; - variant.insert("id", deviceClass.id().toString()); - variant.insert("name", deviceClass.name()); - variant.insert("displayName", NymeaCore::instance()->deviceManager()->translate(deviceClass.pluginId(), deviceClass.displayName(), locale)); - variant.insert("vendorId", deviceClass.vendorId().toString()); - variant.insert("pluginId", deviceClass.pluginId().toString()); - variant.insert("interfaces", deviceClass.interfaces()); - variant.insert("browsable", deviceClass.browsable()); - - QVariantList stateTypes; - foreach (const StateType &stateType, deviceClass.stateTypes()) - stateTypes.append(packStateType(stateType, deviceClass.pluginId(), locale)); - - QVariantList eventTypes; - foreach (const EventType &eventType, deviceClass.eventTypes()) - eventTypes.append(packEventType(eventType, deviceClass.pluginId(), locale)); - - QVariantList actionTypes; - foreach (const ActionType &actionType, deviceClass.actionTypes()) - actionTypes.append(packActionType(actionType, deviceClass.pluginId(), locale)); - - QVariantList browserItemActionTypes; - foreach (const ActionType &actionType, deviceClass.browserItemActionTypes()) - browserItemActionTypes.append(packActionType(actionType, deviceClass.pluginId(), locale)); - - QVariantList paramTypes; - foreach (const ParamType ¶mType, deviceClass.paramTypes()) - paramTypes.append(packParamType(paramType, deviceClass.pluginId(), locale)); - - QVariantList settingsTypes; - foreach (const ParamType &settingsType, deviceClass.settingsTypes()) - settingsTypes.append(packParamType(settingsType, deviceClass.pluginId(), locale)); - - QVariantList discoveryParamTypes; - foreach (const ParamType ¶mType, deviceClass.discoveryParamTypes()) - discoveryParamTypes.append(packParamType(paramType, deviceClass.pluginId(), locale)); - - variant.insert("paramTypes", paramTypes); - variant.insert("settingsTypes", settingsTypes); - variant.insert("discoveryParamTypes", discoveryParamTypes); - variant.insert("stateTypes", stateTypes); - variant.insert("eventTypes", eventTypes); - variant.insert("actionTypes", actionTypes); - variant.insert("browserItemActionTypes", browserItemActionTypes); - variant.insert("createMethods", packCreateMethods(deviceClass.createMethods())); - variant.insert("setupMethod", s_setupMethod.at(deviceClass.setupMethod())); - return variant; -} - -/*! Returns a variant map of the given \a plugin. */ -QVariantMap JsonTypes::packPlugin(DevicePlugin *plugin, const QLocale &locale) -{ - QVariantMap pluginMap; - pluginMap.insert("id", plugin->pluginId().toString()); - pluginMap.insert("name", plugin->pluginName()); - pluginMap.insert("displayName", NymeaCore::instance()->deviceManager()->translate(plugin->pluginId(), plugin->pluginDisplayName(), locale)); - - QVariantList params; - foreach (const ParamType ¶m, plugin->configurationDescription()) - params.append(packParamType(param, plugin->pluginId(), locale)); - - pluginMap.insert("paramTypes", params); - return pluginMap; -} - -/*! Returns a variant map of the given \a device. */ -QVariantMap JsonTypes::packDevice(Device *device) -{ - QVariantMap variant; - variant.insert("id", device->id().toString()); - variant.insert("deviceClassId", device->deviceClassId().toString()); - variant.insert("name", device->name()); - variant.insert("params", packParams(device->params())); - variant.insert("settings", packParams(device->settings())); - - if (!device->parentId().isNull()) - variant.insert("parentId", device->parentId().toString()); - - variant.insert("states", packDeviceStates(device)); - variant.insert("setupComplete", device->setupComplete()); - return variant; -} - -/*! Returns a variant map of the given \a descriptor. */ -QVariantMap JsonTypes::packDeviceDescriptor(const DeviceDescriptor &descriptor) -{ - QVariantMap variant; - variant.insert("id", descriptor.id().toString()); - variant.insert("deviceId", descriptor.deviceId().toString()); - variant.insert("title", descriptor.title()); - variant.insert("description", descriptor.description()); - QVariantList params; - foreach (const Param ¶m, descriptor.params()) { - params.append(packParam(param)); - } - variant.insert("deviceParams", params); - return variant; -} - -/*! Returns a variant map of the given \a rule. */ -QVariantMap JsonTypes::packRule(const Rule &rule) -{ - QVariantMap ruleMap; - ruleMap.insert("id", rule.id().toString()); - ruleMap.insert("name", rule.name()); - ruleMap.insert("enabled", rule.enabled()); - ruleMap.insert("active", rule.active()); - ruleMap.insert("executable", rule.executable()); - ruleMap.insert("timeDescriptor", JsonTypes::packTimeDescriptor(rule.timeDescriptor())); - - QVariantList eventDescriptorList; - foreach (const EventDescriptor &eventDescriptor, rule.eventDescriptors()) - eventDescriptorList.append(JsonTypes::packEventDescriptor(eventDescriptor)); - - ruleMap.insert("eventDescriptors", eventDescriptorList); - ruleMap.insert("stateEvaluator", JsonTypes::packStateEvaluator(rule.stateEvaluator())); - - QVariantList actionList; - foreach (const RuleAction &action, rule.actions()) - actionList.append(JsonTypes::packRuleAction(action)); - - ruleMap.insert("actions", actionList); - - QVariantList exitActionList; - foreach (const RuleAction &action, rule.exitActions()) - exitActionList.append(JsonTypes::packRuleAction(action)); - - ruleMap.insert("exitActions", exitActionList); - return ruleMap; -} - -/*! Returns a variant map of the given \a rules. */ -QVariantList JsonTypes::packRules(const QList rules) -{ - QVariantList rulesList; - foreach (const Rule &rule, rules) - rulesList.append(JsonTypes::packRule(rule)); - - return rulesList; -} - -/*! Returns a variant map of the given \a rule. */ -QVariantMap JsonTypes::packRuleDescription(const Rule &rule) -{ - QVariantMap ruleDescriptionMap; - ruleDescriptionMap.insert("id", rule.id().toString()); - ruleDescriptionMap.insert("name", rule.name()); - ruleDescriptionMap.insert("enabled", rule.enabled()); - ruleDescriptionMap.insert("active", rule.active()); - ruleDescriptionMap.insert("executable", rule.executable()); - return ruleDescriptionMap; -} - -/*! Returns a variant map of the given \a logEntry. */ -QVariantMap JsonTypes::packLogEntry(const LogEntry &logEntry) -{ - QVariantMap logEntryMap; - logEntryMap.insert("timestamp", logEntry.timestamp().toMSecsSinceEpoch()); - logEntryMap.insert("loggingLevel", s_loggingLevel.at(logEntry.level())); - logEntryMap.insert("source", s_loggingSource.at(logEntry.source())); - logEntryMap.insert("eventType", s_loggingEventType.at(logEntry.eventType())); - - if (logEntry.eventType() == Logging::LoggingEventTypeActiveChange) - logEntryMap.insert("active", logEntry.active()); - - if (logEntry.eventType() == Logging::LoggingEventTypeEnabledChange) - logEntryMap.insert("active", logEntry.active()); - - if (logEntry.level() == Logging::LoggingLevelAlert) { - switch (logEntry.source()) { - case Logging::LoggingSourceRules: - logEntryMap.insert("errorCode", s_ruleError.at(logEntry.errorCode())); - break; - case Logging::LoggingSourceActions: - case Logging::LoggingSourceEvents: - case Logging::LoggingSourceStates: - case Logging::LoggingSourceBrowserActions: - logEntryMap.insert("errorCode", s_deviceError.at(logEntry.errorCode())); - break; - case Logging::LoggingSourceSystem: - // FIXME: Update this once we support error codes for the general system - // logEntryMap.insert("errorCode", ""); - break; - } - } - - switch (logEntry.source()) { - case Logging::LoggingSourceActions: - case Logging::LoggingSourceEvents: - case Logging::LoggingSourceStates: - logEntryMap.insert("typeId", logEntry.typeId().toString()); - logEntryMap.insert("deviceId", logEntry.deviceId().toString()); - logEntryMap.insert("value", LogValueTool::convertVariantToString(logEntry.value())); - break; - case Logging::LoggingSourceSystem: - logEntryMap.insert("active", logEntry.active()); - break; - case Logging::LoggingSourceRules: - logEntryMap.insert("typeId", logEntry.typeId().toString()); - break; - case Logging::LoggingSourceBrowserActions: - logEntryMap.insert("itemId", logEntry.value()); - break; - } - - return logEntryMap; -} - -/*! Returns a variant map of the given \a tag. */ -QVariantMap JsonTypes::packTag(const Tag &tag) -{ - QVariantMap ret; - if (!tag.deviceId().isNull()){ - ret.insert("deviceId", tag.deviceId().toString()); - } else { - ret.insert("ruleId", tag.ruleId().toString()); - } - ret.insert("appId", tag.appId()); - ret.insert("tagId", tag.tagId()); - ret.insert("value", tag.value()); - return ret; -} - -/*! Returns a variant list of the given \a createMethods. */ -QVariantList JsonTypes::packCreateMethods(DeviceClass::CreateMethods createMethods) -{ - QVariantList ret; - if (createMethods.testFlag(DeviceClass::CreateMethodUser)) - ret << "CreateMethodUser"; - - if (createMethods.testFlag(DeviceClass::CreateMethodAuto)) - ret << "CreateMethodAuto"; - - if (createMethods.testFlag(DeviceClass::CreateMethodDiscovery)) - ret << "CreateMethodDiscovery"; - - return ret; -} - -/*! Returns a variant map of the given \a option. */ -QVariantMap JsonTypes::packRepeatingOption(const RepeatingOption &option) -{ - QVariantMap optionVariant; - optionVariant.insert("mode", s_repeatingMode.at(option.mode())); - if (!option.weekDays().isEmpty()) { - QVariantList weekDaysVariantList; - foreach (const int& weekDay, option.weekDays()) - weekDaysVariantList.append(QVariant(weekDay)); - - optionVariant.insert("weekDays", weekDaysVariantList); - } - - if (!option.monthDays().isEmpty()) { - QVariantList monthDaysVariantList; - foreach (const int& monthDay, option.monthDays()) - monthDaysVariantList.append(QVariant(monthDay)); - - optionVariant.insert("monthDays", monthDaysVariantList); - } - return optionVariant; -} - -/*! Returns a variant map of the given \a calendarItem. */ -QVariantMap JsonTypes::packCalendarItem(const CalendarItem &calendarItem) -{ - QVariantMap calendarItemVariant; - calendarItemVariant.insert("duration", calendarItem.duration()); - - if (!calendarItem.dateTime().isNull() && calendarItem.dateTime().toTime_t() != 0) - calendarItemVariant.insert("datetime", calendarItem.dateTime().toTime_t()); - - if (!calendarItem.startTime().isNull()) - calendarItemVariant.insert("startTime", calendarItem.startTime().toString("hh:mm")); - - if (!calendarItem.repeatingOption().isEmtpy()) - calendarItemVariant.insert("repeating", packRepeatingOption(calendarItem.repeatingOption())); - - return calendarItemVariant; -} - -/*! Returns a variant map of the given \a timeEventItem. */ -QVariantMap JsonTypes::packTimeEventItem(const TimeEventItem &timeEventItem) -{ - QVariantMap timeEventItemVariant; - - if (!timeEventItem.dateTime().isNull() && timeEventItem.dateTime().toTime_t() != 0) - timeEventItemVariant.insert("datetime", timeEventItem.dateTime().toTime_t()); - - if (!timeEventItem.time().isNull()) - timeEventItemVariant.insert("time", timeEventItem.time().toString("hh:mm")); - - if (!timeEventItem.repeatingOption().isEmtpy()) - timeEventItemVariant.insert("repeating", packRepeatingOption(timeEventItem.repeatingOption())); - - return timeEventItemVariant; -} - -/*! Returns a variant map of the given \a timeDescriptor. */ -QVariantMap JsonTypes::packTimeDescriptor(const TimeDescriptor &timeDescriptor) -{ - QVariantMap timeDescriptorVariant; - - if (!timeDescriptor.calendarItems().isEmpty()) { - QVariantList calendarItems; - foreach (const CalendarItem &calendarItem, timeDescriptor.calendarItems()) - calendarItems.append(packCalendarItem(calendarItem)); - - timeDescriptorVariant.insert("calendarItems", calendarItems); - } - - if (!timeDescriptor.timeEventItems().isEmpty()) { - QVariantList timeEventItems; - foreach (const TimeEventItem &timeEventItem, timeDescriptor.timeEventItems()) - timeEventItems.append(packTimeEventItem(timeEventItem)); - - timeDescriptorVariant.insert("timeEventItems", timeEventItems); - } - - return timeDescriptorVariant; -} - -/*! Returns a variant map of the given \a wirelessAccessPoint. */ -QVariantMap JsonTypes::packWirelessAccessPoint(WirelessAccessPoint *wirelessAccessPoint) -{ - QVariantMap wirelessAccessPointVariant; - wirelessAccessPointVariant.insert("ssid", wirelessAccessPoint->ssid()); - wirelessAccessPointVariant.insert("macAddress", wirelessAccessPoint->macAddress()); - wirelessAccessPointVariant.insert("frequency", wirelessAccessPoint->frequency()); - wirelessAccessPointVariant.insert("signalStrength", wirelessAccessPoint->signalStrength()); - wirelessAccessPointVariant.insert("protected", wirelessAccessPoint->isProtected()); - return wirelessAccessPointVariant; -} - -/*! Returns a variant map of the given \a networkDevice. */ -QVariantMap JsonTypes::packWiredNetworkDevice(WiredNetworkDevice *networkDevice) -{ - QVariantMap networkDeviceVariant; - networkDeviceVariant.insert("interface", networkDevice->interface()); - networkDeviceVariant.insert("macAddress", networkDevice->macAddress()); - networkDeviceVariant.insert("state", networkDevice->deviceStateString()); - networkDeviceVariant.insert("bitRate", QString("%1 [Mb/s]").arg(QString::number(networkDevice->bitRate()))); - networkDeviceVariant.insert("pluggedIn", networkDevice->pluggedIn()); - return networkDeviceVariant; -} - -/*! Returns a variant map of the given \a networkDevice. */ -QVariantMap JsonTypes::packWirelessNetworkDevice(WirelessNetworkDevice *networkDevice) -{ - QVariantMap networkDeviceVariant; - networkDeviceVariant.insert("interface", networkDevice->interface()); - networkDeviceVariant.insert("macAddress", networkDevice->macAddress()); - networkDeviceVariant.insert("state", networkDevice->deviceStateString()); - networkDeviceVariant.insert("bitRate", QString("%1 [Mb/s]").arg(QString::number(networkDevice->bitRate()))); - if (networkDevice->activeAccessPoint()) - networkDeviceVariant.insert("currentAccessPoint", JsonTypes::packWirelessAccessPoint(networkDevice->activeAccessPoint())); - - return networkDeviceVariant; -} - -/*! Returns a variant list of the supported vendors. */ -QVariantList JsonTypes::packSupportedVendors(const QLocale &locale) -{ - QVariantList supportedVendors; - foreach (const Vendor &vendor, NymeaCore::instance()->deviceManager()->supportedVendors()) - supportedVendors.append(packVendor(vendor, locale)); - - return supportedVendors; -} - -/*! Returns a variant list of the supported devices with the given \a vendorId. */ -QVariantList JsonTypes::packSupportedDevices(const VendorId &vendorId, const QLocale &locale) -{ - QVariantList supportedDeviceList; - foreach (const DeviceClass &deviceClass, NymeaCore::instance()->deviceManager()->supportedDevices(vendorId)) - supportedDeviceList.append(packDeviceClass(deviceClass, locale)); - - return supportedDeviceList; -} - -/*! Returns a variant list of configured devices. */ -QVariantList JsonTypes::packConfiguredDevices() -{ - QVariantList configuredDeviceList; - foreach (Device *device, NymeaCore::instance()->deviceManager()->configuredDevices()) - configuredDeviceList.append(packDevice(device)); - - return configuredDeviceList; -} - -/*! Returns a variant list of States from the given \a device. */ -QVariantList JsonTypes::packDeviceStates(Device *device) -{ - DeviceClass deviceClass = NymeaCore::instance()->deviceManager()->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; -} - -/*! Returns a variant list of the given \a deviceDescriptors. */ -QVariantList JsonTypes::packDeviceDescriptors(const QList deviceDescriptors) -{ - QVariantList deviceDescriptorList; - foreach (const DeviceDescriptor &deviceDescriptor, deviceDescriptors) - deviceDescriptorList.append(JsonTypes::packDeviceDescriptor(deviceDescriptor)); - - return deviceDescriptorList; -} - -QVariantList JsonTypes::packBrowserItems(const BrowserItems &items) -{ - QVariantList ret; - foreach (const BrowserItem &item, items) { - ret.append(packBrowserItem(item)); - } - return ret; -} - -/*! Returns a variant map with the current basic configuration of the server. */ -QVariantMap JsonTypes::packBasicConfiguration() -{ - QVariantMap basicConfiguration; - basicConfiguration.insert("serverName", NymeaCore::instance()->configuration()->serverName()); - basicConfiguration.insert("serverUuid", NymeaCore::instance()->configuration()->serverUuid().toString()); - basicConfiguration.insert("serverTime", NymeaCore::instance()->timeManager()->currentDateTime().toTime_t()); - basicConfiguration.insert("timeZone", QString::fromUtf8(NymeaCore::instance()->timeManager()->timeZone())); - basicConfiguration.insert("language", NymeaCore::instance()->configuration()->locale().name()); - basicConfiguration.insert("debugServerEnabled", NymeaCore::instance()->configuration()->debugServerEnabled()); - return basicConfiguration; -} - -QVariantMap JsonTypes::packServerConfiguration(const ServerConfiguration &config) -{ - QVariantMap serverConfiguration; - serverConfiguration.insert("id", config.id); - serverConfiguration.insert("address", config.address.toString()); - serverConfiguration.insert("port", config.port); - serverConfiguration.insert("sslEnabled", config.sslEnabled); - serverConfiguration.insert("authenticationEnabled", config.authenticationEnabled); - return serverConfiguration; -} - -QVariantMap JsonTypes::packWebServerConfiguration(const WebServerConfiguration &config) -{ - QVariantMap webServerConfiguration = packServerConfiguration(config); - webServerConfiguration.insert("publicFolder", config.publicFolder); - return webServerConfiguration; -} - -QVariantMap JsonTypes::packMqttPolicy(const MqttPolicy &policy) -{ - QVariantMap policyMap; - policyMap.insert("clientId", policy.clientId); - policyMap.insert("username", policy.username); - policyMap.insert("password", policy.password); - policyMap.insert("allowedPublishTopicFilters", policy.allowedPublishTopicFilters); - policyMap.insert("allowedSubscribeTopicFilters", policy.allowedSubscribeTopicFilters); - return policyMap; -} - -/*! Returns a variant list containing all rule descriptions. */ -QVariantList JsonTypes::packRuleDescriptions() -{ - QVariantList rulesList; - foreach (const Rule &rule, NymeaCore::instance()->ruleEngine()->rules()) - rulesList.append(JsonTypes::packRuleDescription(rule)); - - return rulesList; -} - -/*! Returns a variant list of the given \a rules. */ -QVariantList JsonTypes::packRuleDescriptions(const QList &rules) -{ - QVariantList rulesList; - foreach (const Rule &rule, rules) - rulesList.append(JsonTypes::packRuleDescription(rule)); - - return rulesList; -} - -/*! Returns a variant list of action types for the given \a deviceClass. */ -QVariantList JsonTypes::packActionTypes(const DeviceClass &deviceClass, const QLocale &locale) -{ - QVariantList actionTypes; - foreach (const ActionType &actionType, deviceClass.actionTypes()) - actionTypes.append(JsonTypes::packActionType(actionType, deviceClass.pluginId(), locale)); - - return actionTypes; -} - -/*! Returns a variant list of state types for the given \a deviceClass. */ -QVariantList JsonTypes::packStateTypes(const DeviceClass &deviceClass, const QLocale &locale) -{ - QVariantList stateTypes; - foreach (const StateType &stateType, deviceClass.stateTypes()) - stateTypes.append(JsonTypes::packStateType(stateType, deviceClass.pluginId(), locale)); - - return stateTypes; -} - -/*! Returns a variant list of event types for the given \a deviceClass. */ -QVariantList JsonTypes::packEventTypes(const DeviceClass &deviceClass, const QLocale &locale) -{ - QVariantList eventTypes; - foreach (const EventType &eventType, deviceClass.eventTypes()) - eventTypes.append(JsonTypes::packEventType(eventType, deviceClass.pluginId(), locale)); - - return eventTypes; -} - -/*! Returns a variant list containing all plugins. */ -QVariantList JsonTypes::packPlugins(const QLocale &locale) -{ - QVariantList pluginsList; - foreach (DevicePlugin *plugin, NymeaCore::instance()->deviceManager()->plugins()) { - QVariantMap pluginMap = packPlugin(plugin, locale); - pluginsList.append(pluginMap); - } - return pluginsList; -} - -QVariantMap JsonTypes::packTokenInfo(const TokenInfo &tokenInfo) -{ - QVariantMap ret; - ret.insert("id", tokenInfo.id().toString()); - ret.insert("userName", tokenInfo.username()); - ret.insert("deviceName", tokenInfo.deviceName()); - ret.insert("creationTime", tokenInfo.creationTime().toTime_t()); - return ret; -} - -QVariantMap JsonTypes::packPackage(const Package &package) -{ - QVariantMap ret; - ret.insert("id", package.packageId()); - ret.insert("displayName", package.displayName()); - ret.insert("summary", package.summary()); - ret.insert("installedVersion", package.installedVersion()); - ret.insert("candidateVersion", package.candidateVersion()); - ret.insert("changelog", package.changelog()); - ret.insert("updateAvailable", package.updateAvailable()); - ret.insert("rollbackAvailable", package.rollbackAvailable()); - ret.insert("canRemove", package.canRemove()); - return ret; -} - -QVariantMap JsonTypes::packRepository(const Repository &repository) -{ - QVariantMap ret; - ret.insert("id", repository.id()); - ret.insert("displayName", repository.displayName()); - ret.insert("enabled", repository.enabled()); - return ret; -} - -/*! Returns the type string for the given \a type. */ -QString JsonTypes::basicTypeToString(const QVariant::Type &type) -{ - switch (type) { - case QVariant::Uuid: - return "Uuid"; - case QVariant::String: - return "String"; - case QVariant::StringList: - return "StringList"; - case QVariant::Int: - return "Int"; - case QVariant::UInt: - return "Uint"; - case QVariant::Double: - return "Double"; - case QVariant::Bool: - return "Bool"; - case QVariant::Color: - return "Color"; - case QVariant::Time: - return "Time"; - default: - return QVariant::typeToName(static_cast(type)); - } -} - -/*! Returns a \l{Param} created from the given \a paramMap. */ -Param JsonTypes::unpackParam(const QVariantMap ¶mMap) -{ - if (paramMap.keys().count() == 0) - return Param(); - - ParamTypeId paramTypeId = paramMap.value("paramTypeId").toString(); - QVariant value = paramMap.value("value"); - return Param(paramTypeId, value); -} - -/*! Returns a \l{ParamList} created from the given \a paramList. */ -ParamList JsonTypes::unpackParams(const QVariantList ¶mList) -{ - ParamList params; - foreach (const QVariant ¶mVariant, paramList) - params.append(unpackParam(paramVariant.toMap())); - - return params; -} - -/*! Returns a \l{Rule} created from the given \a ruleMap. */ -Rule JsonTypes::unpackRule(const QVariantMap &ruleMap) -{ - // The rule id will only be valid if unpacking for edit - RuleId ruleId = RuleId(ruleMap.value("ruleId").toString()); - - QString name = ruleMap.value("name", QString()).toString(); - - // By default enabled - bool enabled = ruleMap.value("enabled", true).toBool(); - - // By default executable - bool executable = ruleMap.value("executable", true).toBool(); - - StateEvaluator stateEvaluator = JsonTypes::unpackStateEvaluator(ruleMap.value("stateEvaluator").toMap()); - TimeDescriptor timeDescriptor = JsonTypes::unpackTimeDescriptor(ruleMap.value("timeDescriptor").toMap()); - - QList eventDescriptors; - if (ruleMap.contains("eventDescriptors")) { - QVariantList eventDescriptorVariantList = ruleMap.value("eventDescriptors").toList(); - foreach (const QVariant &eventDescriptorVariant, eventDescriptorVariantList) { - eventDescriptors.append(JsonTypes::unpackEventDescriptor(eventDescriptorVariant.toMap())); - } - } - - QList actions; - if (ruleMap.contains("actions")) { - QVariantList actionsVariantList = ruleMap.value("actions").toList(); - foreach (const QVariant &actionVariant, actionsVariantList) { - actions.append(JsonTypes::unpackRuleAction(actionVariant.toMap())); - } - } - - QList exitActions; - if (ruleMap.contains("exitActions")) { - QVariantList exitActionsVariantList = ruleMap.value("exitActions").toList(); - foreach (const QVariant &exitActionVariant, exitActionsVariantList) { - exitActions.append(JsonTypes::unpackRuleAction(exitActionVariant.toMap())); - } - } - - Rule rule; - rule.setId(ruleId); - rule.setName(name); - rule.setTimeDescriptor(timeDescriptor); - rule.setStateEvaluator(stateEvaluator); - rule.setEventDescriptors(eventDescriptors); - rule.setActions(actions); - rule.setExitActions(exitActions); - rule.setEnabled(enabled); - rule.setExecutable(executable); - return rule; -} - -/*! Returns a \l{RuleAction} created from the given \a ruleActionMap. */ -RuleAction JsonTypes::unpackRuleAction(const QVariantMap &ruleActionMap) -{ - ActionTypeId actionTypeId(ruleActionMap.value("actionTypeId").toString()); - DeviceId actionDeviceId(ruleActionMap.value("deviceId").toString()); - QString interface = ruleActionMap.value("interface").toString(); - QString interfaceAction = ruleActionMap.value("interfaceAction").toString(); - QString browserItemId = ruleActionMap.value("browserItemId").toString(); - RuleActionParamList actionParamList = JsonTypes::unpackRuleActionParams(ruleActionMap.value("ruleActionParams").toList()); - - if (!actionDeviceId.isNull() && !actionTypeId.isNull()) { - return RuleAction(actionTypeId, actionDeviceId, actionParamList); - } else if (!actionDeviceId.isNull() && !browserItemId.isNull()) { - return RuleAction(actionDeviceId, browserItemId); - } - return RuleAction(interface, interfaceAction, actionParamList); -} - -/*! Returns a \l{RuleActionParam} created from the given \a ruleActionParamMap. */ -RuleActionParam JsonTypes::unpackRuleActionParam(const QVariantMap &ruleActionParamMap) -{ - if (ruleActionParamMap.keys().count() == 0) - return RuleActionParam(); - - ParamTypeId paramTypeId = ParamTypeId(ruleActionParamMap.value("paramTypeId").toString()); - QString paramName = ruleActionParamMap.value("paramName").toString(); - - RuleActionParam param; - if (paramTypeId.isNull()) { - param = RuleActionParam(paramName); - } else { - param = RuleActionParam(paramTypeId); - } - param.setValue(ruleActionParamMap.value("value")); - param.setEventTypeId(EventTypeId(ruleActionParamMap.value("eventTypeId").toString())); - param.setEventParamTypeId(ParamTypeId(ruleActionParamMap.value("eventParamTypeId").toString())); - param.setStateDeviceId(DeviceId(ruleActionParamMap.value("stateDeviceId").toString())); - param.setStateTypeId(StateTypeId(ruleActionParamMap.value("stateTypeId").toString())); - return param; -} - -/*! Returns a \l{RuleActionParamList} created from the given \a ruleActionParamList. */ -RuleActionParamList JsonTypes::unpackRuleActionParams(const QVariantList &ruleActionParamList) -{ - RuleActionParamList ruleActionParams; - foreach (const QVariant ¶mVariant, ruleActionParamList) - ruleActionParams.append(unpackRuleActionParam(paramVariant.toMap())); - - return ruleActionParams; -} - -/*! Returns a \l{ParamDescriptor} created from the given \a paramMap. */ -ParamDescriptor JsonTypes::unpackParamDescriptor(const QVariantMap ¶mMap) -{ - QString operatorString = paramMap.value("operator").toString(); - QMetaObject metaObject = Types::staticMetaObject; - int enumIndex = metaObject.indexOfEnumerator("ValueOperator"); - QMetaEnum metaEnum = metaObject.enumerator(enumIndex); - Types::ValueOperator valueOperator = static_cast(metaEnum.keyToValue(operatorString.toLatin1().data())); - - if (paramMap.contains("paramTypeId")) { - ParamDescriptor param = ParamDescriptor(ParamTypeId(paramMap.value("paramTypeId").toString()), paramMap.value("value")); - param.setOperatorType(valueOperator); - return param; - } - ParamDescriptor param = ParamDescriptor(paramMap.value("paramName").toString(), paramMap.value("value")); - param.setOperatorType(valueOperator); - return param; -} - -/*! Returns a list of \l{ParamDescriptor} created from the given \a paramList. */ -QList JsonTypes::unpackParamDescriptors(const QVariantList ¶mList) -{ - QList params; - foreach (const QVariant ¶mVariant, paramList) - params.append(unpackParamDescriptor(paramVariant.toMap())); - - return params; -} - -/*! Returns a \l{EventDescriptor} created from the given \a eventDescriptorMap. */ -EventDescriptor JsonTypes::unpackEventDescriptor(const QVariantMap &eventDescriptorMap) -{ - EventTypeId eventTypeId(eventDescriptorMap.value("eventTypeId").toString()); - DeviceId eventDeviceId(eventDescriptorMap.value("deviceId").toString()); - QString interface = eventDescriptorMap.value("interface").toString(); - QString interfaceEvent = eventDescriptorMap.value("interfaceEvent").toString(); - QList eventParams = JsonTypes::unpackParamDescriptors(eventDescriptorMap.value("paramDescriptors").toList()); - if (!eventDeviceId.isNull() && !eventTypeId.isNull()) { - return EventDescriptor(eventTypeId, eventDeviceId, eventParams); - } - return EventDescriptor(interface, interfaceEvent, eventParams); -} - -/*! Returns a \l{StateEvaluator} created from the given \a stateEvaluatorMap. */ -StateEvaluator JsonTypes::unpackStateEvaluator(const QVariantMap &stateEvaluatorMap) -{ - StateEvaluator ret(unpackStateDescriptor(stateEvaluatorMap.value("stateDescriptor").toMap())); - if (stateEvaluatorMap.contains("operator")) { - ret.setOperatorType(static_cast(s_stateOperator.indexOf(stateEvaluatorMap.value("operator").toString()))); - } else { - ret.setOperatorType(Types::StateOperatorAnd); - } - - QList childEvaluators; - foreach (const QVariant &childEvaluator, stateEvaluatorMap.value("childEvaluators").toList()) - childEvaluators.append(unpackStateEvaluator(childEvaluator.toMap())); - - ret.setChildEvaluators(childEvaluators); - return ret; -} - -/*! Returns a \l{StateDescriptor} created from the given \a stateDescriptorMap. */ -StateDescriptor JsonTypes::unpackStateDescriptor(const QVariantMap &stateDescriptorMap) -{ - StateTypeId stateTypeId(stateDescriptorMap.value("stateTypeId").toString()); - DeviceId deviceId(stateDescriptorMap.value("deviceId").toString()); - QString interface(stateDescriptorMap.value("interface").toString()); - QString interfaceState(stateDescriptorMap.value("interfaceState").toString()); - QVariant value = stateDescriptorMap.value("value"); - Types::ValueOperator operatorType = static_cast(s_valueOperator.indexOf(stateDescriptorMap.value("operator").toString())); - if (!deviceId.isNull() && !stateTypeId.isNull()) { - StateDescriptor stateDescriptor(stateTypeId, deviceId, value, operatorType); - return stateDescriptor; - } - StateDescriptor stateDescriptor(interface, interfaceState, value, operatorType); - return stateDescriptor; -} - -/*! Returns a \l{LogFilter} created from the given \a logFilterMap. */ -LogFilter JsonTypes::unpackLogFilter(const QVariantMap &logFilterMap) -{ - LogFilter filter; - if (logFilterMap.contains("timeFilters")) { - QVariantList timeFilters = logFilterMap.value("timeFilters").toList(); - foreach (const QVariant &timeFilter, timeFilters) { - QVariantMap timeFilterMap = timeFilter.toMap(); - QDateTime startDate; QDateTime endDate; - if (timeFilterMap.contains("startDate")) - startDate = QDateTime::fromTime_t(timeFilterMap.value("startDate").toUInt()); - - if (timeFilterMap.contains("endDate")) - endDate = QDateTime::fromTime_t(timeFilterMap.value("endDate").toUInt()); - - filter.addTimeFilter(startDate, endDate); - } - } - - if (logFilterMap.contains("loggingSources")) { - QVariantList loggingSources = logFilterMap.value("loggingSources").toList(); - foreach (const QVariant &source, loggingSources) { - filter.addLoggingSource(static_cast(s_loggingSource.indexOf(source.toString()))); - } - } - if (logFilterMap.contains("loggingLevels")) { - QVariantList loggingLevels = logFilterMap.value("loggingLevels").toList(); - foreach (const QVariant &level, loggingLevels) { - filter.addLoggingLevel(static_cast(s_loggingLevel.indexOf(level.toString()))); - } - } - if (logFilterMap.contains("eventTypes")) { - QVariantList eventTypes = logFilterMap.value("eventTypes").toList(); - foreach (const QVariant &eventType, eventTypes) { - filter.addLoggingEventType(static_cast(s_loggingEventType.indexOf(eventType.toString()))); - } - } - if (logFilterMap.contains("typeIds")) { - QVariantList typeIds = logFilterMap.value("typeIds").toList(); - foreach (const QVariant &typeId, typeIds) { - filter.addTypeId(typeId.toUuid()); - } - } - if (logFilterMap.contains("deviceIds")) { - QVariantList deviceIds = logFilterMap.value("deviceIds").toList(); - foreach (const QVariant &deviceId, deviceIds) { - filter.addDeviceId(DeviceId(deviceId.toString())); - } - } - if (logFilterMap.contains("values")) { - QVariantList values = logFilterMap.value("values").toList(); - foreach (const QVariant &value, values) { - filter.addValue(value.toString()); - } - } - if (logFilterMap.contains("limit")) { - filter.setLimit(logFilterMap.value("limit", -1).toInt()); - } - if (logFilterMap.contains("offset")) { - filter.setOffset(logFilterMap.value("offset").toInt()); - } - - return filter; -} - -/*! Returns a \l{RepeatingOption} created from the given \a repeatingOptionMap. */ -RepeatingOption JsonTypes::unpackRepeatingOption(const QVariantMap &repeatingOptionMap) -{ - RepeatingOption::RepeatingMode mode = static_cast(s_repeatingMode.indexOf(repeatingOptionMap.value("mode").toString())); - - QList weekDays; - if (repeatingOptionMap.contains("weekDays")) { - foreach (const QVariant weekDayVariant, repeatingOptionMap.value("weekDays").toList()) { - weekDays.append(weekDayVariant.toInt()); - } - } - - QList monthDays; - if (repeatingOptionMap.contains("monthDays")) { - foreach (const QVariant monthDayVariant, repeatingOptionMap.value("monthDays").toList()) { - monthDays.append(monthDayVariant.toInt()); - } - } - - return RepeatingOption(mode, weekDays, monthDays); -} - -/*! Returns a \l{CalendarItem} created from the given \a calendarItemMap. */ -CalendarItem JsonTypes::unpackCalendarItem(const QVariantMap &calendarItemMap) -{ - CalendarItem calendarItem; - calendarItem.setDuration(calendarItemMap.value("duration").toUInt()); - - if (calendarItemMap.contains("datetime")) - calendarItem.setDateTime(QDateTime::fromTime_t(calendarItemMap.value("datetime").toUInt())); - - if (calendarItemMap.contains("startTime")) - calendarItem.setStartTime(QTime::fromString(calendarItemMap.value("startTime").toString(), "hh:mm")); - - if (calendarItemMap.contains("repeating")) - calendarItem.setRepeatingOption(unpackRepeatingOption(calendarItemMap.value("repeating").toMap())); - - return calendarItem; -} - -/*! Returns a \l{TimeEventItem} created from the given \a timeEventItemMap. */ -TimeEventItem JsonTypes::unpackTimeEventItem(const QVariantMap &timeEventItemMap) -{ - TimeEventItem timeEventItem; - - if (timeEventItemMap.contains("datetime")) - timeEventItem.setDateTime(timeEventItemMap.value("datetime").toUInt()); - - if (timeEventItemMap.contains("time")) - timeEventItem.setTime(timeEventItemMap.value("time").toTime()); - - if (timeEventItemMap.contains("repeating")) - timeEventItem.setRepeatingOption(unpackRepeatingOption(timeEventItemMap.value("repeating").toMap())); - - return timeEventItem; -} - -/*! Returns a \l{TimeDescriptor} created from the given \a timeDescriptorMap. */ -TimeDescriptor JsonTypes::unpackTimeDescriptor(const QVariantMap &timeDescriptorMap) -{ - TimeDescriptor timeDescriptor; - - if (timeDescriptorMap.contains("calendarItems")) { - QList calendarItems; - foreach (const QVariant &calendarItemValiant, timeDescriptorMap.value("calendarItems").toList()) { - calendarItems.append(unpackCalendarItem(calendarItemValiant.toMap())); - } - timeDescriptor.setCalendarItems(calendarItems); - } - - if (timeDescriptorMap.contains("timeEventItems")) { - QList timeEventItems; - foreach (const QVariant &timeEventItemValiant, timeDescriptorMap.value("timeEventItems").toList()) { - timeEventItems.append(unpackTimeEventItem(timeEventItemValiant.toMap())); - } - timeDescriptor.setTimeEventItems(timeEventItems); - } - - return timeDescriptor; -} - -/*! Returns a \l{Tag} created from the given \a tagMap. */ -Tag JsonTypes::unpackTag(const QVariantMap &tagMap) -{ - DeviceId deviceId = DeviceId(tagMap.value("deviceId").toString()); - RuleId ruleId = RuleId(tagMap.value("ruleId").toString()); - QString appId = tagMap.value("appId").toString(); - QString tagId = tagMap.value("tagId").toString(); - QString value = tagMap.value("value").toString(); - if (!deviceId.isNull()) { - return Tag(deviceId, appId, tagId, value); - } - return Tag(ruleId, appId, tagId, value); -} - -ServerConfiguration JsonTypes::unpackServerConfiguration(const QVariantMap &serverConfigurationMap) -{ - ServerConfiguration serverConfiguration; - serverConfiguration.id = serverConfigurationMap.value("id").toString(); - serverConfiguration.address = QHostAddress(serverConfigurationMap.value("address").toString()); - serverConfiguration.port = serverConfigurationMap.value("port").toUInt(); - serverConfiguration.sslEnabled = serverConfigurationMap.value("sslEnabled", true).toBool(); - serverConfiguration.authenticationEnabled = serverConfigurationMap.value("authenticationEnabled", true).toBool(); - return serverConfiguration; -} - -WebServerConfiguration JsonTypes::unpackWebServerConfiguration(const QVariantMap &webServerConfigurationMap) -{ - ServerConfiguration tmp = unpackServerConfiguration(webServerConfigurationMap); - WebServerConfiguration webServerConfiguration; - webServerConfiguration.id = tmp.id; - webServerConfiguration.address = tmp.address; - webServerConfiguration.port = tmp.port; - webServerConfiguration.sslEnabled = tmp.sslEnabled; - webServerConfiguration.authenticationEnabled = tmp.authenticationEnabled; - webServerConfiguration.publicFolder = webServerConfigurationMap.value("publicFolder").toString(); - return webServerConfiguration; -} - -MqttPolicy JsonTypes::unpackMqttPolicy(const QVariantMap &mqttPolicyMap) -{ - MqttPolicy policy; - policy.clientId = mqttPolicyMap.value("clientId").toString(); - policy.username = mqttPolicyMap.value("username").toString(); - policy.password = mqttPolicyMap.value("password").toString(); - policy.allowedPublishTopicFilters = mqttPolicyMap.value("allowedPublishTopicFilters").toStringList(); - policy.allowedSubscribeTopicFilters = mqttPolicyMap.value("allowedSubscribeTopicFilters").toStringList(); - return policy; -} - -/*! Compairs the given \a map with the given \a templateMap. Returns the error string and false if - the params are not valid. */ -QPair JsonTypes::validateMap(const QVariantMap &templateMap, const QVariantMap &map) -{ - s_lastError.clear(); - - // Make sure all values defined in the template are around - foreach (const QString &key, templateMap.keys()) { - QString strippedKey = key; - strippedKey.remove(QRegExp("^o:")); - if (!key.startsWith("o:") && !map.contains(strippedKey)) { - qCWarning(dcJsonRpc) << "*** missing key" << key; - qCWarning(dcJsonRpc) << "Expected: " << templateMap; - qCWarning(dcJsonRpc) << "Got: " << map; - QJsonDocument jsonDoc = QJsonDocument::fromVariant(map); - return report(false, QString("Missing key %1 in %2").arg(key).arg(QString(jsonDoc.toJson(QJsonDocument::Compact)))); - } - if (map.contains(strippedKey)) { - QPair result = validateVariant(templateMap.value(key), map.value(strippedKey)); - if (!result.first) { - QJsonDocument templateDoc = QJsonDocument::fromVariant(templateMap.value(key)); - QJsonDocument mapDoc = QJsonDocument::fromVariant(map.value(strippedKey)); - qCWarning(dcJsonRpc).nospace() << "Object\n" << qUtf8Printable(mapDoc.toJson(QJsonDocument::Indented)) << "not matching template\n" << qUtf8Printable(templateDoc.toJson(QJsonDocument::Indented)); - return result; - } - } - } - - // Make sure there aren't any other parameters than the allowed ones - foreach (const QString &key, map.keys()) { - QString optKey = "o:" + key; - - if (!templateMap.contains(key) && !templateMap.contains(optKey)) { - qCWarning(dcJsonRpc) << "Forbidden param" << key << "in params"; - QJsonDocument jsonDoc = QJsonDocument::fromVariant(map); - return report(false, QString("Forbidden key \"%1\" in %2").arg(key).arg(QString(jsonDoc.toJson(QJsonDocument::Compact)))); - } - } - - return report(true, ""); -} - -/*! Compairs the given \a value with the given \a templateValue. Returns the error string and false if - the params are not valid. */ -QPair JsonTypes::validateProperty(const QVariant &templateValue, const QVariant &value) -{ - QString strippedTemplateValue = templateValue.toString(); - - if (strippedTemplateValue == JsonTypes::basicTypeToString(JsonTypes::Variant)) { - return report(true, ""); - } - if (strippedTemplateValue == JsonTypes::basicTypeToString(QVariant::Uuid)) { - QString errorString = QString("Param %1 is not a uuid.").arg(value.toString()); - return report(value.canConvert(QVariant::Uuid), errorString); - } - if (strippedTemplateValue == JsonTypes::basicTypeToString(QVariant::String)) { - QString errorString = QString("Param %1 is not a string.").arg(value.toString()); - return report(value.canConvert(QVariant::String), errorString); - } - if (strippedTemplateValue == JsonTypes::basicTypeToString(QVariant::StringList)) { - QString errorString = QString("Param %1 is not a string list.").arg(value.toString()); - return report(value.canConvert(QVariant::StringList), errorString); - } - if (strippedTemplateValue == JsonTypes::basicTypeToString(QVariant::Bool)) { - QString errorString = QString("Param %1 is not a bool.").arg(value.toString()); - return report(value.canConvert(QVariant::Bool), errorString); - } - if (strippedTemplateValue == JsonTypes::basicTypeToString(QVariant::Int)) { - QString errorString = QString("Param %1 is not a int.").arg(value.toString()); - return report(value.canConvert(QVariant::Int), errorString); - } - if (strippedTemplateValue == JsonTypes::basicTypeToString(QVariant::UInt)) { - QString errorString = QString("Param %1 is not a uint.").arg(value.toString()); - return report(value.canConvert(QVariant::UInt), errorString); - } - if (strippedTemplateValue == JsonTypes::basicTypeToString(QVariant::Double)) { - QString errorString = QString("Param %1 is not a double.").arg(value.toString()); - return report(value.canConvert(QVariant::Double), errorString); - } - if (strippedTemplateValue == JsonTypes::basicTypeToString(QVariant::Time)) { - QString errorString = QString("Param %1 is not a time (hh:mm).").arg(value.toString()); - return report(value.canConvert(QVariant::Time), errorString); - } - - qCWarning(dcJsonRpc) << QString("Unhandled property type: %1 (expected: %2)").arg(value.toString()).arg(strippedTemplateValue); - QString errorString = QString("Unhandled property type: %1 (expected: %2)").arg(value.toString()).arg(strippedTemplateValue); - return report(false, errorString); -} - -/*! Compairs the given \a list with the given \a templateList. Returns the error string and false if - the params are not valid. */ -QPair JsonTypes::validateList(const QVariantList &templateList, const QVariantList &list) -{ - Q_ASSERT(templateList.count() == 1); - QVariant entryTemplate = templateList.first(); - - for (int i = 0; i < list.count(); ++i) { - QVariant listEntry = list.at(i); - QPair result = validateVariant(entryTemplate, listEntry); - if (!result.first) { - qCWarning(dcJsonRpc) << "List entry not matching template"; - return result; - } - } - return report(true, ""); -} - -/*! Compairs the given \a variant with the given \a templateVariant. Returns the error string and false if - the params are not valid. */ -QPair JsonTypes::validateVariant(const QVariant &templateVariant, const QVariant &variant) -{ - switch(templateVariant.type()) { - case QVariant::String: - if (templateVariant.toString().startsWith("$ref:")) { - QString refName = templateVariant.toString(); - if (refName == actionRef()) { - QPair result = validateMap(actionDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "Error validating action"; - return result; - } - } else if (refName == eventRef()) { - QPair result = validateMap(eventDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "Event not valid"; - return result; - } - } else if (refName == paramRef()) { - if (!variant.canConvert(QVariant::Map)) { - report(false, "Param not valid. Should be a map."); - } - } else if (refName == paramDescriptorRef()) { - QPair result = validateMap(paramDescriptorDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "ParamDescriptor not valid"; - return result; - } - } else if (refName == deviceRef()) { - QPair result = validateMap(deviceDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "Device not valid"; - return result; - } - } else if (refName == deviceDescriptorRef()) { - QPair result = validateMap(deviceDescriptorDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "Devicedescriptor not valid"; - return result; - } - } else if (refName == vendorRef()) { - QPair result = validateMap(vendorDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "Value not allowed in" << vendorRef(); - } - } else if (refName == deviceClassRef()) { - QPair result = validateMap(deviceClassDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "Device class not valid"; - return result; - } - } else if (refName == paramTypeRef()) { - QPair result = validateMap(paramTypeDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "Param types not matching"; - return result; - } - } else if (refName == ruleActionRef()) { - QPair result = validateMap(ruleActionDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "RuleAction type not matching"; - return result; - } - } else if (refName == ruleActionParamRef()) { - QPair result = validateMap(ruleActionParamDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "RuleActionParam type not matching"; - return result; - } - } else if (refName == actionTypeRef()) { - QPair result = validateMap(actionTypeDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "Action type not matching"; - return result; - } - } else if (refName == eventTypeRef()) { - QPair result = validateMap(eventTypeDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "Event type not matching"; - return result; - } - } else if (refName == stateTypeRef()) { - QPair result = validateMap(stateTypeDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "State type not matching"; - return result; - } - } else if (refName == stateEvaluatorRef()) { - QPair result = validateMap(stateEvaluatorDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "StateEvaluator type not matching"; - return result; - } - } else if (refName == stateDescriptorRef()) { - QPair result = validateMap(stateDescriptorDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "StateDescriptor type not matching"; - return result; - } - } else if (refName == pluginRef()) { - QPair result = validateMap(pluginDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "Plugin not matching"; - return result; - } - } else if (refName == ruleRef()) { - QPair result = validateMap(ruleDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "Rule type not matching"; - return result; - } - } else if (refName == ruleDescriptionRef()) { - QPair result = validateMap(s_ruleDescription, variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "RuleDescription type not matching"; - return result; - } - } else if (refName == stateRef()) { - QPair result = validateMap(s_state, variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "State not matching"; - return result; - } - } else if (refName == eventDescriptorRef()) { - QPair result = validateMap(eventDescriptorDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "Eventdescriptor not matching"; - return result; - } - } else if (refName == logEntryRef()) { - QPair result = validateMap(logEntryDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "LogEntry not matching"; - return result; - } - } else if (refName == timeDescriptorRef()) { - QPair result = validateMap(timeDescriptorDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "TimeDescriptor not matching"; - return result; - } - } else if (refName == calendarItemRef()) { - QPair result = validateMap(calendarItemDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "CalendarItem not matching"; - return result; - } - } else if (refName == timeDescriptorRef()) { - QPair result = validateMap(timeEventItemDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "TimeEventItem not matching"; - return result; - } - } else if (refName == repeatingOptionRef()) { - QPair result = validateMap(repeatingOptionDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "RepeatingOption not matching"; - return result; - } - } else if (refName == timeEventItemRef()) { - QPair result = validateMap(timeEventItemDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "TimeEventItem not matching"; - return result; - } - } else if (refName == wirelessAccessPointRef()) { - QPair result = validateMap(wirelessAccessPointDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "WirelessAccessPoint not matching"; - return result; - } - } else if (refName == wiredNetworkDeviceRef()) { - QPair result = validateMap(wiredNetworkDeviceDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "WiredNetworkDevice not matching"; - return result; - } - } else if (refName == wirelessNetworkDeviceRef()) { - QPair result = validateMap(wirelessNetworkDeviceDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "WirelessNetworkDevice not matching"; - return result; - } - } else if (refName == tokenInfoRef()) { - QPair result = validateMap(tokenInfoDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "TokenInfo not matching"; - return result; - } - } else if (refName == serverConfigurationRef()) { - QPair result = validateMap(serverConfigurationDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "ServerConfiguration not matching"; - return result; - } - } else if (refName == webServerConfigurationRef()) { - QPair result = validateMap(webServerConfigurationDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "WebServerConfiguration not matching"; - return result; - } - } else if (refName == mqttPolicyRef()) { - QPair result = validateMap(s_mqttPolicy, variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "MqttPolicy not matching"; - return result; - } - } else if (refName == tagRef()) { - QPair result = validateMap(tagDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "Tag not matching"; - return result; - } - } else if (refName == packageRef()) { - QPair result = validateMap(packageDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "Package not matching"; - return result; - } - } else if (refName == repositoryRef()) { - QPair result = validateMap(repositoryDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "Repository not matching"; - return result; - } - } else if (refName == browserItemRef()) { - QPair result = validateMap(browserItemDescription(), variant.toMap()); - if (!result.first) { - qCWarning(dcJsonRpc) << "BrowserItem not matching"; - return result; - } - } else if (refName == basicTypeRef()) { - QPair result = validateBasicType(variant); - if (!result.first) { - qCWarning(dcJsonRpc) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(basicTypeRef()); - return result; - } - } else if (refName == stateOperatorRef()) { - QPair result = validateEnum(s_stateOperator, variant); - if (!result.first) { - qCWarning(dcJsonRpc) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(stateOperatorRef()); - return result; - } - } else if (refName == createMethodRef()) { - QPair result = validateEnum(s_createMethod, variant); - if (!result.first) { - qCWarning(dcJsonRpc) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(createMethodRef()); - return result; - } - } else if (refName == setupMethodRef()) { - QPair result = validateEnum(s_setupMethod, variant); - if (!result.first) { - qCWarning(dcJsonRpc) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(setupMethodRef()); - return result; - } - } else if (refName == valueOperatorRef()) { - QPair result = validateEnum(s_valueOperator, variant); - if (!result.first) { - qCWarning(dcJsonRpc) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(valueOperatorRef()); - return result; - } - } else if (refName == deviceErrorRef()) { - QPair result = validateEnum(s_deviceError, variant); - if (!result.first) { - qCWarning(dcJsonRpc) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(deviceErrorRef()); - return result; - } - } else if (refName == ruleErrorRef()) { - QPair result = validateEnum(s_ruleError, variant); - if (!result.first) { - qCWarning(dcJsonRpc) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(ruleErrorRef()); - return result; - } - } else if (refName == loggingErrorRef()) { - QPair result = validateEnum(s_loggingError, variant); - if (!result.first) { - qCWarning(dcJsonRpc) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(loggingErrorRef()); - return result; - } - } else if (refName == loggingSourceRef()) { - QPair result = validateEnum(s_loggingSource, variant); - if (!result.first) { - qCWarning(dcJsonRpc) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(loggingSourceRef()); - return result; - } - } else if (refName == loggingLevelRef()) { - QPair result = validateEnum(s_loggingLevel, variant); - if (!result.first) { - qCWarning(dcJsonRpc) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(loggingLevelRef()); - return result; - } - } else if (refName == loggingEventTypeRef()) { - QPair result = validateEnum(s_loggingEventType, variant); - if (!result.first) { - qCWarning(dcJsonRpc) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(loggingEventTypeRef()); - return result; - } - } else if (refName == inputTypeRef()) { - QPair result = validateEnum(s_inputType, variant); - if (!result.first) { - qCWarning(dcJsonRpc) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(inputTypeRef()); - return result; - } - } else if (refName == unitRef()) { - QPair result = validateEnum(s_unit, variant); - if (!result.first) { - qCWarning(dcJsonRpc) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(unitRef()); - return result; - } - } else if (refName == repeatingModeRef()) { - QPair result = validateEnum(s_repeatingMode, variant); - if (!result.first) { - qCWarning(dcJsonRpc) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(repeatingModeRef()); - return result; - } - } else if (refName == removePolicyRef()) { - QPair result = validateEnum(s_removePolicy, variant); - if (!result.first) { - qCWarning(dcJsonRpc) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(removePolicyRef()); - return result; - } - } else if (refName == configurationErrorRef()) { - QPair result = validateEnum(s_configurationError, variant); - if (!result.first) { - qCWarning(dcJsonRpc) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(configurationErrorRef()); - return result; - } - } else if (refName == networkManagerStateRef()) { - QPair result = validateEnum(s_networkManagerState, variant); - if (!result.first) { - qCWarning(dcJsonRpc) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(networkManagerStateRef()); - return result; - } - } else if (refName == networkManagerErrorRef()) { - QPair result = validateEnum(s_networkManagerError, variant); - if (!result.first) { - qCWarning(dcJsonRpc) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(networkManagerErrorRef()); - return result; - } - } else if (refName == networkDeviceStateRef()) { - QPair result = validateEnum(s_networkDeviceState, variant); - if (!result.first) { - qCWarning(dcJsonRpc) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(networkDeviceStateRef()); - return result; - } - } else if (refName == userErrorRef()) { - QPair result = validateEnum(s_userError, variant); - if (!result.first) { - qCWarning(dcJsonRpc) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(userErrorRef()); - return result; - } - } else if (refName == tagErrorRef()) { - QPair result = validateEnum(s_tagError, variant); - if (!result.first) { - qCWarning(dcJsonRpc()) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(tagErrorRef()); - return result; - } - } else if (refName == cloudConnectionStateRef()) { - QPair result = validateEnum(s_cloudConnectionState, variant); - if (!result.first) { - qCWarning(dcJsonRpc()) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(cloudConnectionStateRef()); - return result; - } - } else if (refName == browserIconRef()) { - QPair result = validateEnum(s_browserIcon, variant); - if (!result.first) { - qCWarning(dcJsonRpc()) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(browserIconRef()); - return result; - } - } else if (refName == mediaBrowserIconRef()) { - QPair result = validateEnum(s_mediaBrowserIcon, variant); - if (!result.first) { - qCWarning(dcJsonRpc()) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(mediaBrowserIconRef()); - return result; - } - } else if (refName == "$ref:Namespace") { - // This is quite hacky, but unless we explicitly propagate the namespace info in here we can't know. - // Let's assume jsonrpcserver handles this properly... - // Actually this entire jsontypes file should probably be split up into the handlers themselves but that's a different story. - return qMakePair(true, QString()); - } else { - Q_ASSERT_X(false, "JsonTypes", QString("Unhandled ref: %1").arg(refName).toLatin1().data()); - return report(false, QString("Unhandled ref %1. Server implementation incomplete.").arg(refName)); - } - } else { - QPair result = JsonTypes::validateProperty(templateVariant, variant); - if (!result.first) { - qCWarning(dcJsonRpc) << "property not matching:" << templateVariant << "!=" << variant; - return result; - } - } - break; - case QVariant::Map: { - QPair result = validateMap(templateVariant.toMap(), variant.toMap()); - if (!result.first) { - return result; - } - break; - } - case QVariant::List: { - QPair result = validateList(templateVariant.toList(), variant.toList()); - if (!result.first) { - return result; - } - break; - } - default: - qCWarning(dcJsonRpc) << "Unhandled value" << templateVariant; - return report(false, QString("Unhandled value %1.").arg(templateVariant.toString())); - } - return report(true, ""); -} - -/*! Verify the given \a variant with the possible \l{BasicType}. Returns the error string and false if - the params are not valid. */ -QPair JsonTypes::validateBasicType(const QVariant &variant) -{ - if (variant.canConvert(QVariant::Uuid) && QVariant(variant).convert(QVariant::Uuid)) { - return report(true, ""); - } - if (variant.canConvert(QVariant::String) && QVariant(variant).convert(QVariant::String)) { - return report(true, ""); - } - if (variant.canConvert(QVariant::StringList) && QVariant(variant).convert(QVariant::StringList)) { - return report(true, ""); - } - if (variant.canConvert(QVariant::Int) && QVariant(variant).convert(QVariant::Int)) { - return report(true, ""); - } - if (variant.canConvert(QVariant::UInt) && QVariant(variant).convert(QVariant::UInt)){ - return report(true, ""); - } - if (variant.canConvert(QVariant::Double) && QVariant(variant).convert(QVariant::Double)) { - return report(true, ""); - } - if (variant.canConvert(QVariant::Bool && QVariant(variant).convert(QVariant::Bool))) { - return report(true, ""); - } - if (variant.canConvert(QVariant::Color) && QVariant(variant).convert(QVariant::Color)) { - return report(true, ""); - } - if (variant.canConvert(QVariant::Time) && QVariant(variant).convert(QVariant::Time)) { - return report(true, ""); - } - - return report(false, QString("Error validating basic type %1.").arg(variant.toString())); -} - -/*! Compairs the given \a value with the given \a enumDescription. Returns the error string and false if - the enum does not contain the given \a value. */ -QPair JsonTypes::validateEnum(const QVariantList &enumDescription, const QVariant &value) -{ - QStringList enumStrings; - foreach (const QVariant &variant, enumDescription) - enumStrings.append(variant.toString()); - - return report(enumDescription.contains(value.toString()), QString("Value %1 not allowed in %2").arg(value.toString()).arg(enumStrings.join(", "))); -} - -} diff --git a/libnymea-core/jsonrpc/jsontypes.h b/libnymea-core/jsonrpc/jsontypes.h deleted file mode 100644 index bc5f9878..00000000 --- a/libnymea-core/jsonrpc/jsontypes.h +++ /dev/null @@ -1,292 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * * - * Copyright (C) 2015 Simon Stürz * - * Copyright (C) 2014 Michael Zanetti * - * Copyright (C) 2017 Michael Zanetti * - * * - * This file is part of nymea. * - * * - * nymea 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. * - * * - * nymea 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 nymea. If not, see . * - * * - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -#ifndef JSONTYPES_H -#define JSONTYPES_H - -#include "devices/devicedescriptor.h" -#include "devices/devicemanager.h" -#include "ruleengine/rule.h" -#include "ruleengine/ruleengine.h" -#include "ruleengine/ruleactionparam.h" -#include "nymeaconfiguration.h" -#include "usermanager/usermanager.h" - -#include "types/deviceclass.h" -#include "types/event.h" -#include "types/action.h" -#include "types/actiontype.h" -#include "types/paramtype.h" -#include "types/paramdescriptor.h" -#include "types/mediabrowseritem.h" - -#include "logging/logging.h" -#include "logging/logentry.h" -#include "logging/logfilter.h" - -#include "tagging/tagsstorage.h" -#include "tagging/tag.h" - -#include "time/calendaritem.h" -#include "time/repeatingoption.h" -#include "time/timedescriptor.h" -#include "time/timeeventitem.h" - -#include "networkmanager/networkmanager.h" -#include "networkmanager/networkdevice.h" -#include "networkmanager/wirednetworkdevice.h" -#include "networkmanager/wirelessnetworkdevice.h" -#include "networkmanager/wirelessaccesspoint.h" - -#include "cloud/cloudmanager.h" -#include "platform/package.h" -#include "platform/repository.h" - -#include - -#include -#include -#include - -class DevicePlugin; -class Device; - -namespace nymeaserver { - -#define DECLARE_OBJECT(typeName, jsonName) \ - public: \ - static QString typeName##Ref() { return QStringLiteral("$ref:") + QStringLiteral(jsonName); } \ - static QVariantMap typeName##Description() { \ - if (!s_initialized) { init(); } \ - return s_##typeName; \ - } \ - private: \ - static QVariantMap s_##typeName; \ - public: - -#define DECLARE_TYPE(typeName, enumString, className, enumName) \ - public: \ - static QString typeName##Ref() { return QStringLiteral("$ref:") + QStringLiteral(enumString); } \ - static QVariantList typeName() { \ - if (!s_initialized) { init(); } \ - return s_##typeName; \ - } \ - static QString typeName##ToString(className::enumName value) { \ - QMetaEnum metaEnum = QMetaEnum::fromType(); \ - return metaEnum.valueToKey(value); \ - } \ - private: \ - static QVariantList s_##typeName; \ - public: - -class JsonTypes -{ - Q_GADGET - -public: - enum BasicType { - Uuid, - String, - StringList, - Int, - Uint, - Double, - Bool, - Variant, - Color, - Time, - Object - }; - Q_ENUM(BasicType) - - static QVariantMap allTypes(); - - DECLARE_TYPE(basicType, "BasicType", JsonTypes, BasicType) - DECLARE_TYPE(stateOperator, "StateOperator", Types, StateOperator) - DECLARE_TYPE(valueOperator, "ValueOperator", Types, ValueOperator) - DECLARE_TYPE(inputType, "InputType", Types, InputType) - DECLARE_TYPE(unit, "Unit", Types, Unit) - DECLARE_TYPE(createMethod, "CreateMethod", DeviceClass, CreateMethod) - DECLARE_TYPE(setupMethod, "SetupMethod", DeviceClass, SetupMethod) - DECLARE_TYPE(deviceError, "DeviceError", Device, DeviceError) - DECLARE_TYPE(removePolicy, "RemovePolicy", RuleEngine, RemovePolicy) - DECLARE_TYPE(ruleError, "RuleError", RuleEngine, RuleError) - DECLARE_TYPE(loggingError, "LoggingError", Logging, LoggingError) - DECLARE_TYPE(loggingSource, "LoggingSource", Logging, LoggingSource) - DECLARE_TYPE(loggingLevel, "LoggingLevel", Logging, LoggingLevel) - DECLARE_TYPE(loggingEventType, "LoggingEventType", Logging, LoggingEventType) - DECLARE_TYPE(repeatingMode, "RepeatingMode", RepeatingOption, RepeatingMode) - DECLARE_TYPE(configurationError, "ConfigurationError", NymeaConfiguration, ConfigurationError) - DECLARE_TYPE(networkManagerError, "NetworkManagerError", NetworkManager, NetworkManagerError) - DECLARE_TYPE(networkManagerState, "NetworkManagerState", NetworkManager, NetworkManagerState) - DECLARE_TYPE(networkDeviceState, "NetworkDeviceState", NetworkDevice, NetworkDeviceState) - DECLARE_TYPE(userError, "UserError", UserManager, UserError) - DECLARE_TYPE(tagError, "TagError", TagsStorage, TagError) - DECLARE_TYPE(cloudConnectionState, "CloudConnectionState", CloudManager, CloudConnectionState) - DECLARE_TYPE(browserIcon, "BrowserIcon", BrowserItem, BrowserIcon) - DECLARE_TYPE(mediaBrowserIcon, "MediaBrowserIcon", MediaBrowserItem, MediaBrowserIcon) - - DECLARE_OBJECT(paramType, "ParamType") - DECLARE_OBJECT(param, "Param") - DECLARE_OBJECT(paramDescriptor, "ParamDescriptor") - DECLARE_OBJECT(ruleAction, "RuleAction") - DECLARE_OBJECT(ruleActionParam, "RuleActionParam") - DECLARE_OBJECT(stateType, "StateType") - DECLARE_OBJECT(stateDescriptor, "StateDescriptor") - DECLARE_OBJECT(state, "State") - DECLARE_OBJECT(stateEvaluator, "StateEvaluator") - DECLARE_OBJECT(eventType, "EventType") - DECLARE_OBJECT(event, "Event") - DECLARE_OBJECT(eventDescriptor, "EventDescriptor") - DECLARE_OBJECT(actionType, "ActionType") - DECLARE_OBJECT(action, "Action") - DECLARE_OBJECT(plugin, "Plugin") - DECLARE_OBJECT(vendor, "Vendor") - DECLARE_OBJECT(deviceClass, "DeviceClass") - DECLARE_OBJECT(device, "Device") - DECLARE_OBJECT(deviceDescriptor, "DeviceDescriptor") - DECLARE_OBJECT(rule, "Rule") - DECLARE_OBJECT(ruleDescription, "RuleDescription") - DECLARE_OBJECT(logEntry, "LogEntry") - DECLARE_OBJECT(timeDescriptor, "TimeDescriptor") - DECLARE_OBJECT(calendarItem, "CalendarItem") - DECLARE_OBJECT(timeEventItem, "TimeEventItem") - DECLARE_OBJECT(repeatingOption, "RepeatingOption") - DECLARE_OBJECT(wirelessAccessPoint, "WirelessAccessPoint") - DECLARE_OBJECT(wiredNetworkDevice, "WiredNetworkDevice") - DECLARE_OBJECT(wirelessNetworkDevice, "WirelessNetworkDevice") - DECLARE_OBJECT(tokenInfo, "TokenInfo") - DECLARE_OBJECT(serverConfiguration, "ServerConfiguration") - DECLARE_OBJECT(webServerConfiguration, "WebServerConfiguration") - DECLARE_OBJECT(tag, "Tag") - DECLARE_OBJECT(mqttPolicy, "MqttPolicy") - DECLARE_OBJECT(package, "Package") - DECLARE_OBJECT(repository, "Repository") - DECLARE_OBJECT(browserItem, "BrowserItem") - - // pack types - static QVariantMap packEventType(const EventType &eventType, const PluginId &pluginId, const QLocale &locale); - static QVariantMap packEvent(const Event &event); - static QVariantMap packEventDescriptor(const EventDescriptor &event); - static QVariantMap packActionType(const ActionType &actionType, const PluginId &pluginId, const QLocale &locale); - static QVariantMap packAction(const Action &action); - static QVariantMap packRuleAction(const RuleAction &ruleAction); - static QVariantMap packRuleActionParam(const RuleActionParam &ruleActionParam); - static QVariantMap packState(const State &state); - static QVariantMap packStateType(const StateType &stateType, const PluginId &pluginId, const QLocale &locale); - static QVariantMap packStateDescriptor(const StateDescriptor &stateDescriptor); - static QVariantMap packStateEvaluator(const StateEvaluator &stateEvaluator); - static QVariantMap packParam(const Param ¶m); - static QVariantMap packBrowserItem(const BrowserItem &item); - static QVariantMap packParamType(const ParamType ¶mType, const PluginId &pluginId, const QLocale &locale); - static QVariantMap packParamDescriptor(const ParamDescriptor ¶mDescriptor); - static QVariantMap packVendor(const Vendor &vendor, const QLocale &locale); - static QVariantMap packDeviceClass(const DeviceClass &deviceClass, const QLocale &locale); - static QVariantMap packPlugin(DevicePlugin *pluginid, const QLocale &locale); - static QVariantMap packDevice(Device *device); - static QVariantMap packDeviceDescriptor(const DeviceDescriptor &descriptor); - static QVariantMap packRule(const Rule &rule); - static QVariantMap packRuleDescription(const Rule &rule); - static QVariantMap packLogEntry(const LogEntry &logEntry); - static QVariantMap packTag(const Tag &tag); - static QVariantMap packRepeatingOption(const RepeatingOption &option); - static QVariantMap packCalendarItem(const CalendarItem &calendarItem); - static QVariantMap packTimeEventItem(const TimeEventItem &timeEventItem); - static QVariantMap packTimeDescriptor(const TimeDescriptor &timeDescriptor); - static QVariantMap packWirelessAccessPoint(WirelessAccessPoint *wirelessAccessPoint); - static QVariantMap packWiredNetworkDevice(WiredNetworkDevice *networkDevice); - static QVariantMap packWirelessNetworkDevice(WirelessNetworkDevice *networkDevice); - - static QVariantList packParams(const ParamList ¶mList); - static QVariantList packBrowserItems(const BrowserItems &items); - static QVariantList packRules(const QList rules); - static QVariantList packCreateMethods(DeviceClass::CreateMethods createMethods); - static QVariantList packSupportedVendors(const QLocale &locale); - static QVariantList packSupportedDevices(const VendorId &vendorId, const QLocale &locale); - static QVariantList packConfiguredDevices(); - static QVariantList packDeviceStates(Device *device); - static QVariantList packDeviceDescriptors(const QList deviceDescriptors); - - static QVariantMap packBasicConfiguration(); - static QVariantMap packServerConfiguration(const ServerConfiguration &config); - static QVariantMap packWebServerConfiguration(const WebServerConfiguration &config); - static QVariantMap packMqttPolicy(const MqttPolicy &policy); - - static QVariantList packRuleDescriptions(); - static QVariantList packRuleDescriptions(const QList &rules); - - static QVariantList packActionTypes(const DeviceClass &deviceClass, const QLocale &locale); - static QVariantList packStateTypes(const DeviceClass &deviceClass, const QLocale &locale); - static QVariantList packEventTypes(const DeviceClass &deviceClass, const QLocale &locale); - static QVariantList packPlugins(const QLocale &locale); - - static QVariantMap packTokenInfo(const TokenInfo &tokenInfo); - - static QVariantMap packPackage(const Package &package); - static QVariantMap packRepository(const Repository &repository); - - static QString basicTypeToString(const QVariant::Type &type); - - // unpack Types - static Param unpackParam(const QVariantMap ¶mMap); - static ParamList unpackParams(const QVariantList ¶mList); - static Rule unpackRule(const QVariantMap &ruleMap); - static RuleAction unpackRuleAction(const QVariantMap &ruleActionMap); - static RuleActionParam unpackRuleActionParam(const QVariantMap &ruleActionParamMap); - static RuleActionParamList unpackRuleActionParams(const QVariantList &ruleActionParamList); - static ParamDescriptor unpackParamDescriptor(const QVariantMap ¶mDescriptorMap); - static QList unpackParamDescriptors(const QVariantList ¶mDescriptorList); - static EventDescriptor unpackEventDescriptor(const QVariantMap &eventDescriptorMap); - static StateEvaluator unpackStateEvaluator(const QVariantMap &stateEvaluatorMap); - static StateDescriptor unpackStateDescriptor(const QVariantMap &stateDescriptorMap); - static LogFilter unpackLogFilter(const QVariantMap &logFilterMap); - static RepeatingOption unpackRepeatingOption(const QVariantMap &repeatingOptionMap); - static CalendarItem unpackCalendarItem(const QVariantMap &calendarItemMap); - static TimeEventItem unpackTimeEventItem(const QVariantMap &timeEventItemMap); - static TimeDescriptor unpackTimeDescriptor(const QVariantMap &timeDescriptorMap); - static Tag unpackTag(const QVariantMap &tagMap); - - static ServerConfiguration unpackServerConfiguration(const QVariantMap &serverConfigurationMap); - static WebServerConfiguration unpackWebServerConfiguration(const QVariantMap &webServerConfigurationMap); - static MqttPolicy unpackMqttPolicy(const QVariantMap &mqttPolicyMap); - - // validate - static QPair validateMap(const QVariantMap &templateMap, const QVariantMap &map); - static QPair validateProperty(const QVariant &templateValue, const QVariant &value); - static QPair validateList(const QVariantList &templateList, const QVariantList &list); - static QPair validateVariant(const QVariant &templateVariant, const QVariant &variant); - static QPair validateEnum(const QVariantList &enumList, const QVariant &value); - static QPair validateBasicType(const QVariant &variant); - -private: - static bool s_initialized; - static void init(); - - static QPair report(bool status, const QString &message); - static QVariantList enumToStrings(const QMetaObject &metaObject, const QString &enumName); - - static QString s_lastError; -}; - -} - -#endif // JSONTYPES_H diff --git a/libnymea-core/jsonrpc/jsonvalidator.cpp b/libnymea-core/jsonrpc/jsonvalidator.cpp new file mode 100644 index 00000000..9846e834 --- /dev/null +++ b/libnymea-core/jsonrpc/jsonvalidator.cpp @@ -0,0 +1,278 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2019 Michael Zanetti * + * * + * This file is part of nymea. * + * * + * nymea 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. * + * * + * nymea 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 nymea. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "jsonvalidator.h" +#include "jsonrpc/jsonhandler.h" + +#include "loggingcategories.h" + +#include +#include +#include + +namespace nymeaserver { + +bool JsonValidator::checkRefs(const QVariantMap &map, const QVariantMap &api) +{ + QVariantMap enums = api.value("enums").toMap(); + QVariantMap flags = api.value("flags").toMap(); + QVariantMap types = api.value("types").toMap(); + foreach (const QString &key, map.keys()) { + if (map.value(key).toString().startsWith("$ref:")) { + QString refName = map.value(key).toString().remove("$ref:"); + if (!enums.contains(refName) && !flags.contains(refName) && !types.contains(refName)) { + qCWarning(dcJsonRpc()) << "Invalid reference to" << refName; + return false; + } + } + if (map.value(key).type() == QVariant::Map) { + bool ret = checkRefs(map.value(key).toMap(), api); + if (!ret) { + return false; + } + } + if (map.value(key).type() == QVariant::List) { + foreach (const QVariant &entry, map.value(key).toList()) { + if (entry.toString().startsWith("$ref:")) { + QString refName = entry.toString().remove("$ref:"); + if (!enums.contains(refName) && !flags.contains(refName) && !types.contains(refName)) { + qCWarning(dcJsonRpc()) << "Invalid reference to" << refName; + return false; + } + } + if (entry.type() == QVariant::Map) { + bool ret = checkRefs(map.value(key).toMap(), api); + if (!ret) { + return false; + } + } + } + } + } + return true; + +} + +JsonValidator::Result JsonValidator::validateParams(const QVariantMap ¶ms, const QString &method, const QVariantMap &api) +{ + QVariantMap paramDefinition = api.value("methods").toMap().value(method).toMap().value("params").toMap(); + m_result = validateMap(params, paramDefinition, api, QIODevice::WriteOnly); + m_result.setWhere(method + ", param " + m_result.where()); + return m_result; +} + +JsonValidator::Result JsonValidator::validateReturns(const QVariantMap &returns, const QString &method, const QVariantMap &api) +{ + QVariantMap returnsDefinition = api.value("methods").toMap().value(method).toMap().value("returns").toMap(); + m_result = validateMap(returns, returnsDefinition, api, QIODevice::ReadOnly); + m_result.setWhere(method + ", returns " + m_result.where()); + return m_result; +} + +JsonValidator::Result JsonValidator::validateNotificationParams(const QVariantMap ¶ms, const QString ¬ification, const QVariantMap &api) +{ + QVariantMap paramDefinition = api.value("notifications").toMap().value(notification).toMap().value("params").toMap(); + m_result = validateMap(params, paramDefinition, api, QIODevice::ReadOnly); + m_result.setWhere(notification + ", param " + m_result.where()); + return m_result; +} + +JsonValidator::Result JsonValidator::result() const +{ + return m_result; +} + +JsonValidator::Result JsonValidator::validateMap(const QVariantMap &map, const QVariantMap &definition, const QVariantMap &api, QIODevice::OpenMode openMode) +{ + // Make sure all required values are available + foreach (const QString &key, definition.keys()) { + QRegExp isOptional = QRegExp("^([a-z]:)*o:.*"); + if (isOptional.exactMatch(key)) { + continue; + } + QRegExp isReadOnly = QRegExp("^([a-z]:)*r:.*"); + if (isReadOnly.exactMatch(key) && openMode.testFlag(QIODevice::WriteOnly)) { + continue; + } + QString trimmedKey = key; + trimmedKey.remove(QRegExp("^(o:|r:)")); + if (!map.contains(trimmedKey)) { + return Result(false, "Missing required key: " + key, key); + } + } + + // Make sure given values are valid + foreach (const QString &key, map.keys()) { + // Is the key allowed in here? + QVariant expectedValue = definition.value(key); + foreach (const QString &definitionKey, definition.keys()) { + QRegExp regExp = QRegExp("(o:|r:)*" + key); + if (regExp.exactMatch(definitionKey)) { + expectedValue = definition.value(definitionKey); + } + } + if (!expectedValue.isValid()) { + expectedValue = definition.value("o:" + key); + } + if (!expectedValue.isValid()) { + expectedValue = definition.value("o:" + key); + } + if (!expectedValue.isValid()) { + return Result(false, "Invalid key: " + key); + } + + // Validate content + QVariant value = map.value(key); + + Result result = validateEntry(value, expectedValue, api, openMode); + if (!result.success()) { + result.setWhere(key + '.' + result.where()); + result.setErrorString(result.errorString()); + return result; + } + + } + + return Result(true); +} + +JsonValidator::Result JsonValidator::validateEntry(const QVariant &value, const QVariant &definition, const QVariantMap &api, QIODevice::OpenMode openMode) +{ + if (definition.type() == QVariant::String) { + QString expectedTypeName = definition.toString(); + + if (expectedTypeName.startsWith("$ref:")) { + QString refName = expectedTypeName; + refName.remove("$ref:"); + + // Refs might be enums + QVariantMap enums = api.value("enums").toMap(); + if (enums.contains(refName)) { + QVariant refDefinition = enums.value(refName); + + QVariantList enumList = refDefinition.toList(); + if (!enumList.contains(value.toString())) { + return Result(false, "Expected enum " + refName + " but got " + value.toJsonDocument().toJson()); + } + return Result(true); + } + // Or flags + QVariantMap flags = api.value("flags").toMap(); + if (flags.contains(refName)) { + QVariant refDefinition = flags.value(refName); + if (value.type() != QVariant::StringList) { + return Result(false, "Expected flags " + refName + " but got " + value.toString()); + } + QString flagEnum = refDefinition.toList().first().toString(); + foreach (const QVariant &flagsEntry, value.toList()) { + Result result = validateEntry(flagsEntry, flagEnum, api, openMode); + if (!result.success()) { + return result; + } + } + return Result(true); + } + + QVariantMap types = api.value("types").toMap(); + QVariant refDefinition = types.value(refName); + return validateEntry(value, refDefinition, api, openMode); + } + + JsonHandler::BasicType expectedBasicType = JsonHandler::enumNameToValue(expectedTypeName); + QVariant::Type expectedVariantType = JsonHandler::basicTypeToVariantType(expectedBasicType); + + // Verify basic compatiblity + if (expectedBasicType != JsonHandler::Variant && !value.canConvert(expectedVariantType)) { + return Result(false, "Invalid value. Expected: " + definition.toString() + ", Got: " + value.toString()); + } + + // Any string converts fine to Uuid, but the resulting uuid might be null + if (expectedBasicType == JsonHandler::Uuid && value.toUuid().isNull()) { + return Result(false, "Invalid Uuid: " + value.toString()); + } + // Make sure ints are valid + if (expectedBasicType == JsonHandler::Int) { + bool ok; + value.toLongLong(&ok); + if (!ok) { + return Result(false, "Invalid Int: " + value.toString()); + } + } + // UInts + if (expectedBasicType == JsonHandler::Uint) { + bool ok; + value.toULongLong(&ok); + if (!ok) { + return Result(false, "Invalid UInt: " + value.toString()); + } + } + // Double + if (expectedBasicType == JsonHandler::Double) { + bool ok; + value.toDouble(&ok); + if (!ok) { + return Result(false, "Invalid Double: " + value.toString()); + } + } + // Color + if (expectedBasicType == JsonHandler::Color) { + QColor color = value.value(); + if (!color.isValid()) { + return Result(false, "Invalid Color: " + value.toString()); + } + } + // Time + if (expectedBasicType == JsonHandler::Time) { + QTime time = QTime::fromString(value.toString(), "hh:mm"); + if (!time.isValid()) { + return Result(false, "Invalid Time: " + value.toString()); + } + } + + + return Result(true); + } + + if (definition.type() == QVariant::Map) { + if (value.type() != QVariant::Map) { + return Result(false, "Invalid value. Expected a map bug received: " + value.toString()); + } + return validateMap(value.toMap(), definition.toMap(), api, openMode); + } + + if (definition.type() == QVariant::List) { + QVariantList list = definition.toList(); + QVariant entryDefinition = list.first(); + if (value.type() != QVariant::List && value.type() != QVariant::StringList) { + return Result(false, "Expected list of " + entryDefinition.toString() + " but got value of type " + value.typeName() + "\n" + QJsonDocument::fromVariant(value).toJson()); + } + foreach (const QVariant &entry, value.toList()) { + Result result = validateEntry(entry, entryDefinition, api, openMode); + if (!result.success()) { + return result; + } + } + return Result(true); + } + Q_ASSERT_X(false, "JsonValildator", "Incomplete validation. Unexpected type in template"); + return Result(false); +} + +} diff --git a/libnymea-core/jsonrpc/jsonvalidator.h b/libnymea-core/jsonrpc/jsonvalidator.h new file mode 100644 index 00000000..e59f41b4 --- /dev/null +++ b/libnymea-core/jsonrpc/jsonvalidator.h @@ -0,0 +1,70 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2019 Michael Zanetti * + * * + * This file is part of nymea. * + * * + * nymea 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. * + * * + * nymea 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 nymea. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef JSONVALIDATOR_H +#define JSONVALIDATOR_H + +#include +#include +#include + +namespace nymeaserver { + +class JsonValidator +{ +public: + class Result { + public: + Result() {} + Result(bool success, const QString &errorString = QString(), const QString &where = QString()): m_success(success), m_errorString(errorString), m_where(where) {} + bool success() const { return m_success; } + void setSuccess(bool success) { m_success = success; } + QString errorString() const { return m_errorString; } + void setErrorString(const QString &errorString) { m_errorString = errorString; } + QString where() const { return m_where; } + void setWhere(const QString &where) { m_where = where; } + bool deprecated() { return m_deprecated; } + void setDeprecated(bool deprecated) { m_deprecated = deprecated; } + private: + bool m_success = false; + QString m_errorString; + QString m_where; + bool m_deprecated = false; + }; + + JsonValidator() {} + + static bool checkRefs(const QVariantMap &map, const QVariantMap &api); + + Result validateParams(const QVariantMap ¶ms, const QString &method, const QVariantMap &api); + Result validateReturns(const QVariantMap &returns, const QString &method, const QVariantMap &api); + Result validateNotificationParams(const QVariantMap ¶ms, const QString ¬ification, const QVariantMap &api); + + Result result() const; +private: + Result validateMap(const QVariantMap &map, const QVariantMap &definition, const QVariantMap &api, QIODevice::OpenMode openMode); + Result validateEntry(const QVariant &value, const QVariant &definition, const QVariantMap &api, QIODevice::OpenMode openMode); + + Result m_result; +}; + +} + +#endif // JSONVALIDATOR_H diff --git a/libnymea-core/jsonrpc/logginghandler.cpp b/libnymea-core/jsonrpc/logginghandler.cpp index abbeaadf..c5b047bf 100644 --- a/libnymea-core/jsonrpc/logginghandler.cpp +++ b/libnymea-core/jsonrpc/logginghandler.cpp @@ -45,6 +45,8 @@ #include "logginghandler.h" #include "logging/logengine.h" #include "logging/logfilter.h" +#include "logging/logentry.h" +#include "logging/logvaluetool.h" #include "loggingcategories.h" #include "nymeacore.h" @@ -54,12 +56,18 @@ namespace nymeaserver { LoggingHandler::LoggingHandler(QObject *parent) : JsonHandler(parent) { - QVariantMap params; - QVariantMap returns; + // Enums + registerEnum(); + registerEnum(); + registerEnum(); + registerEnum(); - QVariantMap timeFilter; - params.clear(); returns.clear(); - setDescription("GetLogEntries", "Get the LogEntries matching the given filter. " + // Objects + registerObject(); + + // Methods + QString description; QVariantMap params; QVariantMap returns; + description = "Get the LogEntries matching the given filter. " "The result set will contain entries matching all filter rules combined. " "If multiple options are given for a single filter type, the result set will " "contain entries matching any of those. The offset starts at the newest entry " @@ -73,38 +81,38 @@ LoggingHandler::LoggingHandler(QObject *parent) : "1) offset 0, maxCount 1000: Entries 0 to 9999\n" "2) offset 10000, maxCount 1000: Entries 10000 - 19999\n" "3) offset 20000, maxCount 1000: Entries 20000 - 29999\n" - "..."); - timeFilter.insert("o:startDate", JsonTypes::basicTypeToString(JsonTypes::Int)); - timeFilter.insert("o:endDate", JsonTypes::basicTypeToString(JsonTypes::Int)); + "..."; + QVariantMap timeFilter; + timeFilter.insert("o:startDate", enumValueName(Int)); + timeFilter.insert("o:endDate", enumValueName(Int)); params.insert("o:timeFilters", QVariantList() << timeFilter); - params.insert("o:loggingSources", QVariantList() << JsonTypes::loggingSourceRef()); - params.insert("o:loggingLevels", QVariantList() << JsonTypes::loggingLevelRef()); - params.insert("o:eventTypes", QVariantList() << JsonTypes::loggingEventTypeRef()); - params.insert("o:typeIds", QVariantList() << JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("o:deviceIds", QVariantList() << JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("o:values", QVariantList() << JsonTypes::basicTypeToString(JsonTypes::Variant)); - params.insert("o:limit", JsonTypes::basicTypeToString(JsonTypes::Int)); - params.insert("o:offset", JsonTypes::basicTypeToString(JsonTypes::Int)); - setParams("GetLogEntries", params); - returns.insert("loggingError", JsonTypes::loggingErrorRef()); - returns.insert("o:logEntries", QVariantList() << JsonTypes::logEntryRef()); - returns.insert("count", JsonTypes::basicTypeToString(JsonTypes::Int)); - returns.insert("offset", JsonTypes::basicTypeToString(JsonTypes::Int)); - setReturns("GetLogEntries", returns); + params.insert("o:loggingSources", QVariantList() << enumRef()); + params.insert("o:loggingLevels", QVariantList() << enumRef()); + params.insert("o:eventTypes", QVariantList() << enumRef()); + params.insert("o:typeIds", QVariantList() << enumValueName(Uuid)); + params.insert("o:deviceIds", QVariantList() << enumValueName(Uuid)); + params.insert("o:values", QVariantList() << enumValueName(Variant)); + params.insert("o:limit", enumValueName(Int)); + params.insert("o:offset", enumValueName(Int)); + returns.insert("loggingError", enumRef()); + returns.insert("o:logEntries", objectRef()); + returns.insert("count", enumValueName(Int)); + returns.insert("offset", enumValueName(Int)); + registerMethod("GetLogEntries", description, params, returns); // Notifications params.clear(); - setDescription("LogEntryAdded", "Emitted whenever an entry is appended to the logging system. "); - params.insert("logEntry", JsonTypes::logEntryRef()); - setParams("LogEntryAdded", params); + description = "Emitted whenever an entry is appended to the logging system. "; + params.insert("logEntry", objectRef()); + registerNotification("LogEntryAdded", description, params); params.clear(); - setDescription("LogDatabaseUpdated", "Emitted whenever the database was updated. " + description = "Emitted whenever the database was updated. " "The database will be updated when a log entry was deleted. A log " "entry will be deleted when the corresponding device or a rule will " "be removed, or when the oldest entry of the database was deleted to " - "keep to database in the size limits."); - setParams("LogDatabaseUpdated", params); + "keep to database in the size limits."; + registerNotification("LogDatabaseUpdated", description, params); connect(NymeaCore::instance()->logEngine(), &LogEngine::logEntryAdded, this, &LoggingHandler::logEntryAdded); connect(NymeaCore::instance()->logEngine(), &LogEngine::logDatabaseUpdated, this, &LoggingHandler::logDatabaseUpdated); @@ -119,7 +127,7 @@ QString LoggingHandler::name() const void LoggingHandler::logEntryAdded(const LogEntry &logEntry) { QVariantMap params; - params.insert("logEntry", JsonTypes::packLogEntry(logEntry)); + params.insert("logEntry", packLogEntry(logEntry)); emit LogEntryAdded(params); } @@ -130,18 +138,136 @@ void LoggingHandler::logDatabaseUpdated() JsonReply* LoggingHandler::GetLogEntries(const QVariantMap ¶ms) const { - LogFilter filter = JsonTypes::unpackLogFilter(params); + LogFilter filter = unpackLogFilter(params); QVariantList entries; foreach (const LogEntry &entry, NymeaCore::instance()->logEngine()->logEntries(filter)) { - entries.append(JsonTypes::packLogEntry(entry)); + entries.append(packLogEntry(entry)); } - QVariantMap returns = statusToReply(Logging::LoggingErrorNoError); - + QVariantMap returns; + returns.insert("loggingError", enumValueName(Logging::LoggingErrorNoError)); returns.insert("logEntries", entries); returns.insert("offset", filter.offset()); returns.insert("count", entries.count()); return createReply(returns); } +QVariantMap LoggingHandler::packLogEntry(const LogEntry &logEntry) +{ + QVariantMap logEntryMap; + logEntryMap.insert("timestamp", logEntry.timestamp().toMSecsSinceEpoch()); + logEntryMap.insert("loggingLevel", enumValueName(logEntry.level())); + logEntryMap.insert("source", enumValueName(logEntry.source())); + logEntryMap.insert("eventType", enumValueName(logEntry.eventType())); + + if (logEntry.eventType() == Logging::LoggingEventTypeActiveChange) + logEntryMap.insert("active", logEntry.active()); + + if (logEntry.eventType() == Logging::LoggingEventTypeEnabledChange) + logEntryMap.insert("active", logEntry.active()); + + if (logEntry.level() == Logging::LoggingLevelAlert) { + switch (logEntry.source()) { + case Logging::LoggingSourceRules: + logEntryMap.insert("errorCode", enumValueName(static_cast(logEntry.errorCode()))); + break; + case Logging::LoggingSourceActions: + case Logging::LoggingSourceEvents: + case Logging::LoggingSourceStates: + case Logging::LoggingSourceBrowserActions: + logEntryMap.insert("errorCode", enumValueName(static_cast(logEntry.errorCode()))); + break; + case Logging::LoggingSourceSystem: + // FIXME: Update this once we support error codes for the general system + // logEntryMap.insert("errorCode", ""); + break; + } + } + + switch (logEntry.source()) { + case Logging::LoggingSourceActions: + case Logging::LoggingSourceEvents: + case Logging::LoggingSourceStates: + case Logging::LoggingSourceBrowserActions: + if (!logEntry.typeId().isNull()) { + logEntryMap.insert("typeId", logEntry.typeId()); + } + logEntryMap.insert("deviceId", logEntry.deviceId()); + logEntryMap.insert("value", LogValueTool::convertVariantToString(logEntry.value())); + break; + case Logging::LoggingSourceSystem: + logEntryMap.insert("active", logEntry.active()); + break; + case Logging::LoggingSourceRules: + logEntryMap.insert("typeId", logEntry.typeId().toString()); + break; + } + + return logEntryMap; +} + +LogFilter LoggingHandler::unpackLogFilter(const QVariantMap &logFilterMap) +{ + LogFilter filter; + if (logFilterMap.contains("timeFilters")) { + QVariantList timeFilters = logFilterMap.value("timeFilters").toList(); + foreach (const QVariant &timeFilter, timeFilters) { + QVariantMap timeFilterMap = timeFilter.toMap(); + QDateTime startDate; QDateTime endDate; + if (timeFilterMap.contains("startDate")) + startDate = QDateTime::fromTime_t(timeFilterMap.value("startDate").toUInt()); + + if (timeFilterMap.contains("endDate")) + endDate = QDateTime::fromTime_t(timeFilterMap.value("endDate").toUInt()); + + filter.addTimeFilter(startDate, endDate); + } + } + + if (logFilterMap.contains("loggingSources")) { + QVariantList loggingSources = logFilterMap.value("loggingSources").toList(); + foreach (const QVariant &source, loggingSources) { + filter.addLoggingSource(enumNameToValue(source.toString())); + } + } + if (logFilterMap.contains("loggingLevels")) { + QVariantList loggingLevels = logFilterMap.value("loggingLevels").toList(); + foreach (const QVariant &level, loggingLevels) { + filter.addLoggingLevel(enumNameToValue(level.toString())); + } + } + if (logFilterMap.contains("eventTypes")) { + QVariantList eventTypes = logFilterMap.value("eventTypes").toList(); + foreach (const QVariant &eventType, eventTypes) { + filter.addLoggingEventType(enumNameToValue(eventType.toString())); + } + } + if (logFilterMap.contains("typeIds")) { + QVariantList typeIds = logFilterMap.value("typeIds").toList(); + foreach (const QVariant &typeId, typeIds) { + filter.addTypeId(typeId.toUuid()); + } + } + if (logFilterMap.contains("deviceIds")) { + QVariantList deviceIds = logFilterMap.value("deviceIds").toList(); + foreach (const QVariant &deviceId, deviceIds) { + filter.addDeviceId(DeviceId(deviceId.toString())); + } + } + if (logFilterMap.contains("values")) { + QVariantList values = logFilterMap.value("values").toList(); + foreach (const QVariant &value, values) { + filter.addValue(value.toString()); + } + } + if (logFilterMap.contains("limit")) { + filter.setLimit(logFilterMap.value("limit", -1).toInt()); + } + if (logFilterMap.contains("offset")) { + filter.setOffset(logFilterMap.value("offset").toInt()); + } + + return filter; +} + } diff --git a/libnymea-core/jsonrpc/logginghandler.h b/libnymea-core/jsonrpc/logginghandler.h index 595766d2..577ce90c 100644 --- a/libnymea-core/jsonrpc/logginghandler.h +++ b/libnymea-core/jsonrpc/logginghandler.h @@ -22,8 +22,9 @@ #ifndef LOGGINGHANDLER_H #define LOGGINGHANDLER_H -#include "jsonhandler.h" +#include "jsonrpc/jsonhandler.h" #include "logging/logentry.h" +#include "logging/logfilter.h" namespace nymeaserver { @@ -40,6 +41,11 @@ signals: void LogEntryAdded(const QVariantMap ¶ms); void LogDatabaseUpdated(const QVariantMap ¶ms); +private: + static QVariantMap packLogEntry(const LogEntry &logEntry); + + static LogFilter unpackLogFilter(const QVariantMap &logFilterMap); + private slots: void logEntryAdded(const LogEntry &entry); void logDatabaseUpdated(); diff --git a/libnymea-core/jsonrpc/networkmanagerhandler.cpp b/libnymea-core/jsonrpc/networkmanagerhandler.cpp index 47af5632..e38c82ee 100644 --- a/libnymea-core/jsonrpc/networkmanagerhandler.cpp +++ b/libnymea-core/jsonrpc/networkmanagerhandler.cpp @@ -68,7 +68,6 @@ #include "nymeacore.h" -#include "jsontypes.h" #include "loggingcategories.h" #include "networkmanagerhandler.h" #include "networkmanager/networkmanager.h" @@ -80,107 +79,115 @@ namespace nymeaserver { NetworkManagerHandler::NetworkManagerHandler(QObject *parent) : JsonHandler(parent) { - QVariantMap params; QVariantMap returns; + // Enums + registerEnum(); + registerEnum(); + registerEnum(); - params.clear(); returns.clear(); - setDescription("GetNetworkStatus", "Get the current network manager status."); - setParams("GetNetworkStatus", params); + // Objects + registerUncreatableObject(); + registerUncreatableObject(); + + QVariantMap wirelessNetworkDevice; + wirelessNetworkDevice.insert("interface", enumValueName(String)); + wirelessNetworkDevice.insert("macAddress", enumValueName(String)); + wirelessNetworkDevice.insert("state", enumRef()); + wirelessNetworkDevice.insert("bitRate", enumValueName(String)); + wirelessNetworkDevice.insert("o:currentAccessPoint", objectRef()); + registerObject("WirelessNetworkDevice", wirelessNetworkDevice); + + // Methods + QString description; QVariantMap params; QVariantMap returns; + description = "Get the current network manager status."; QVariantMap status; - status.insert("networkingEnabled", JsonTypes::basicTypeToString(QVariant::Bool)); - status.insert("wirelessNetworkingEnabled", JsonTypes::basicTypeToString(QVariant::Bool)); - status.insert("state", JsonTypes::networkManagerStateRef()); + status.insert("networkingEnabled", enumValueName(Bool)); + status.insert("wirelessNetworkingEnabled", enumValueName(Bool)); + status.insert("state", enumRef()); returns.insert("o:status", status); - returns.insert("networkManagerError", JsonTypes::networkManagerErrorRef()); - setReturns("GetNetworkStatus", returns); + returns.insert("networkManagerError", enumRef()); + registerMethod("GetNetworkStatus", description, params, returns); params.clear(); returns.clear(); - setDescription("EnableNetworking", "Enable or disable networking in the NetworkManager."); - params.insert("enable", JsonTypes::basicTypeToString(QVariant::Bool)); - setParams("EnableNetworking", params); - returns.insert("networkManagerError", JsonTypes::networkManagerErrorRef()); - setReturns("EnableNetworking", returns); + description = "Enable or disable networking in the NetworkManager."; + params.insert("enable", enumValueName(Bool)); + returns.insert("networkManagerError", enumRef()); + registerMethod("EnableNetworking", description, params, returns); params.clear(); returns.clear(); - setDescription("EnableWirelessNetworking", "Enable or disable wireless networking in the NetworkManager."); - params.insert("enable", JsonTypes::basicTypeToString(QVariant::Bool)); - setParams("EnableWirelessNetworking", params); - returns.insert("networkManagerError", JsonTypes::networkManagerErrorRef()); - setReturns("EnableWirelessNetworking", returns); + description = "Enable or disable wireless networking in the NetworkManager."; + params.insert("enable", enumValueName(Bool)); + returns.insert("networkManagerError", enumRef()); + registerMethod("EnableWirelessNetworking", description, params, returns); params.clear(); returns.clear(); - setDescription("GetWirelessAccessPoints", "Get the current list of wireless network access points for the given interface. The interface has to be a WirelessNetworkDevice."); - params.insert("interface", JsonTypes::basicTypeToString(QVariant::String)); - setParams("GetWirelessAccessPoints", params); - returns.insert("o:wirelessAccessPoints", QVariantList() << JsonTypes::wirelessAccessPointRef()); - returns.insert("networkManagerError", JsonTypes::networkManagerErrorRef()); - setReturns("GetWirelessAccessPoints", returns); + description = "Get the current list of wireless network access points for the given interface. The interface has to be a WirelessNetworkDevice."; + params.insert("interface", enumValueName(String)); + returns.insert("o:wirelessAccessPoints", QVariantList() << objectRef("WirelessAccessPoint")); + returns.insert("networkManagerError", enumRef()); + registerMethod("GetWirelessAccessPoints", description, params, returns); params.clear(); returns.clear(); - setDescription("DisconnectInterface", "Disconnect the given network interface. The interface will remain disconnected until the user connect it again."); - params.insert("interface", JsonTypes::basicTypeToString(QVariant::String)); - setParams("DisconnectInterface", params); - returns.insert("networkManagerError", JsonTypes::networkManagerErrorRef()); - setReturns("DisconnectInterface", returns); + description = "Disconnect the given network interface. The interface will remain disconnected until the user connect it again."; + params.insert("interface", enumValueName(String)); + returns.insert("networkManagerError", enumRef()); + registerMethod("DisconnectInterface", description, params, returns); params.clear(); returns.clear(); - setDescription("GetNetworkDevices", "Get the list of current network devices."); - setParams("GetNetworkDevices", params); - returns.insert("wiredNetworkDevices", QVariantList() << JsonTypes::wiredNetworkDeviceRef()); - returns.insert("wirelessNetworkDevices", QVariantList() << JsonTypes::wirelessNetworkDeviceRef()); - returns.insert("networkManagerError", JsonTypes::networkManagerErrorRef()); - setReturns("GetNetworkDevices", returns); + description = "Get the list of current network devices."; + returns.insert("wiredNetworkDevices", QVariantList() << objectRef("WiredNetworkDevice")); + returns.insert("wirelessNetworkDevices", QVariantList() << objectRef("WirelessNetworkDevice")); + returns.insert("networkManagerError", enumRef()); + registerMethod("GetNetworkDevices", description, params, returns); params.clear(); returns.clear(); - setDescription("ScanWifiNetworks", "Start a wifi scan for searching new networks."); - params.insert("interface", JsonTypes::basicTypeToString(QVariant::String)); - setParams("ScanWifiNetworks", params); - returns.insert("networkManagerError", JsonTypes::networkManagerErrorRef()); - setReturns("ScanWifiNetworks", returns); + description = "Start a wifi scan for searching new networks."; + params.insert("interface", enumValueName(String)); + returns.insert("networkManagerError", enumRef()); + registerMethod("ScanWifiNetworks", description, params, returns); params.clear(); returns.clear(); - setDescription("ConnectWifiNetwork", "Connect to the wifi network with the given ssid and password."); - params.insert("interface", JsonTypes::basicTypeToString(QVariant::String)); - params.insert("ssid", JsonTypes::basicTypeToString(QVariant::String)); - params.insert("o:password", JsonTypes::basicTypeToString(QVariant::String)); - setParams("ConnectWifiNetwork", params); - returns.insert("networkManagerError", JsonTypes::networkManagerErrorRef()); - setReturns("ConnectWifiNetwork", returns); + description = "Connect to the wifi network with the given ssid and password."; + params.insert("interface", enumValueName(String)); + params.insert("ssid", enumValueName(String)); + params.insert("o:password", enumValueName(String)); + returns.insert("networkManagerError", enumRef()); + registerMethod("ConnectWifiNetwork", description, params, returns); // Notifications params.clear(); returns.clear(); - setDescription("NetworkStatusChanged", "Emitted whenever a status of a NetworkManager changes."); + description = "Emitted whenever a status of a NetworkManager changes."; params.insert("status", status); - setParams("NetworkStatusChanged", params); + registerNotification("NetworkStatusChanged", description, params); params.clear(); returns.clear(); - setDescription("WirelessNetworkDeviceAdded", "Emitted whenever a new WirelessNetworkDevice was added."); - params.insert("wirelessNetworkDevice", JsonTypes::wirelessNetworkDeviceRef()); - setParams("WirelessNetworkDeviceAdded", params); + description = "Emitted whenever a new WirelessNetworkDevice was added."; + params.insert("wirelessNetworkDevice", objectRef("WirelessNetworkDevice")); + registerNotification("WirelessNetworkDeviceAdded", description, params); params.clear(); returns.clear(); - setDescription("WirelessNetworkDeviceRemoved", "Emitted whenever a WirelessNetworkDevice was removed."); - params.insert("interface", JsonTypes::basicTypeToString(QVariant::String)); - setParams("WirelessNetworkDeviceRemoved", params); + description = "Emitted whenever a WirelessNetworkDevice was removed."; + params.insert("interface", enumValueName(String)); + registerNotification("WirelessNetworkDeviceRemoved", description, params); params.clear(); returns.clear(); - setDescription("WirelessNetworkDeviceChanged", "Emitted whenever the given WirelessNetworkDevice has changed."); - params.insert("wirelessNetworkDevice", JsonTypes::wirelessNetworkDeviceRef()); - setParams("WirelessNetworkDeviceChanged", params); + description = "Emitted whenever the given WirelessNetworkDevice has changed."; + params.insert("wirelessNetworkDevice", objectRef("WirelessNetworkDevice")); + registerNotification("WirelessNetworkDeviceChanged", description, params); params.clear(); returns.clear(); - setDescription("WiredNetworkDeviceAdded", "Emitted whenever a new WiredNetworkDevice was added."); - params.insert("wiredNetworkDevice", JsonTypes::wiredNetworkDeviceRef()); - setParams("WiredNetworkDeviceAdded", params); + description = "Emitted whenever a new WiredNetworkDevice was added."; + params.insert("wiredNetworkDevice", objectRef("WiredNetworkDevice")); + registerNotification("WiredNetworkDeviceAdded", description, params); params.clear(); returns.clear(); - setDescription("WiredNetworkDeviceRemoved", "Emitted whenever a WiredNetworkDevice was removed."); - params.insert("interface", JsonTypes::basicTypeToString(QVariant::String)); - setParams("WiredNetworkDeviceRemoved", params); + description = "Emitted whenever a WiredNetworkDevice was removed."; + params.insert("interface", enumValueName(String)); + registerNotification("WiredNetworkDeviceRemoved", description, params); params.clear(); returns.clear(); - setDescription("WiredNetworkDeviceChanged", "Emitted whenever the given WiredNetworkDevice has changed."); - params.insert("wiredNetworkDevice", JsonTypes::wiredNetworkDeviceRef()); - setParams("WiredNetworkDeviceChanged", params); + description = "Emitted whenever the given WiredNetworkDevice has changed."; + params.insert("wiredNetworkDevice", objectRef("WiredNetworkDevice")); + registerNotification("WiredNetworkDeviceChanged", description, params); connect(NymeaCore::instance()->networkManager(), &NetworkManager::stateChanged, this, &NetworkManagerHandler::onNetworkManagerStatusChanged); connect(NymeaCore::instance()->networkManager(), &NetworkManager::networkingEnabledChanged, this, &NetworkManagerHandler::onNetworkManagerStatusChanged); @@ -203,16 +210,15 @@ QString NetworkManagerHandler::name() const JsonReply *NetworkManagerHandler::GetNetworkStatus(const QVariantMap ¶ms) { - Q_UNUSED(params); + Q_UNUSED(params) // Check available if (!NymeaCore::instance()->networkManager()->available()) return createReply(statusToReply(NetworkManager::NetworkManagerErrorNetworkManagerNotAvailable)); // Pack network manager status - QVariantMap returns; + QVariantMap returns = statusToReply(NetworkManager::NetworkManagerErrorNoError); returns.insert("status", packNetworkManagerStatus()); - returns.insert("networkManagerError", JsonTypes::networkManagerErrorToString(NetworkManager::NetworkManagerErrorNoError)); return createReply(returns); } @@ -266,11 +272,10 @@ JsonReply *NetworkManagerHandler::GetWirelessAccessPoints(const QVariantMap &par if (networkDevice->interface() == interface) { QVariantList wirelessAccessPoints; foreach (WirelessAccessPoint *wirelessAccessPoint, networkDevice->accessPoints()) - wirelessAccessPoints.append(JsonTypes::packWirelessAccessPoint(wirelessAccessPoint)); + wirelessAccessPoints.append(packWirelessAccessPoint(wirelessAccessPoint)); - QVariantMap returns; + QVariantMap returns = statusToReply(NetworkManager::NetworkManagerErrorNoError); returns.insert("wirelessAccessPoints", wirelessAccessPoints); - returns.insert("networkManagerError", JsonTypes::networkManagerErrorToString(NetworkManager::NetworkManagerErrorNoError)); return createReply(returns); } @@ -288,22 +293,21 @@ JsonReply *NetworkManagerHandler::GetNetworkDevices(const QVariantMap ¶ms) QVariantList wirelessNetworkDevices; foreach (WirelessNetworkDevice *networkDevice, NymeaCore::instance()->networkManager()->wirelessNetworkDevices()) - wirelessNetworkDevices.append(JsonTypes::packWirelessNetworkDevice(networkDevice)); + wirelessNetworkDevices.append(packWirelessNetworkDevice(networkDevice)); QVariantList wiredNetworkDevices; foreach (WiredNetworkDevice *networkDevice, NymeaCore::instance()->networkManager()->wiredNetworkDevices()) - wiredNetworkDevices.append(JsonTypes::packWiredNetworkDevice(networkDevice)); + wiredNetworkDevices.append(packWiredNetworkDevice(networkDevice)); - QVariantMap returns; + QVariantMap returns = statusToReply(NetworkManager::NetworkManagerErrorNoError); returns.insert("wirelessNetworkDevices", wirelessNetworkDevices); returns.insert("wiredNetworkDevices", wiredNetworkDevices); - returns.insert("networkManagerError", JsonTypes::networkManagerErrorToString(NetworkManager::NetworkManagerErrorNoError)); return createReply(returns); } JsonReply *NetworkManagerHandler::ScanWifiNetworks(const QVariantMap ¶ms) { - Q_UNUSED(params); + Q_UNUSED(params) if (!NymeaCore::instance()->networkManager()->available()) return createReply(statusToReply(NetworkManager::NetworkManagerErrorNetworkManagerNotAvailable)); @@ -388,7 +392,7 @@ void NetworkManagerHandler::onNetworkManagerStatusChanged() void NetworkManagerHandler::onWirelessNetworkDeviceAdded(WirelessNetworkDevice *networkDevice) { QVariantMap notification; - notification.insert("wirelessNetworkDevice", JsonTypes::packWirelessNetworkDevice(networkDevice)); + notification.insert("wirelessNetworkDevice", packWirelessNetworkDevice(networkDevice)); emit WirelessNetworkDeviceAdded(notification); } @@ -402,14 +406,14 @@ void NetworkManagerHandler::onWirelessNetworkDeviceRemoved(const QString &interf void NetworkManagerHandler::onWirelessNetworkDeviceChanged(WirelessNetworkDevice *networkDevice) { QVariantMap notification; - notification.insert("wirelessNetworkDevice", JsonTypes::packWirelessNetworkDevice(networkDevice)); + notification.insert("wirelessNetworkDevice", packWirelessNetworkDevice(networkDevice)); emit WirelessNetworkDeviceChanged(notification); } void NetworkManagerHandler::onWiredNetworkDeviceAdded(WiredNetworkDevice *networkDevice) { QVariantMap notification; - notification.insert("wiredNetworkDevice", JsonTypes::packWiredNetworkDevice(networkDevice)); + notification.insert("wiredNetworkDevice", packWiredNetworkDevice(networkDevice)); emit WiredNetworkDeviceAdded(notification); } @@ -423,8 +427,50 @@ void NetworkManagerHandler::onWiredNetworkDeviceRemoved(const QString &interface void NetworkManagerHandler::onWiredNetworkDeviceChanged(WiredNetworkDevice *networkDevice) { QVariantMap notification; - notification.insert("wiredNetworkDevice", JsonTypes::packWiredNetworkDevice(networkDevice)); + notification.insert("wiredNetworkDevice", packWiredNetworkDevice(networkDevice)); emit WiredNetworkDeviceChanged(notification); } +QVariantMap NetworkManagerHandler::packWirelessAccessPoint(WirelessAccessPoint *wirelessAccessPoint) +{ + QVariantMap wirelessAccessPointVariant; + wirelessAccessPointVariant.insert("ssid", wirelessAccessPoint->ssid()); + wirelessAccessPointVariant.insert("macAddress", wirelessAccessPoint->macAddress()); + wirelessAccessPointVariant.insert("frequency", wirelessAccessPoint->frequency()); + wirelessAccessPointVariant.insert("signalStrength", wirelessAccessPoint->signalStrength()); + wirelessAccessPointVariant.insert("protected", wirelessAccessPoint->isProtected()); + return wirelessAccessPointVariant; +} + +QVariantMap NetworkManagerHandler::packWiredNetworkDevice(WiredNetworkDevice *networkDevice) +{ + QVariantMap networkDeviceVariant; + networkDeviceVariant.insert("interface", networkDevice->interface()); + networkDeviceVariant.insert("macAddress", networkDevice->macAddress()); + networkDeviceVariant.insert("state", networkDevice->deviceStateString()); + networkDeviceVariant.insert("bitRate", QString("%1 [Mb/s]").arg(QString::number(networkDevice->bitRate()))); + networkDeviceVariant.insert("pluggedIn", networkDevice->pluggedIn()); + return networkDeviceVariant; +} + +QVariantMap NetworkManagerHandler::packWirelessNetworkDevice(WirelessNetworkDevice *networkDevice) +{ + QVariantMap networkDeviceVariant; + networkDeviceVariant.insert("interface", networkDevice->interface()); + networkDeviceVariant.insert("macAddress", networkDevice->macAddress()); + networkDeviceVariant.insert("state", networkDevice->deviceStateString()); + networkDeviceVariant.insert("bitRate", QString("%1 [Mb/s]").arg(QString::number(networkDevice->bitRate()))); + if (networkDevice->activeAccessPoint()) + networkDeviceVariant.insert("currentAccessPoint", packWirelessAccessPoint(networkDevice->activeAccessPoint())); + + return networkDeviceVariant; +} + +QVariantMap NetworkManagerHandler::statusToReply(NetworkManager::NetworkManagerError status) const +{ + QVariantMap returns; + returns.insert("networkManagerError", enumValueName(status)); + return returns; +} + } diff --git a/libnymea-core/jsonrpc/networkmanagerhandler.h b/libnymea-core/jsonrpc/networkmanagerhandler.h index b8834173..d9d15b75 100644 --- a/libnymea-core/jsonrpc/networkmanagerhandler.h +++ b/libnymea-core/jsonrpc/networkmanagerhandler.h @@ -23,7 +23,8 @@ #include -#include "jsonhandler.h" +#include "jsonrpc/jsonhandler.h" +#include "networkmanager/networkmanager.h" namespace nymeaserver { @@ -73,6 +74,13 @@ private slots: void onWiredNetworkDeviceRemoved(const QString &interface); void onWiredNetworkDeviceChanged(WiredNetworkDevice *networkDevice); +private: + QVariantMap packWirelessAccessPoint(WirelessAccessPoint *wirelessAccessPoint); + QVariantMap packWiredNetworkDevice(WiredNetworkDevice *networkDevice); + QVariantMap packWirelessNetworkDevice(WirelessNetworkDevice *networkDevice); + + QVariantMap statusToReply(NetworkManager::NetworkManagerError status) const; + }; } diff --git a/libnymea-core/jsonrpc/ruleshandler.cpp b/libnymea-core/jsonrpc/ruleshandler.cpp index c1bf8d00..2141f198 100644 --- a/libnymea-core/jsonrpc/ruleshandler.cpp +++ b/libnymea-core/jsonrpc/ruleshandler.cpp @@ -58,6 +58,7 @@ #include "loggingcategories.h" #include +#include namespace nymeaserver { @@ -65,26 +66,49 @@ namespace nymeaserver { RulesHandler::RulesHandler(QObject *parent) : JsonHandler(parent) { - QVariantMap params; - QVariantMap returns; + // Enums + registerEnum(); + registerEnum(); + registerEnum(); + registerEnum(); + + // Objects + QVariantMap ruleDescription; + ruleDescription.insert("id", enumValueName(Uuid)); + ruleDescription.insert("name", enumValueName(String)); + ruleDescription.insert("enabled", enumValueName(Bool)); + ruleDescription.insert("active", enumValueName(Bool)); + ruleDescription.insert("executable", enumValueName(Bool)); + registerObject("RuleDescription", ruleDescription); + + registerObject(); + registerObject(); + registerObject(); + registerObject(); + registerObject(); + registerObject(); + registerObject(); + registerObject(); + registerObject(); + registerObject(); + registerObject(); + + // Methods + QString description; QVariantMap params; QVariantMap returns; + description = "Get the descriptions of all configured rules. If you need more information about a specific rule use the " + "method Rules.GetRuleDetails."; + returns.insert("ruleDescriptions", QVariantList() << objectRef("RuleDescription")); + registerMethod("GetRules", description, params, returns); params.clear(); returns.clear(); - setDescription("GetRules", "Get the descriptions of all configured rules. If you need more information about a specific rule use the " - "method Rules.GetRuleDetails."); - setParams("GetRules", params); - returns.insert("ruleDescriptions", QVariantList() << JsonTypes::ruleDescriptionRef()); - setReturns("GetRules", returns); + description = "Get details for the rule identified by ruleId"; + params.insert("ruleId", enumValueName(Uuid)); + returns.insert("o:rule", objectRef("Rule")); + returns.insert("ruleError", enumRef()); + registerMethod("GetRuleDetails", description, params, returns); params.clear(); returns.clear(); - setDescription("GetRuleDetails", "Get details for the rule identified by ruleId"); - params.insert("ruleId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setParams("GetRuleDetails", params); - returns.insert("o:rule", JsonTypes::ruleRef()); - returns.insert("ruleError", JsonTypes::ruleErrorRef()); - setReturns("GetRuleDetails", returns); - - params.clear(); returns.clear(); - setDescription("AddRule", "Add a rule. You can describe rules by one or many EventDesciptors and a StateEvaluator. " + description = "Add a rule. You can describe rules by one or many EventDesciptors and a StateEvaluator. " "Note that only one of either eventDescriptor or eventDescriptorList may be passed at a time. " "A rule can be created but left disabled, meaning it won't actually be executed until set to enabled. " "If not given, enabled defaults to true. A rule can have a list of actions and exitActions. " @@ -94,104 +118,96 @@ RulesHandler::RulesHandler(QObject *parent) : "happens and if the stateEvaluator matches the system's state. ExitActions for such rules will be " "executed when a matching event happens and the stateEvaluator is not matching the system's state. " "A rule marked as executable can be executed via the API using Rules.ExecuteRule, that means, its " - "actions will be executed regardless of the eventDescriptor and stateEvaluators."); - params.insert("name", JsonTypes::basicTypeToString(JsonTypes::String)); - params.insert("actions", QVariantList() << JsonTypes::ruleActionRef()); - params.insert("o:timeDescriptor", JsonTypes::timeDescriptorRef()); - params.insert("o:stateEvaluator", JsonTypes::stateEvaluatorRef()); - params.insert("o:eventDescriptors", QVariantList() << JsonTypes::eventDescriptorRef()); - params.insert("o:exitActions", QVariantList() << JsonTypes::ruleActionRef()); - params.insert("o:enabled", JsonTypes::basicTypeToString(JsonTypes::Bool)); - params.insert("o:executable", JsonTypes::basicTypeToString(JsonTypes::Bool)); - setParams("AddRule", params); - returns.insert("ruleError", JsonTypes::ruleErrorRef()); - returns.insert("o:ruleId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setReturns("AddRule", returns); + "actions will be executed regardless of the eventDescriptor and stateEvaluators."; + params.insert("name", enumValueName(String)); + params.insert("actions", QVariantList() << objectRef("RuleAction")); + params.insert("o:timeDescriptor", objectRef("TimeDescriptor")); + params.insert("o:stateEvaluator", objectRef("StateEvaluator")); + params.insert("o:eventDescriptors", QVariantList() << objectRef("EventDescriptor")); + params.insert("o:exitActions", QVariantList() << objectRef("RuleAction")); + params.insert("o:enabled", enumValueName(Bool)); + params.insert("o:executable", enumValueName(Bool)); + returns.insert("ruleError", enumRef()); + returns.insert("o:ruleId", enumValueName(Uuid)); + registerMethod("AddRule", description, params, returns); params.clear(); returns.clear(); - setDescription("EditRule", "Edit the parameters of a rule. The configuration of the rule with the given ruleId " + description = "Edit the parameters of a rule. The configuration of the rule with the given ruleId " "will be replaced with the new given configuration. In ordert to enable or disable a Rule, please use the " "methods \"Rules.EnableRule\" and \"Rules.DisableRule\". If successful, the notification \"Rule.RuleConfigurationChanged\" " - "will be emitted."); - params.insert("ruleId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("name", JsonTypes::basicTypeToString(JsonTypes::String)); - params.insert("actions", QVariantList() << JsonTypes::ruleActionRef()); - params.insert("o:timeDescriptor", JsonTypes::timeDescriptorRef()); - params.insert("o:stateEvaluator", JsonTypes::stateEvaluatorRef()); - params.insert("o:eventDescriptors", QVariantList() << JsonTypes::eventDescriptorRef()); - params.insert("o:exitActions", QVariantList() << JsonTypes::ruleActionRef()); - params.insert("o:enabled", JsonTypes::basicTypeToString(JsonTypes::Bool)); - params.insert("o:executable", JsonTypes::basicTypeToString(JsonTypes::Bool)); - setParams("EditRule", params); - returns.insert("ruleError", JsonTypes::ruleErrorRef()); - returns.insert("o:rule", JsonTypes::ruleRef()); - setReturns("EditRule", returns); + "will be emitted."; + params.insert("ruleId", enumValueName(Uuid)); + params.insert("name", enumValueName(String)); + params.insert("actions", QVariantList() << objectRef("RuleAction")); + params.insert("o:timeDescriptor", objectRef("TimeDescriptor")); + params.insert("o:stateEvaluator", objectRef("StateEvaluator")); + params.insert("o:eventDescriptors", QVariantList() << objectRef("EventDescriptor")); + params.insert("o:exitActions", QVariantList() << objectRef("RuleAction")); + params.insert("o:enabled", enumValueName(Bool)); + params.insert("o:executable", enumValueName(Bool)); + returns.insert("ruleError", enumRef()); + returns.insert("o:rule", objectRef("Rule")); + registerMethod("EditRule", description, params, returns); params.clear(); returns.clear(); - setDescription("RemoveRule", "Remove a rule"); - params.insert("ruleId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setParams("RemoveRule", params); - returns.insert("ruleError", JsonTypes::ruleErrorRef()); - setReturns("RemoveRule", returns); + description = "Remove a rule"; + params.insert("ruleId", enumValueName(Uuid)); + returns.insert("ruleError", enumRef()); + registerMethod("RemoveRule", description, params, returns); params.clear(); returns.clear(); - setDescription("FindRules", "Find a list of rules containing any of the given parameters."); - params.insert("deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setParams("FindRules", params); - returns.insert("ruleIds", QVariantList() << JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setReturns("FindRules", returns); + description = "Find a list of rules containing any of the given parameters."; + params.insert("deviceId", enumValueName(Uuid)); + returns.insert("ruleIds", QVariantList() << enumValueName(Uuid)); + registerMethod("FindRules", description, params, returns); params.clear(); returns.clear(); - setDescription("EnableRule", "Enabled a rule that has previously been disabled." - "If successful, the notification \"Rule.RuleConfigurationChanged\" will be emitted."); - params.insert("ruleId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setParams("EnableRule", params); - returns.insert("ruleError", JsonTypes::ruleErrorRef()); - setReturns("EnableRule", returns); + description = "Enabled a rule that has previously been disabled." + "If successful, the notification \"Rule.RuleConfigurationChanged\" will be emitted."; + params.insert("ruleId", enumValueName(Uuid)); + returns.insert("ruleError", enumRef()); + registerMethod("EnableRule", description, params, returns); params.clear(); returns.clear(); - setDescription("DisableRule", "Disable a rule. The rule won't be triggered by it's events or state changes while it is disabled. " - "If successful, the notification \"Rule.RuleConfigurationChanged\" will be emitted."); - params.insert("ruleId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setParams("DisableRule", params); - returns.insert("ruleError", JsonTypes::ruleErrorRef()); - setReturns("DisableRule", returns); + description = "Disable a rule. The rule won't be triggered by it's events or state changes while it is disabled. " + "If successful, the notification \"Rule.RuleConfigurationChanged\" will be emitted."; + params.insert("ruleId", enumValueName(Uuid)); + returns.insert("ruleError", enumRef()); + registerMethod("DisableRule", description, params, returns); params.clear(); returns.clear(); - setDescription("ExecuteActions", "Execute the action list of the rule with the given ruleId."); - params.insert("ruleId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setParams("ExecuteActions", params); - returns.insert("ruleError", JsonTypes::ruleErrorRef()); - setReturns("ExecuteActions", returns); + description = "Execute the action list of the rule with the given ruleId."; + params.insert("ruleId", enumValueName(Uuid)); + returns.insert("ruleError", enumRef()); + registerMethod("ExecuteActions", description, params, returns); params.clear(); returns.clear(); - setDescription("ExecuteExitActions", "Execute the exit action list of the rule with the given ruleId."); - params.insert("ruleId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setParams("ExecuteExitActions", params); - returns.insert("ruleError", JsonTypes::ruleErrorRef()); - setReturns("ExecuteExitActions", returns); + description = "Execute the exit action list of the rule with the given ruleId."; + params.insert("ruleId", enumValueName(Uuid)); + returns.insert("ruleError", enumRef()); + registerMethod("ExecuteExitActions", description, params, returns); // Notifications params.clear(); returns.clear(); - setDescription("RuleRemoved", "Emitted whenever a Rule was removed."); - params.insert("ruleId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setParams("RuleRemoved", params); + description = "Emitted whenever a Rule was removed."; + params.insert("ruleId", enumValueName(Uuid)); + registerNotification("RuleRemoved", description, params); params.clear(); returns.clear(); - setDescription("RuleAdded", "Emitted whenever a Rule was added."); - params.insert("rule", JsonTypes::ruleRef()); - setParams("RuleAdded", params); + description = "Emitted whenever a Rule was added."; + params.insert("rule", objectRef("Rule")); + registerNotification("RuleAdded", description, params); params.clear(); returns.clear(); - setDescription("RuleActiveChanged", "Emitted whenever the active state of a Rule changed."); - params.insert("ruleId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("active", JsonTypes::basicTypeToString(JsonTypes::Bool)); - setParams("RuleActiveChanged", params); + description = "Emitted whenever the active state of a Rule changed."; + params.insert("ruleId", enumValueName(Uuid)); + params.insert("active", enumValueName(Bool)); + registerNotification("RuleActiveChanged", description, params); params.clear(); returns.clear(); - setDescription("RuleConfigurationChanged", "Emitted whenever the configuration of a Rule changed."); - params.insert("rule", JsonTypes::ruleRef()); - setParams("RuleConfigurationChanged", params); + description = "Emitted whenever the configuration of a Rule changed."; + params.insert("rule", objectRef("Rule")); + registerNotification("RuleConfigurationChanged", description, params); connect(NymeaCore::instance(), &NymeaCore::ruleAdded, this, &RulesHandler::ruleAddedNotification); connect(NymeaCore::instance(), &NymeaCore::ruleRemoved, this, &RulesHandler::ruleRemovedNotification); @@ -209,9 +225,13 @@ JsonReply* RulesHandler::GetRules(const QVariantMap ¶ms) { Q_UNUSED(params) - QVariantMap returns; - returns.insert("ruleDescriptions", JsonTypes::packRuleDescriptions()); + QVariantList rulesList; + foreach (const Rule &rule, NymeaCore::instance()->ruleEngine()->rules()) { + rulesList.append(packRuleDescription(rule)); + } + QVariantMap returns; + returns.insert("ruleDescriptions", rulesList); return createReply(returns); } @@ -220,16 +240,19 @@ JsonReply *RulesHandler::GetRuleDetails(const QVariantMap ¶ms) RuleId ruleId = RuleId(params.value("ruleId").toString()); Rule rule = NymeaCore::instance()->ruleEngine()->findRule(ruleId); if (rule.id().isNull()) { - return createReply(statusToReply(RuleEngine::RuleErrorRuleNotFound)); + QVariantMap data; + data.insert("ruleError", enumValueName(RuleEngine::RuleErrorRuleNotFound)); + return createReply(data); } - QVariantMap returns = statusToReply(RuleEngine::RuleErrorNoError); - returns.insert("rule", JsonTypes::packRule(rule)); + QVariantMap returns; + returns.insert("ruleError", enumValueName(RuleEngine::RuleErrorNoError)); + returns.insert("rule", pack(rule)); return createReply(returns); } JsonReply* RulesHandler::AddRule(const QVariantMap ¶ms) { - Rule rule = JsonTypes::unpackRule(params); + Rule rule = unpack(params); rule.setId(RuleId::createRuleId()); RuleEngine::RuleError status = NymeaCore::instance()->ruleEngine()->addRule(rule); @@ -237,19 +260,23 @@ JsonReply* RulesHandler::AddRule(const QVariantMap ¶ms) if (status == RuleEngine::RuleErrorNoError) { returns.insert("ruleId", rule.id().toString()); } - returns.insert("ruleError", JsonTypes::ruleErrorToString(status)); + returns.insert("ruleError", enumValueName(status)); return createReply(returns); } JsonReply *RulesHandler::EditRule(const QVariantMap ¶ms) { - Rule rule = JsonTypes::unpackRule(params); + Rule rule = unpack(params); + + // FIXME: Edit rule API currently has "ruleId" while the Rule type has "id". Auto unpacking will fail for this property + rule.setId(params.value("ruleId").toUuid()); + RuleEngine::RuleError status = NymeaCore::instance()->ruleEngine()->editRule(rule); QVariantMap returns; if (status == RuleEngine::RuleErrorNoError) { - returns.insert("rule", JsonTypes::packRule(NymeaCore::instance()->ruleEngine()->findRule(rule.id()))); + returns.insert("rule", pack(NymeaCore::instance()->ruleEngine()->findRule(rule.id()))); } - returns.insert("ruleError", JsonTypes::ruleErrorToString(status)); + returns.insert("ruleError", enumValueName(status)); return createReply(returns); } @@ -258,7 +285,7 @@ JsonReply* RulesHandler::RemoveRule(const QVariantMap ¶ms) QVariantMap returns; RuleId ruleId(params.value("ruleId").toString()); RuleEngine::RuleError status = NymeaCore::instance()->removeRule(ruleId); - returns.insert("ruleError", JsonTypes::ruleErrorToString(status)); + returns.insert("ruleError", enumValueName(status)); return createReply(returns); } @@ -279,12 +306,18 @@ JsonReply *RulesHandler::FindRules(const QVariantMap ¶ms) JsonReply *RulesHandler::EnableRule(const QVariantMap ¶ms) { - return createReply(statusToReply(NymeaCore::instance()->ruleEngine()->enableRule(RuleId(params.value("ruleId").toString())))); + RuleEngine::RuleError status = NymeaCore::instance()->ruleEngine()->enableRule(RuleId(params.value("ruleId").toString())); + QVariantMap ret; + ret.insert("ruleError", enumValueName(status)); + return createReply(ret); } JsonReply *RulesHandler::DisableRule(const QVariantMap ¶ms) { - return createReply(statusToReply(NymeaCore::instance()->ruleEngine()->disableRule(RuleId(params.value("ruleId").toString())))); + RuleEngine::RuleError status = NymeaCore::instance()->ruleEngine()->disableRule(RuleId(params.value("ruleId").toString())); + QVariantMap ret; + ret.insert("ruleError", enumValueName(status)); + return createReply(ret); } JsonReply *RulesHandler::ExecuteActions(const QVariantMap ¶ms) @@ -292,7 +325,7 @@ JsonReply *RulesHandler::ExecuteActions(const QVariantMap ¶ms) QVariantMap returns; RuleId ruleId(params.value("ruleId").toString()); RuleEngine::RuleError status = NymeaCore::instance()->ruleEngine()->executeActions(ruleId); - returns.insert("ruleError", JsonTypes::ruleErrorToString(status)); + returns.insert("ruleError", enumValueName(status)); return createReply(returns); } @@ -301,7 +334,7 @@ JsonReply *RulesHandler::ExecuteExitActions(const QVariantMap ¶ms) QVariantMap returns; RuleId ruleId(params.value("ruleId").toString()); RuleEngine::RuleError status = NymeaCore::instance()->ruleEngine()->executeExitActions(ruleId); - returns.insert("ruleError", JsonTypes::ruleErrorToString(status)); + returns.insert("ruleError", enumValueName(status)); return createReply(returns); } @@ -316,7 +349,7 @@ void RulesHandler::ruleRemovedNotification(const RuleId &ruleId) void RulesHandler::ruleAddedNotification(const Rule &rule) { QVariantMap params; - params.insert("rule", JsonTypes::packRule(rule)); + params.insert("rule", pack(rule)); emit RuleAdded(params); } @@ -333,9 +366,20 @@ void RulesHandler::ruleActiveChangedNotification(const Rule &rule) void RulesHandler::ruleConfigurationChangedNotification(const Rule &rule) { QVariantMap params; - params.insert("rule", JsonTypes::packRule(rule)); + params.insert("rule", pack(rule)); emit RuleConfigurationChanged(params); } +QVariantMap RulesHandler::packRuleDescription(const Rule &rule) +{ + QVariantMap ruleDescriptionMap; + ruleDescriptionMap.insert("id", rule.id().toString()); + ruleDescriptionMap.insert("name", rule.name()); + ruleDescriptionMap.insert("enabled", rule.enabled()); + ruleDescriptionMap.insert("active", rule.active()); + ruleDescriptionMap.insert("executable", rule.executable()); + return ruleDescriptionMap; +} + } diff --git a/libnymea-core/jsonrpc/ruleshandler.h b/libnymea-core/jsonrpc/ruleshandler.h index 0a8d504d..57e42edf 100644 --- a/libnymea-core/jsonrpc/ruleshandler.h +++ b/libnymea-core/jsonrpc/ruleshandler.h @@ -22,7 +22,9 @@ #ifndef RULESHANDLER_H #define RULESHANDLER_H -#include "jsonhandler.h" +#include "jsonrpc/jsonhandler.h" + +#include "ruleengine/rule.h" namespace nymeaserver { @@ -30,7 +32,7 @@ class RulesHandler : public JsonHandler { Q_OBJECT public: - explicit RulesHandler(QObject *parent = 0); + explicit RulesHandler(QObject *parent = nullptr); QString name() const override; @@ -60,6 +62,8 @@ private slots: void ruleActiveChangedNotification(const Rule &rule); void ruleConfigurationChangedNotification(const Rule &rule); +private: + QVariantMap packRuleDescription(const Rule &rule); }; } diff --git a/libnymea-core/jsonrpc/statehandler.cpp b/libnymea-core/jsonrpc/statehandler.cpp index a25e2b52..65281a44 100644 --- a/libnymea-core/jsonrpc/statehandler.cpp +++ b/libnymea-core/jsonrpc/statehandler.cpp @@ -42,16 +42,17 @@ namespace nymeaserver { StateHandler::StateHandler(QObject *parent) : JsonHandler(parent) { - QVariantMap params; - QVariantMap returns; + registerEnum(); + registerObject(); + registerObject(); - params.clear(); returns.clear(); - setDescription("GetStateType", "Get the StateType for the given stateTypeId."); - params.insert("stateTypeId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - setParams("GetStateType", params); - returns.insert("deviceError", JsonTypes::deviceErrorRef()); - returns.insert("o:stateType", JsonTypes::stateTypeRef()); - setReturns("GetStateType", returns); + // Methods + QString description; QVariantMap params; QVariantMap returns; + description = "Get the StateType for the given stateTypeId."; + params.insert("stateTypeId", enumValueName(Uuid)); + returns.insert("deviceError", enumRef()); + returns.insert("o:stateType", objectRef()); + registerMethod("GetStateType", description, params, returns, "Please use the Devices namespace instead."); } /*! Returns the name of the \l{StateHandler}. In this case \b States.*/ @@ -62,18 +63,24 @@ QString StateHandler::name() const JsonReply* StateHandler::GetStateType(const QVariantMap ¶ms) const { + QLocale locale = params.value("locale").toLocale(); qCDebug(dcJsonRpc) << "asked for state type" << params; StateTypeId stateTypeId(params.value("stateTypeId").toString()); foreach (const DeviceClass &deviceClass, NymeaCore::instance()->deviceManager()->supportedDevices()) { foreach (const StateType &stateType, deviceClass.stateTypes()) { if (stateType.id() == stateTypeId) { - QVariantMap data = statusToReply(Device::DeviceErrorNoError); - data.insert("stateType", JsonTypes::packStateType(stateType, deviceClass.pluginId(), params.value("locale").toLocale())); + QVariantMap data; + data.insert("deviceError", enumValueName(Device::DeviceErrorNoError)); + StateType translatedStateType = stateType; + translatedStateType.setDisplayName(NymeaCore::instance()->deviceManager()->translate(deviceClass.pluginId(), stateType.displayName(), locale)); + data.insert("stateType", pack(translatedStateType)); return createReply(data); } } } - return createReply(statusToReply(Device::DeviceErrorStateTypeNotFound)); + QVariantMap data; + data.insert("deviceError", enumValueName(Device::DeviceErrorStateTypeNotFound)); + return createReply(data); } } diff --git a/libnymea-core/jsonrpc/statehandler.h b/libnymea-core/jsonrpc/statehandler.h index 7b4589e1..4ad977ec 100644 --- a/libnymea-core/jsonrpc/statehandler.h +++ b/libnymea-core/jsonrpc/statehandler.h @@ -22,7 +22,7 @@ #ifndef STATEHANDLER_H #define STATEHANDLER_H -#include "jsonhandler.h" +#include "jsonrpc/jsonhandler.h" namespace nymeaserver { @@ -30,7 +30,7 @@ class StateHandler : public JsonHandler { Q_OBJECT public: - explicit StateHandler(QObject *parent = 0); + explicit StateHandler(QObject *parent = nullptr); QString name() const override; Q_INVOKABLE JsonReply *GetStateType(const QVariantMap ¶ms) const; diff --git a/libnymea-core/jsonrpc/systemhandler.cpp b/libnymea-core/jsonrpc/systemhandler.cpp index 3b16c84a..c433f97b 100644 --- a/libnymea-core/jsonrpc/systemhandler.cpp +++ b/libnymea-core/jsonrpc/systemhandler.cpp @@ -32,146 +32,133 @@ SystemHandler::SystemHandler(Platform *platform, QObject *parent): JsonHandler(parent), m_platform(platform) { + // Objects + registerObject(); + registerObject(); + // Methods - QVariantMap params; QVariantMap returns; - setDescription("GetCapabilities", "Get the list of capabilites on this system. This allows reading whether things like rebooting or shutting down the system running nymea:core is supported on this host."); - setParams("GetCapabilities", params); - returns.insert("powerManagement", JsonTypes::basicTypeToString(JsonTypes::Bool)); - returns.insert("updateManagement", JsonTypes::basicTypeToString(JsonTypes::Bool)); - setReturns("GetCapabilities", returns); + QString description; QVariantMap params; QVariantMap returns; + description = "Get the list of capabilites on this system. This allows reading whether things like rebooting or shutting down the system running nymea:core is supported on this host."; + returns.insert("powerManagement", enumValueName(Bool)); + returns.insert("updateManagement", enumValueName(Bool)); + registerMethod("GetCapabilities", description, params, returns); params.clear(); returns.clear(); - setDescription("Reboot", "Initiate a reboot of the system. The return value will indicate whether the procedure has been initiated successfully."); - setParams("Reboot", params); - returns.insert("success", JsonTypes::basicTypeToString(JsonTypes::Bool)); - setReturns("Reboot", returns); + description = "Initiate a reboot of the system. The return value will indicate whether the procedure has been initiated successfully."; + returns.insert("success", enumValueName(Bool)); + registerMethod("Reboot", description, params, returns); params.clear(); returns.clear(); - setDescription("Shutdown", "Initiate a shutdown of the system. The return value will indicate whether the procedure has been initiated successfully."); - setParams("Shutdown", params); - returns.insert("success", JsonTypes::basicTypeToString(JsonTypes::Bool)); - setReturns("Shutdown", returns); + description = "Initiate a shutdown of the system. The return value will indicate whether the procedure has been initiated successfully."; + returns.insert("success", enumValueName(Bool)); + registerMethod("Shutdown", description, params, returns); params.clear(); returns.clear(); - setDescription("GetUpdateStatus", - "Get the current status of the update system. \"busy\" indicates that the system is current busy with " + description = "Get the current status of the update system. \"busy\" indicates that the system is current busy with " "an operation regarding updates. This does not necessarily mean an actual update is running. When this " "is true, update related functions on the client should be marked as busy and no interaction with update " "components shall be allowed. An example for such a state is when the system queries the server if there " "are updates available, typically after a call to CheckForUpdates. \"updateRunning\" on the other hand " "indicates an actual update process is ongoing. The user should be informed about it, the system also " - "might restart at any point while an update is running."); - setParams("GetUpdateStatus", params); - returns.insert("busy", JsonTypes::basicTypeToString(JsonTypes::Bool)); - returns.insert("updateRunning", JsonTypes::basicTypeToString(JsonTypes::Bool)); - setReturns("GetUpdateStatus", returns); + "might restart at any point while an update is running."; + returns.insert("busy", enumValueName(Bool)); + returns.insert("updateRunning", enumValueName(Bool)); + registerMethod("GetUpdateStatus", description, params, returns); params.clear(); returns.clear(); - setDescription("CheckForUpdates", - "Instruct the system to poll the server for updates. Normally the system should automatically do this " + description = "Instruct the system to poll the server for updates. Normally the system should automatically do this " "in regular intervals, however, if the client wants to allow the user to manually check for new updates " "now, this can be called. Returns true if the operation has been started successfully and the update " "manager will become busy. In order to know whether there are updates available, clients should walk through " "the list of packages retrieved from GetPackages and check whether there are packages with the updateAvailable " - "flag set to true."); - setParams("CheckForUpdates", params); - returns.insert("success", JsonTypes::basicTypeToString(JsonTypes::Bool)); - setReturns("CheckForUpdates", returns); + "flag set to true."; + returns.insert("success", enumValueName(Bool)); + registerMethod("CheckForUpdates", description, params, returns); params.clear(); returns.clear(); - setDescription("GetPackages", - "Get the list of packages currently available to the system. This might include installed available but " - "not installed packages. Installed packages will have the installedVersion set to a non-empty value."); - setParams("GetPackages", params); - returns.insert("packages", QVariantList() << JsonTypes::packageRef()); - setReturns("GetPackages", returns); + description = "Get the list of packages currently available to the system. This might include installed available but " + "not installed packages. Installed packages will have the installedVersion set to a non-empty value."; + returns.insert("packages", objectRef("Packages")); + registerMethod("GetPackages", description, params, returns); params.clear(); returns.clear(); - setDescription("UpdatePackages", - "Starts updating/installing packages with the given ids. Returns true if the upgrade has been started " + description = "Starts updating/installing packages with the given ids. Returns true if the upgrade has been started " "successfully. Note that it might still fail later. Before calling this method, clients should " "check the packages whether they are in a state where they can either be installed (no installedVersion " - "set) or upgraded (updateAvailable set to true)."); - params.insert("o:packageIds", QVariantList() << JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("UpdatePackages", params); - returns.insert("success", JsonTypes::basicTypeToString(JsonTypes::Bool)); - setReturns("UpdatePackages", returns); + "set) or upgraded (updateAvailable set to true)."; + params.insert("o:packageIds", QVariantList() << enumValueName(String)); + returns.insert("success", enumValueName(Bool)); + registerMethod("UpdatePackages", description, params, returns); params.clear(); returns.clear(); - setDescription("RollbackPackages", - "Starts a rollback. Returns true if the rollback has been started successfully. Before calling this " - "method, clients should check whether the package can be rolled back (canRollback set to true)."); - params.insert("packageIds", QVariantList() << JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("RollbackPackages", params); - returns.insert("success", JsonTypes::basicTypeToString(JsonTypes::Bool)); - setReturns("RollbackPackages", returns); + description = "Starts a rollback. Returns true if the rollback has been started successfully. Before calling this " + "method, clients should check whether the package can be rolled back (canRollback set to true)."; + params.insert("packageIds", QVariantList() << enumValueName(String)); + returns.insert("success", enumValueName(Bool)); + registerMethod("RollbackPackages", description, params, returns); params.clear(); returns.clear(); - setDescription("RemovePackages", - "Starts removing a package. Returns true if the removal has been started successfully. Before calling " - "this method, clients should check whether the package can be removed (canRemove set to true)."); - params.insert("packageIds", QVariantList() << JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("RemovePackages", params); - returns.insert("success", JsonTypes::basicTypeToString(JsonTypes::Bool)); - setReturns("RemovePackages", returns); + description = "Starts removing a package. Returns true if the removal has been started successfully. Before calling " + "this method, clients should check whether the package can be removed (canRemove set to true)."; + params.insert("packageIds", QVariantList() << enumValueName(String)); + returns.insert("success", enumValueName(Bool)); + registerMethod("RemovePackages", description, params, returns); params.clear(); returns.clear(); - setDescription("GetRepositories", "Get the list of repositories currently available to the system."); - setParams("GetRepositories", params); - returns.insert("repositories", QVariantList() << JsonTypes::repositoryRef()); - setReturns("GetRepositories", returns); + description = "Get the list of repositories currently available to the system."; + returns.insert("repositories",objectRef("Repositories")); + registerMethod("GetRepositories", description, params, returns); params.clear(); returns.clear(); - setDescription("EnableRepository", "Enable or disable a repository."); - params.insert("repositoryId", JsonTypes::basicTypeToString(JsonTypes::String)); - params.insert("enabled", JsonTypes::basicTypeToString(JsonTypes::Bool)); - setParams("EnableRepository", params); - returns.insert("success", JsonTypes::basicTypeToString(JsonTypes::Bool)); - setReturns("EnableRepository", returns); + description = "Enable or disable a repository."; + params.insert("repositoryId", enumValueName(String)); + params.insert("enabled", enumValueName(Bool)); + returns.insert("success", enumValueName(Bool)); + registerMethod("EnableRepository", description, params, returns); // Notifications params.clear(); - setDescription("CapabilitiesChanged", "Emitted whenever the system capabilities change."); - params.insert("powerManagement", JsonTypes::basicTypeToString(JsonTypes::Bool)); - params.insert("updateManagement", JsonTypes::basicTypeToString(JsonTypes::Bool)); - setParams("CapabilitiesChanged", params); + description = "Emitted whenever the system capabilities change."; + params.insert("powerManagement", enumValueName(Bool)); + params.insert("updateManagement", enumValueName(Bool)); + registerNotification("CapabilitiesChanged", description, params); params.clear(); - setDescription("UpdateStatusChanged", "Emitted whenever the update status changes."); - params.insert("busy", JsonTypes::basicTypeToString(JsonTypes::Bool)); - params.insert("updateRunning", JsonTypes::basicTypeToString(JsonTypes::Bool)); - setParams("UpdateStatusChanged", params); + description = "Emitted whenever the update status changes."; + params.insert("busy", enumValueName(Bool)); + params.insert("updateRunning", enumValueName(Bool)); + registerNotification("UpdateStatusChanged", description, params); params.clear(); - setDescription("PackageAdded", "Emitted whenever a package is added to the list of packages."); - params.insert("package", JsonTypes::packageRef()); - setParams("PackageAdded", params); + description = "Emitted whenever a package is added to the list of packages."; + params.insert("package", objectRef("Package")); + registerNotification("PackageAdded", description, params); params.clear(); - setDescription("PackageChanged", "Emitted whenever a package in the list of packages changes."); - params.insert("package", JsonTypes::packageRef()); - setParams("PackageChanged", params); + description = "Emitted whenever a package in the list of packages changes."; + params.insert("package", objectRef("Package")); + registerNotification("PackageChanged", description, params); params.clear(); - setDescription("PackageRemoved", "Emitted whenever a package is removed from the list of packages."); - params.insert("packageId", JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("PackageRemoved", params); + description = "Emitted whenever a package is removed from the list of packages."; + params.insert("packageId", enumValueName(String)); + registerNotification("PackageRemoved", description, params); params.clear(); - setDescription("RepositoryAdded", "Emitted whenever a repository is added to the list of repositories."); - params.insert("repository", JsonTypes::repositoryRef()); - setParams("RepositoryAdded", params); + description = "Emitted whenever a repository is added to the list of repositories."; + params.insert("repository", objectRef("Repository")); + registerNotification("RepositoryAdded", description, params); params.clear(); - setDescription("RepositoryChanged", "Emitted whenever a repository in the list of repositories changes."); - params.insert("repository", JsonTypes::repositoryRef()); - setParams("RepositoryChanged", params); + description = "Emitted whenever a repository in the list of repositories changes."; + params.insert("repository", objectRef("Repository")); + registerNotification("RepositoryChanged", description, params); params.clear(); - setDescription("RepositoryRemoved", "Emitted whenever a repository is removed from the list of repositories."); - params.insert("repositoryId", JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("RepositoryRemoved", params); + description = "Emitted whenever a repository is removed from the list of repositories."; + params.insert("repositoryId", enumValueName(String)); + registerNotification("RepositoryRemoved", description, params); connect(m_platform->systemController(), &PlatformSystemController::availableChanged, this, &SystemHandler::onCapabilitiesChanged); @@ -190,12 +177,12 @@ SystemHandler::SystemHandler(Platform *platform, QObject *parent): }); connect(m_platform->updateController(), &PlatformUpdateController::packageAdded, this, [this](const Package &package){ QVariantMap params; - params.insert("package", JsonTypes::packPackage(package)); + params.insert("package", pack(package)); emit PackageAdded(params); }); connect(m_platform->updateController(), &PlatformUpdateController::packageChanged, this, [this](const Package &package){ QVariantMap params; - params.insert("package", JsonTypes::packPackage(package)); + params.insert("package", pack(package)); emit PackageChanged(params); }); connect(m_platform->updateController(), &PlatformUpdateController::packageRemoved, this, [this](const QString &packageId){ @@ -205,12 +192,12 @@ SystemHandler::SystemHandler(Platform *platform, QObject *parent): }); connect(m_platform->updateController(), &PlatformUpdateController::repositoryAdded, this, [this](const Repository &repository){ QVariantMap params; - params.insert("repository", JsonTypes::packRepository(repository)); + params.insert("repository", pack(repository)); emit RepositoryAdded(params); }); connect(m_platform->updateController(), &PlatformUpdateController::repositoryChanged, this, [this](const Repository &repository){ QVariantMap params; - params.insert("repository", JsonTypes::packRepository(repository)); + params.insert("repository", pack(repository)); emit RepositoryChanged(params); }); connect(m_platform->updateController(), &PlatformUpdateController::repositoryRemoved, this, [this](const QString &repositoryId){ @@ -236,7 +223,7 @@ JsonReply *SystemHandler::GetCapabilities(const QVariantMap ¶ms) JsonReply *SystemHandler::Reboot(const QVariantMap ¶ms) const { - Q_UNUSED(params); + Q_UNUSED(params) bool status = m_platform->systemController()->reboot(); QVariantMap returns; returns.insert("success", status); @@ -245,7 +232,7 @@ JsonReply *SystemHandler::Reboot(const QVariantMap ¶ms) const JsonReply *SystemHandler::Shutdown(const QVariantMap ¶ms) const { - Q_UNUSED(params); + Q_UNUSED(params) bool status = m_platform->systemController()->shutdown(); QVariantMap returns; returns.insert("success", status); @@ -275,7 +262,7 @@ JsonReply *SystemHandler::GetPackages(const QVariantMap ¶ms) const Q_UNUSED(params) QVariantList packagelist; foreach (const Package &package, m_platform->updateController()->packages()) { - packagelist.append(JsonTypes::packPackage(package)); + packagelist.append(pack(package)); } QVariantMap returns; returns.insert("packages", packagelist); @@ -308,10 +295,10 @@ JsonReply *SystemHandler::RemovePackages(const QVariantMap ¶ms) const JsonReply *SystemHandler::GetRepositories(const QVariantMap ¶ms) const { - Q_UNUSED(params); + Q_UNUSED(params) QVariantList repos; foreach (const Repository &repository, m_platform->updateController()->repositories()) { - repos.append(JsonTypes::packRepository(repository)); + repos.append(pack(repository)); } QVariantMap returns; returns.insert("repositories", repos); diff --git a/libnymea-core/jsonrpc/systemhandler.h b/libnymea-core/jsonrpc/systemhandler.h index 36dc09df..4c43a4e8 100644 --- a/libnymea-core/jsonrpc/systemhandler.h +++ b/libnymea-core/jsonrpc/systemhandler.h @@ -23,9 +23,11 @@ #include -#include "jsonhandler.h" +#include "jsonrpc/jsonhandler.h" #include "platform/platform.h" +#include "platform/package.h" +#include "platform/repository.h" namespace nymeaserver { diff --git a/libnymea-core/jsonrpc/tagshandler.cpp b/libnymea-core/jsonrpc/tagshandler.cpp index 601b296b..e9b842f8 100644 --- a/libnymea-core/jsonrpc/tagshandler.cpp +++ b/libnymea-core/jsonrpc/tagshandler.cpp @@ -27,51 +27,52 @@ namespace nymeaserver { TagsHandler::TagsHandler(QObject *parent) : JsonHandler(parent) { - QVariantMap params; - QVariantMap returns; + // Enums + registerEnum(); + + // Objects + registerObject(); + + // Methods + QString description; QVariantMap params; QVariantMap returns; + description = "Get the Tags matching the given filter. Tags can be filtered by a deviceID, a ruleId, an appId, a tagId or a combination of any (however, combining deviceId and ruleId will return an empty result set)."; + params.insert("o:deviceId", enumValueName(Uuid)); + params.insert("o:ruleId", enumValueName(Uuid)); + params.insert("o:appId", enumValueName(String)); + params.insert("o:tagId", enumValueName(String)); + returns.insert("tagError", enumRef()); + returns.insert("o:tags", objectRef("Tags")); + registerMethod("GetTags", description, params, returns); params.clear(); returns.clear(); - setDescription("GetTags", "Get the Tags matching the given filter. Tags can be filtered by a deviceID, a ruleId, an appId, a tagId or a combination of any (however, combining deviceId and ruleId will return an empty result set)."); - params.insert("o:deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("o:ruleId", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("o:appId", JsonTypes::basicTypeToString(JsonTypes::String)); - params.insert("o:tagId", JsonTypes::basicTypeToString(JsonTypes::String)); - setParams("GetTags", params); - returns.insert("tagError", JsonTypes::tagErrorRef()); - returns.insert("o:tags", QVariantList() << JsonTypes::tagRef()); - setReturns("GetTags", returns); + description = "Add a Tag. A Tag must have a deviceId OR a ruleId (call this method twice if you want to attach the same tag to a device and a rule), an appId (Use the appId of your app), a tagId (e.g. \"favorites\") and a value. Upon success, a TagAdded notification will be emitted. Calling this method twice for the same ids (device/rule, appId and tagId) but with a different value will update the tag's value and the TagValueChanged notification will be emitted."; + params.insert("tag", objectRef("Tag")); + returns.insert("tagError", enumRef()); + registerMethod("AddTag", description, params, returns); params.clear(); returns.clear(); - setDescription("AddTag", "Add a Tag. A Tag must have a deviceId OR a ruleId (call this method twice if you want to attach the same tag to a device and a rule), an appId (Use the appId of your app), a tagId (e.g. \"favorites\") and a value. Upon success, a TagAdded notification will be emitted. Calling this method twice for the same ids (device/rule, appId and tagId) but with a different value will update the tag's value and the TagValueChanged notification will be emitted."); - params.insert("tag", JsonTypes::tagRef()); - setParams("AddTag", params); - returns.insert("tagError", JsonTypes::tagErrorRef()); - setReturns("AddTag", returns); - - params.clear(); returns.clear(); - setDescription("RemoveTag", "Remove a Tag. Tag value is optional and will be disregarded. If the ids match, the tag will be deleted and a TagRemoved notification will be emitted."); - params.insert("tag", JsonTypes::tagRef()); - setParams("RemoveTag", params); - returns.insert("tagError", JsonTypes::tagErrorRef()); - setReturns("RemoveTag", returns); + description = "Remove a Tag. Tag value is optional and will be disregarded. If the ids match, the tag will be deleted and a TagRemoved notification will be emitted."; + params.insert("tag", objectRef("Tag")); + returns.insert("tagError", enumRef()); + registerMethod("RemoveTag", description, params, returns); // Notifications params.clear(); - setDescription("TagAdded", "Emitted whenever a tag is added to the system. "); - params.insert("tag", JsonTypes::tagRef()); - setParams("TagAdded", params); + description = "Emitted whenever a tag is added to the system. "; + params.insert("tag", objectRef("Tag")); + registerNotification("TagAdded", description, params); connect(NymeaCore::instance()->tagsStorage(), &TagsStorage::tagAdded, this, &TagsHandler::onTagAdded); params.clear(); - setDescription("TagRemoved", "Emitted whenever a tag is removed from the system. "); - params.insert("tag", JsonTypes::tagRef()); - setParams("TagRemoved", params); + description = "Emitted whenever a tag is removed from the system. "; + params.insert("tag", objectRef("Tag")); + registerNotification("TagRemoved", description, params); connect(NymeaCore::instance()->tagsStorage(), &TagsStorage::tagRemoved, this, &TagsHandler::onTagRemoved); params.clear(); - setDescription("TagValueChanged", "Emitted whenever a tag's value is changed in the system. "); - params.insert("tag", JsonTypes::tagRef()); - setParams("TagValueChanged", params); + description = "Emitted whenever a tag's value is changed in the system. "; + params.insert("tag", objectRef("Tag")); + registerNotification("TagValueChanged", description, params); connect(NymeaCore::instance()->tagsStorage(), &TagsStorage::tagValueChanged, this, &TagsHandler::onTagValueChanged); } @@ -96,7 +97,7 @@ JsonReply *TagsHandler::GetTags(const QVariantMap ¶ms) const if (params.contains("tagId") && params.value("tagId").toString() != tag.tagId()) { continue; } - ret.append(JsonTypes::packTag(tag)); + ret.append(pack(tag)); } QVariantMap returns = statusToReply(TagsStorage::TagErrorNoError); returns.insert("tags", ret); @@ -106,7 +107,7 @@ JsonReply *TagsHandler::GetTags(const QVariantMap ¶ms) const JsonReply *TagsHandler::AddTag(const QVariantMap ¶ms) const { - Tag tag = JsonTypes::unpackTag(params.value("tag").toMap()); + Tag tag = unpack(params.value("tag").toMap()); TagsStorage::TagError error = NymeaCore::instance()->tagsStorage()->addTag(tag); QVariantMap returns = statusToReply(error); return createReply(returns); @@ -114,7 +115,7 @@ JsonReply *TagsHandler::AddTag(const QVariantMap ¶ms) const JsonReply *TagsHandler::RemoveTag(const QVariantMap ¶ms) const { - Tag tag = JsonTypes::unpackTag(params.value("tag").toMap()); + Tag tag = unpack(params.value("tag").toMap()); TagsStorage::TagError error = NymeaCore::instance()->tagsStorage()->removeTag(tag); QVariantMap returns = statusToReply(error); return createReply(returns); @@ -124,7 +125,7 @@ void TagsHandler::onTagAdded(const Tag &tag) { qCDebug(dcJsonRpc) << "Notify \"Tags.TagAdded\""; QVariantMap params; - params.insert("tag", JsonTypes::packTag(tag)); + params.insert("tag", pack(tag)); emit TagAdded(params); } @@ -132,7 +133,7 @@ void TagsHandler::onTagRemoved(const Tag &tag) { qCDebug(dcJsonRpc) << "Notify \"Tags.TagRemoved\""; QVariantMap params; - params.insert("tag", JsonTypes::packTag(tag)); + params.insert("tag", pack(tag)); emit TagRemoved(params); } @@ -140,8 +141,15 @@ void TagsHandler::onTagValueChanged(const Tag &tag) { qCDebug(dcJsonRpc) << "Notify \"Tags.TagValueChanged\""; QVariantMap params; - params.insert("tag", JsonTypes::packTag(tag)); + params.insert("tag", pack(tag)); emit TagValueChanged(params); } +QVariantMap TagsHandler::statusToReply(TagsStorage::TagError status) const +{ + QVariantMap returns; + returns.insert("tagError", enumValueName(status)); + return returns; +} + } diff --git a/libnymea-core/jsonrpc/tagshandler.h b/libnymea-core/jsonrpc/tagshandler.h index 6bbc7124..8d3c907c 100644 --- a/libnymea-core/jsonrpc/tagshandler.h +++ b/libnymea-core/jsonrpc/tagshandler.h @@ -23,7 +23,8 @@ #include -#include "jsonhandler.h" +#include "jsonrpc/jsonhandler.h" +#include "tagging/tagsstorage.h" namespace nymeaserver { @@ -47,6 +48,10 @@ private slots: void onTagAdded(const Tag &tag); void onTagRemoved(const Tag &tag); void onTagValueChanged(const Tag &tag); + +private: + QVariantMap statusToReply(TagsStorage::TagError status) const; + }; } diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index 43dd82b9..5e5fbf32 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -18,6 +18,8 @@ RESOURCES += $$top_srcdir/icons.qrc \ HEADERS += nymeacore.h \ devices/devicemanagerimplementation.h \ devices/translator.h \ + experiences/experiencemanager.h \ + jsonrpc/jsonrpcserverimplementation.h \ ruleengine/ruleengine.h \ ruleengine/rule.h \ ruleengine/stateevaluator.h \ @@ -34,10 +36,8 @@ HEADERS += nymeacore.h \ servers/bluetoothserver.h \ servers/websocketserver.h \ servers/mqttbroker.h \ - jsonrpc/jsonrpcserver.h \ - jsonrpc/jsonhandler.h \ + jsonrpc/jsonvalidator.h \ jsonrpc/devicehandler.h \ - jsonrpc/jsontypes.h \ jsonrpc/ruleshandler.h \ jsonrpc/actionhandler.h \ jsonrpc/eventhandler.h \ @@ -50,10 +50,6 @@ HEADERS += nymeacore.h \ logging/logfilter.h \ logging/logentry.h \ logging/logvaluetool.h \ - time/timedescriptor.h \ - time/calendaritem.h \ - time/repeatingoption.h \ - time/timeeventitem.h \ time/timemanager.h \ networkmanager/dbus-interfaces.h \ networkmanager/networkmanager.h \ @@ -96,6 +92,8 @@ HEADERS += nymeacore.h \ SOURCES += nymeacore.cpp \ devices/devicemanagerimplementation.cpp \ devices/translator.cpp \ + experiences/experiencemanager.cpp \ + jsonrpc/jsonrpcserverimplementation.cpp \ ruleengine/ruleengine.cpp \ ruleengine/rule.cpp \ ruleengine/stateevaluator.cpp \ @@ -112,10 +110,8 @@ SOURCES += nymeacore.cpp \ servers/websocketserver.cpp \ servers/bluetoothserver.cpp \ servers/mqttbroker.cpp \ - jsonrpc/jsonrpcserver.cpp \ - jsonrpc/jsonhandler.cpp \ + jsonrpc/jsonvalidator.cpp \ jsonrpc/devicehandler.cpp \ - jsonrpc/jsontypes.cpp \ jsonrpc/ruleshandler.cpp \ jsonrpc/actionhandler.cpp \ jsonrpc/eventhandler.cpp \ @@ -127,10 +123,6 @@ SOURCES += nymeacore.cpp \ logging/logfilter.cpp \ logging/logentry.cpp \ logging/logvaluetool.cpp \ - time/timedescriptor.cpp \ - time/calendaritem.cpp \ - time/repeatingoption.cpp \ - time/timeeventitem.cpp \ time/timemanager.cpp \ networkmanager/networkmanager.cpp \ networkmanager/networkdevice.cpp \ diff --git a/libnymea-core/logging/logentry.cpp b/libnymea-core/logging/logentry.cpp index 1ebe8cca..159ee7bc 100644 --- a/libnymea-core/logging/logentry.cpp +++ b/libnymea-core/logging/logentry.cpp @@ -38,12 +38,17 @@ #include "logentry.h" #include "nymeacore.h" -#include "jsonrpc/jsontypes.h" #include +#include namespace nymeaserver { +LogEntry::LogEntry() +{ + +} + /*! Constructs a \l{LogEntry} with the given \a timestamp, \a level, \a source and \a errorCode.*/ LogEntry::LogEntry(QDateTime timestamp, Logging::LoggingLevel level, Logging::LoggingSource source, int errorCode): m_timestamp(timestamp), @@ -156,17 +161,41 @@ int LogEntry::errorCode() const QDebug operator<<(QDebug dbg, const LogEntry &entry) { + QMetaEnum metaEnum; dbg.nospace() << "LogEntry (" << entry.timestamp().toString() << ")" << endl; dbg.nospace() << " time stamp: " << entry.timestamp().toTime_t() << endl; dbg.nospace() << " DeviceId: " << entry.deviceId().toString() << endl; dbg.nospace() << " type id: " << entry.typeId().toString() << endl; - dbg.nospace() << " source: " << JsonTypes::loggingSourceToString(entry.source()) << endl; - dbg.nospace() << " level: " << JsonTypes::loggingLevelToString(entry.level()) << endl; - dbg.nospace() << " eventType: " << JsonTypes::loggingEventTypeToString(entry.eventType()) << endl; + metaEnum = QMetaEnum::fromType(); + dbg.nospace() << " source: " << metaEnum.valueToKey(entry.source()) << endl; + metaEnum = QMetaEnum::fromType(); + dbg.nospace() << " level: " << metaEnum.valueToKey(entry.level()) << endl; + metaEnum = QMetaEnum::fromType(); + dbg.nospace() << " eventType: " << metaEnum.valueToKey(entry.eventType()) << endl; dbg.nospace() << " error code: " << entry.errorCode() << endl; dbg.nospace() << " active: " << entry.active() << endl; dbg.nospace() << " value: " << entry.value() << endl; return dbg.space(); } +LogEntries::LogEntries() +{ + +} + +LogEntries::LogEntries(const QList &other): QList(other) +{ + +} + +QVariant LogEntries::get(int index) const +{ + return QVariant::fromValue(at(index)); +} + +void LogEntries::put(const QVariant &variant) +{ + append(variant.value()); +} + } diff --git a/libnymea-core/logging/logentry.h b/libnymea-core/logging/logentry.h index 5cd8fb84..706175c1 100644 --- a/libnymea-core/logging/logentry.h +++ b/libnymea-core/logging/logentry.h @@ -34,8 +34,18 @@ namespace nymeaserver { class LogEntry { Q_GADGET + Q_PROPERTY(QDateTime timestamp READ timestamp) + Q_PROPERTY(Logging::LoggingLevel loggingLevel READ level) + Q_PROPERTY(Logging::LoggingSource source READ source) + Q_PROPERTY(QUuid typeId READ typeId USER true) + Q_PROPERTY(QUuid deviceId READ deviceId USER true) + Q_PROPERTY(QVariant value READ value USER true) + Q_PROPERTY(bool active READ active USER true) + Q_PROPERTY(Logging::LoggingEventType eventType READ eventType USER true) + Q_PROPERTY(QString errorCode READ errorCode USER true) public: + LogEntry(); LogEntry(QDateTime timestamp, Logging::LoggingLevel level, Logging::LoggingSource source, int errorCode = 0); LogEntry(Logging::LoggingLevel level, Logging::LoggingSource source, int errorCode = 0); LogEntry(Logging::LoggingSource source); @@ -82,8 +92,21 @@ private: int m_errorCode; }; +class LogEntries: QList +{ + Q_GADGET + Q_PROPERTY(int count READ count) +public: + LogEntries(); + LogEntries(const QList &other); + Q_INVOKABLE QVariant get(int index) const; + Q_INVOKABLE void put(const QVariant &variant); +}; + QDebug operator<<(QDebug dbg, const LogEntry &entry); } +Q_DECLARE_METATYPE(nymeaserver::LogEntry) +Q_DECLARE_METATYPE(nymeaserver::LogEntries) #endif diff --git a/libnymea-core/networkmanager/networkdevice.cpp b/libnymea-core/networkmanager/networkdevice.cpp index c875cbcc..c31272e5 100644 --- a/libnymea-core/networkmanager/networkdevice.cpp +++ b/libnymea-core/networkmanager/networkdevice.cpp @@ -334,7 +334,7 @@ QString NetworkDevice::deviceStateReasonToString(const NetworkDevice::NetworkDev void NetworkDevice::onStateChanged(uint newState, uint oldState, uint reason) { - Q_UNUSED(oldState); + Q_UNUSED(oldState) qCDebug(dcNetworkManager()) << m_interface << "--> State changed:" << deviceStateToString(NetworkDeviceState(newState)) << ":" << deviceStateReasonToString(NetworkDeviceStateReason(reason)); if (m_deviceState != NetworkDeviceState(newState)) { m_deviceState = NetworkDeviceState(newState); diff --git a/libnymea-core/networkmanager/wirednetworkdevice.h b/libnymea-core/networkmanager/wirednetworkdevice.h index a3d12510..e605cc68 100644 --- a/libnymea-core/networkmanager/wirednetworkdevice.h +++ b/libnymea-core/networkmanager/wirednetworkdevice.h @@ -31,8 +31,14 @@ namespace nymeaserver { class WiredNetworkDevice : public NetworkDevice { Q_OBJECT + Q_PROPERTY(QString interface READ interface) + Q_PROPERTY(QString macAddress READ macAddress) + Q_PROPERTY(NetworkDeviceState state READ deviceState) + Q_PROPERTY(QString bitRate READ bitRate) + Q_PROPERTY(bool pluggedIn READ pluggedIn) + public: - explicit WiredNetworkDevice(const QDBusObjectPath &objectPath, QObject *parent = 0); + explicit WiredNetworkDevice(const QDBusObjectPath &objectPath, QObject *parent = nullptr); QString macAddress() const; int bitRate() const; diff --git a/libnymea-core/networkmanager/wirelessaccesspoint.h b/libnymea-core/networkmanager/wirelessaccesspoint.h index 6900658e..6c8375c9 100644 --- a/libnymea-core/networkmanager/wirelessaccesspoint.h +++ b/libnymea-core/networkmanager/wirelessaccesspoint.h @@ -36,6 +36,12 @@ class WirelessAccessPoint : public QObject Q_OBJECT Q_FLAGS(ApSecurityModes) + Q_PROPERTY(QString ssid READ ssid) + Q_PROPERTY(QString macAddress READ macAddress) + Q_PROPERTY(double frequency READ frequency) + Q_PROPERTY(int signalStrength READ signalStrength NOTIFY signalStrengthChanged) + Q_PROPERTY(bool protected READ isProtected) + public: enum ApSecurityMode{ ApSecurityModeNone = 0x000, @@ -53,7 +59,7 @@ public: Q_DECLARE_FLAGS(ApSecurityModes, ApSecurityMode) - explicit WirelessAccessPoint(const QDBusObjectPath &objectPath, QObject *parent = 0); + explicit WirelessAccessPoint(const QDBusObjectPath &objectPath, QObject *parent = nullptr); QDBusObjectPath objectPath() const; diff --git a/libnymea-core/networkmanager/wirelessnetworkdevice.h b/libnymea-core/networkmanager/wirelessnetworkdevice.h index f33ac6ea..90c10079 100644 --- a/libnymea-core/networkmanager/wirelessnetworkdevice.h +++ b/libnymea-core/networkmanager/wirelessnetworkdevice.h @@ -37,9 +37,15 @@ namespace nymeaserver { class WirelessNetworkDevice : public NetworkDevice { Q_OBJECT + Q_PROPERTY(QString interface READ interface) + Q_PROPERTY(QString macAddress READ macAddress) + Q_PROPERTY(NetworkDeviceState state READ deviceState) + Q_PROPERTY(QString bitRate READ bitRate) + Q_PROPERTY(WirelessAccessPoint* currentAccessPoint READ activeAccessPoint) + public: - explicit WirelessNetworkDevice(const QDBusObjectPath &objectPath, QObject *parent = 0); + explicit WirelessNetworkDevice(const QDBusObjectPath &objectPath, QObject *parent = nullptr); // Properties QString macAddress() const; diff --git a/libnymea-core/nymeaconfiguration.h b/libnymea-core/nymeaconfiguration.h index e6ada65b..eba54c09 100644 --- a/libnymea-core/nymeaconfiguration.h +++ b/libnymea-core/nymeaconfiguration.h @@ -30,9 +30,17 @@ namespace nymeaserver { class ServerConfiguration { + Q_GADGET + Q_PROPERTY(QString id MEMBER id) + Q_PROPERTY(QString address READ addressString WRITE setAddress) + Q_PROPERTY(uint port MEMBER port) + Q_PROPERTY(bool sslEnabled MEMBER sslEnabled) + Q_PROPERTY(bool authenticationEnabled MEMBER authenticationEnabled) public: QString id; QHostAddress address; + QString addressString() { return address.toString(); } + void setAddress(const QString &addressString) {address = QHostAddress(addressString); } uint port = 0; bool sslEnabled = true; bool authenticationEnabled = true; @@ -50,6 +58,8 @@ QDebug operator <<(QDebug debug, const ServerConfiguration &configuration); class WebServerConfiguration: public ServerConfiguration { + Q_GADGET + Q_PROPERTY(QString publicFolder MEMBER publicFolder) public: QString publicFolder; bool restServerEnabled = false; @@ -57,6 +67,13 @@ public: class MqttPolicy { + Q_GADGET + Q_PROPERTY(QString clientId MEMBER clientId) + Q_PROPERTY(QString username MEMBER username) + Q_PROPERTY(QString password MEMBER password) + Q_PROPERTY(QStringList allowedPublishTopicFilters MEMBER allowedPublishTopicFilters) + Q_PROPERTY(QStringList allowedSubscribeTopicFilters MEMBER allowedSubscribeTopicFilters) + public: QString clientId; QString username; diff --git a/libnymea-core/nymeacore.cpp b/libnymea-core/nymeacore.cpp index 6068d8d5..44574b64 100644 --- a/libnymea-core/nymeacore.cpp +++ b/libnymea-core/nymeacore.cpp @@ -91,12 +91,13 @@ #include "nymeacore.h" #include "loggingcategories.h" #include "platform/platform.h" -#include "jsonrpc/jsonrpcserver.h" +#include "jsonrpc/jsonrpcserverimplementation.h" #include "ruleengine/ruleengine.h" #include "networkmanager/networkmanager.h" #include "nymeasettings.h" #include "tagging/tagsstorage.h" #include "platform/platform.h" +#include "experiences/experiencemanager.h" #include "devices/devicemanagerimplementation.h" #include "devices/device.h" @@ -171,6 +172,10 @@ void NymeaCore::init() { qCDebug(dcApplication) << "Creating Cloud Manager"; m_cloudManager = new CloudManager(m_configuration, m_networkManager, this); + qCDebug(dcApplication()) << "Loading experiences"; + m_experienceManager = new ExperienceManager(m_deviceManager, m_serverManager->jsonServer(), this); + + CloudNotifications *cloudNotifications = m_cloudManager->createNotificationsPlugin(); m_deviceManager->registerStaticPlugin(cloudNotifications, cloudNotifications->metaData()); @@ -650,6 +655,7 @@ QStringList NymeaCore::loggingFilters() "Platform", "PlatformUpdate", "PlatformZeroConf", + "Experiences", "Device", "DeviceManager", "RuleEngine", @@ -793,7 +799,7 @@ void NymeaCore::gotEvent(const Event &event) // Set action params, depending on the event value foreach (RuleAction ruleAction, eventBasedActions) { - RuleActionParamList newParams; + RuleActionParams newParams; foreach (RuleActionParam ruleActionParam, ruleAction.ruleActionParams()) { // if this event param should be taken over in this action if (event.eventTypeId() == ruleActionParam.eventTypeId()) { @@ -848,7 +854,7 @@ LogEngine* NymeaCore::logEngine() const } /*! Returns the pointer to the \l{JsonRPCServer} of this instance. */ -JsonRPCServer *NymeaCore::jsonRPCServer() const +JsonRPCServerImplementation *NymeaCore::jsonRPCServer() const { return m_serverManager->jsonServer(); } diff --git a/libnymea-core/nymeacore.h b/libnymea-core/nymeacore.h index a49c5576..9a80434e 100644 --- a/libnymea-core/nymeacore.h +++ b/libnymea-core/nymeacore.h @@ -46,7 +46,7 @@ class Device; namespace nymeaserver { -class JsonRPCServer; +class JsonRPCServerImplementation; class LogEngine; class NetworkManager; class NymeaConfiguration; @@ -54,6 +54,7 @@ class TagsStorage; class UserManager; class Platform; class System; +class ExperienceManager; class NymeaCore : public QObject { @@ -81,7 +82,7 @@ public: NymeaConfiguration *configuration() const; LogEngine* logEngine() const; - JsonRPCServer *jsonRPCServer() const; + JsonRPCServerImplementation *jsonRPCServer() const; DeviceManager *deviceManager() const; RuleEngine *ruleEngine() const; TimeManager *timeManager() const; @@ -134,6 +135,7 @@ private: NetworkManager *m_networkManager; UserManager *m_userManager; System *m_system; + ExperienceManager *m_experienceManager; QList m_executingRules; diff --git a/libnymea-core/ruleengine/rule.cpp b/libnymea-core/ruleengine/rule.cpp index f025cb15..8d2b9b46 100644 --- a/libnymea-core/ruleengine/rule.cpp +++ b/libnymea-core/ruleengine/rule.cpp @@ -49,7 +49,7 @@ Rule::Rule(): m_eventDescriptors(QList()), m_actions(QList()), m_exitActions(QList()), - m_enabled(false), + m_enabled(true), m_active(false), m_statesActive(false), m_timeActive(false), @@ -128,37 +128,37 @@ void Rule::setStateEvaluator(const StateEvaluator &stateEvaluator) } /*! Returns the \l{EventDescriptor} for this Rule.*/ -QList Rule::eventDescriptors() const +EventDescriptors Rule::eventDescriptors() const { return m_eventDescriptors; } /*! Sets the \a eventDescriptors of this \l{Rule}. */ -void Rule::setEventDescriptors(const QList &eventDescriptors) +void Rule::setEventDescriptors(const EventDescriptors &eventDescriptors) { m_eventDescriptors = eventDescriptors; } /*! Returns the \l{RuleAction}{RuleActions} to be executed when this Rule is matched and states match. */ -QList Rule::actions() const +RuleActions Rule::actions() const { return m_actions; } /*! Sets the \a actions of this \l{Rule}. */ -void Rule::setActions(const QList actions) +void Rule::setActions(const RuleActions actions) { m_actions = actions; } /*! Returns the \l{RuleAction}{RuleActions} to be executed when this Rule leaves the active state. */ -QList Rule::exitActions() const +RuleActions Rule::exitActions() const { return m_exitActions; } /*! Sets the \a exitActions of this \l{Rule}. */ -void Rule::setExitActions(const QList exitActions) +void Rule::setExitActions(const RuleActions exitActions) { m_exitActions = exitActions; } @@ -250,4 +250,24 @@ QDebug operator<<(QDebug dbg, const Rule &rule) return dbg.space(); } +Rules::Rules() +{ + +} + +Rules::Rules(const QList &other): QList(other) +{ + +} + +QVariant Rules::get(int index) const +{ + return QVariant::fromValue(at(index)); +} + +void Rules::put(const QVariant &variant) +{ + append(variant.value()); +} + } diff --git a/libnymea-core/ruleengine/rule.h b/libnymea-core/ruleengine/rule.h index dacf9559..5759a0ef 100644 --- a/libnymea-core/ruleengine/rule.h +++ b/libnymea-core/ruleengine/rule.h @@ -34,6 +34,18 @@ namespace nymeaserver { class Rule { + Q_GADGET + Q_PROPERTY(QUuid id READ id WRITE setId USER true) + Q_PROPERTY(QString name READ name WRITE setName) + Q_PROPERTY(bool active READ active USER true) + Q_PROPERTY(bool enabled READ enabled WRITE setEnabled USER true) + Q_PROPERTY(bool executable READ executable WRITE setExecutable USER true) + Q_PROPERTY(EventDescriptors eventDescriptors READ eventDescriptors WRITE setEventDescriptors USER true) + Q_PROPERTY(RuleActions actions READ actions WRITE setActions) + Q_PROPERTY(RuleActions exitActions READ exitActions WRITE setExitActions USER true) + Q_PROPERTY(nymeaserver::StateEvaluator stateEvaluator READ stateEvaluator WRITE setStateEvaluator USER true) + Q_PROPERTY(TimeDescriptor timeDescriptor READ timeDescriptor WRITE setTimeDescriptor USER true) + public: Rule(); @@ -53,14 +65,14 @@ public: StateEvaluator stateEvaluator() const; void setStateEvaluator(const StateEvaluator &stateEvaluator); - QList eventDescriptors() const; - void setEventDescriptors(const QList &eventDescriptors); + EventDescriptors eventDescriptors() const; + void setEventDescriptors(const EventDescriptors &eventDescriptors); - QList actions() const; - void setActions(const QList actions); + RuleActions actions() const; + void setActions(const RuleActions actions); - QList exitActions() const; - void setExitActions(const QList exitActions); + RuleActions exitActions() const; + void setExitActions(const RuleActions exitActions); bool enabled() const; void setEnabled(const bool &enabled); @@ -83,9 +95,9 @@ private: QString m_name; TimeDescriptor m_timeDescriptor; StateEvaluator m_stateEvaluator; - QList m_eventDescriptors; - QList m_actions; - QList m_exitActions; + EventDescriptors m_eventDescriptors; + RuleActions m_actions; + RuleActions m_exitActions; bool m_enabled; bool m_active; @@ -94,8 +106,20 @@ private: bool m_executable; }; +class Rules: QList +{ + Q_GADGET + Q_PROPERTY(int count READ count) +public: + Rules(); + Rules(const QList &other); + Q_INVOKABLE QVariant get(int index) const; + Q_INVOKABLE void put(const QVariant &variant); +}; + QDebug operator<<(QDebug dbg, const Rule &rule); } +Q_DECLARE_METATYPE(nymeaserver::Rules) #endif // RULE_H diff --git a/libnymea-core/ruleengine/ruleaction.cpp b/libnymea-core/ruleengine/ruleaction.cpp index 10b31d11..a3a53789 100644 --- a/libnymea-core/ruleengine/ruleaction.cpp +++ b/libnymea-core/ruleengine/ruleaction.cpp @@ -49,7 +49,7 @@ /*! Constructs a RuleAction with the given by \a actionTypeId, \a deviceId and \a params. * Use this to create a RuleAction for regular actions, that is, identifying the Action by deviceId and actionTypeId. */ -RuleAction::RuleAction(const ActionTypeId &actionTypeId, const DeviceId &deviceId, const RuleActionParamList ¶ms): +RuleAction::RuleAction(const ActionTypeId &actionTypeId, const DeviceId &deviceId, const RuleActionParams ¶ms): m_id(ActionId::createActionId()), m_deviceId(deviceId), m_actionTypeId(actionTypeId), @@ -61,7 +61,7 @@ RuleAction::RuleAction(const ActionTypeId &actionTypeId, const DeviceId &deviceI /*! Constructs a RuleAction with the given by \a interface and \a interfaceAction. * This will create an interface based RuleAction. Meaning, the Action is idenfified by an interface and and interfaceAction. */ -RuleAction::RuleAction(const QString &interface, const QString &interfaceAction, const RuleActionParamList ¶ms) : +RuleAction::RuleAction(const QString &interface, const QString &interfaceAction, const RuleActionParams ¶ms) : m_interface(interface), m_interfaceAction(interfaceAction), m_ruleActionParams(params) @@ -169,40 +169,65 @@ ActionTypeId RuleAction::actionTypeId() const return m_actionTypeId; } +void RuleAction::setActionTypeId(const ActionTypeId &actionTypeId) +{ + m_actionTypeId = actionTypeId; +} + /*! Returns the browserItemId of this RuleAction. */ QString RuleAction::browserItemId() const { return m_browserItemId; } +void RuleAction::setBrowserItemId(const QString &browserItemId) +{ + m_browserItemId = browserItemId; +} + /*! Returns the deviceId of this RuleAction. */ DeviceId RuleAction::deviceId() const { return m_deviceId; } +void RuleAction::setDeviceId(const DeviceId &deviceId) +{ + m_deviceId = deviceId; +} + /*! Returns the name of the interface associated with this RuleAction. */ QString RuleAction::interface() const { return m_interface; } +void RuleAction::setInterface(const QString &interface) +{ + m_interface = interface; +} + /*! Returns the name of the action of the associated interface. */ QString RuleAction::interfaceAction() const { return m_interfaceAction; } +void RuleAction::setInterfaceAction(const QString &interfaceAction) +{ + m_interfaceAction = interfaceAction; +} + /*! Returns the \l{RuleActionParamList} of this RuleAction. * \sa RuleActionParam, */ -RuleActionParamList RuleAction::ruleActionParams() const +RuleActionParams RuleAction::ruleActionParams() const { return m_ruleActionParams; } /*! Set the \l{RuleActionParamList} of this RuleAction to the given \a ruleActionParams. * \sa RuleActionParam, */ -void RuleAction::setRuleActionParams(const RuleActionParamList &ruleActionParams) +void RuleAction::setRuleActionParams(const RuleActionParams &ruleActionParams) { m_ruleActionParams = ruleActionParams; } @@ -260,3 +285,23 @@ QDebug operator<<(QDebug dbg, const QList &ruleActionList) } return dbg; } + +RuleActions::RuleActions() +{ + +} + +RuleActions::RuleActions(const QList &other): QList(other) +{ + +} + +QVariant RuleActions::get(int index) const +{ + return QVariant::fromValue(at(index)); +} + +void RuleActions::put(const QVariant &variant) +{ + append(variant.value()); +} diff --git a/libnymea-core/ruleengine/ruleaction.h b/libnymea-core/ruleengine/ruleaction.h index d71b318a..02a15690 100644 --- a/libnymea-core/ruleengine/ruleaction.h +++ b/libnymea-core/ruleengine/ruleaction.h @@ -31,14 +31,22 @@ class LIBNYMEA_EXPORT RuleAction { + Q_GADGET + Q_PROPERTY(QUuid deviceId READ deviceId WRITE setDeviceId USER true) + Q_PROPERTY(QUuid actionTypeId READ actionTypeId WRITE setActionTypeId USER true) + Q_PROPERTY(QString interface READ interface WRITE setInterface USER true) + Q_PROPERTY(QString interfaceAction READ interfaceAction WRITE setInterfaceAction USER true) + Q_PROPERTY(QString browserItemId READ browserItemId WRITE setBrowserItemId USER true) + Q_PROPERTY(RuleActionParams ruleActionParams READ ruleActionParams WRITE setRuleActionParams USER true) + public: enum Type { TypeDevice, TypeInterface, TypeBrowser }; - explicit RuleAction(const ActionTypeId &actionTypeId = ActionTypeId(), const DeviceId &deviceId = DeviceId(), const RuleActionParamList ¶ms = RuleActionParamList()); - explicit RuleAction(const QString &interface, const QString &interfaceAction, const RuleActionParamList ¶ms = RuleActionParamList()); + explicit RuleAction(const ActionTypeId &actionTypeId = ActionTypeId(), const DeviceId &deviceId = DeviceId(), const RuleActionParams ¶ms = RuleActionParams()); + explicit RuleAction(const QString &interface, const QString &interfaceAction, const RuleActionParams ¶ms = RuleActionParams()); explicit RuleAction(const DeviceId &deviceId, const QString &browserItemId); RuleAction(const RuleAction &other); @@ -54,14 +62,22 @@ public: BrowserItemAction toBrowserItemAction() const; DeviceId deviceId() const; + void setDeviceId(const DeviceId &deviceId); + ActionTypeId actionTypeId() const; + void setActionTypeId(const ActionTypeId &actionTypeId); + QString browserItemId() const; + void setBrowserItemId(const QString &browserItemId); QString interface() const; - QString interfaceAction() const; + void setInterface(const QString &interface); - RuleActionParamList ruleActionParams() const; - void setRuleActionParams(const RuleActionParamList &ruleActionParams); + QString interfaceAction() const; + void setInterfaceAction(const QString &interfaceAction); + + RuleActionParams ruleActionParams() const; + void setRuleActionParams(const RuleActionParams &ruleActionParams); RuleActionParam ruleActionParam(const ParamTypeId &ruleActionParamTypeId) const; RuleActionParam ruleActionParam(const QString &ruleActionParamName) const; @@ -74,8 +90,21 @@ private: QString m_browserItemId; QString m_interface; QString m_interfaceAction; - RuleActionParamList m_ruleActionParams; + RuleActionParams m_ruleActionParams; }; +Q_DECLARE_METATYPE(RuleAction) + +class RuleActions: public QList +{ + Q_GADGET + Q_PROPERTY(int count READ count) +public: + RuleActions(); + RuleActions(const QList &other); + Q_INVOKABLE QVariant get(int index) const; + Q_INVOKABLE void put(const QVariant &variant); +}; +Q_DECLARE_METATYPE(RuleActions) QDebug operator<<(QDebug dbg, const RuleAction &ruleAction); QDebug operator<<(QDebug dbg, const QList &ruleActionList); diff --git a/libnymea-core/ruleengine/ruleactionparam.cpp b/libnymea-core/ruleengine/ruleactionparam.cpp index 31c92b50..349a3e41 100644 --- a/libnymea-core/ruleengine/ruleactionparam.cpp +++ b/libnymea-core/ruleengine/ruleactionparam.cpp @@ -124,12 +124,22 @@ ParamTypeId RuleActionParam::paramTypeId() const return m_paramTypeId; } +void RuleActionParam::setParamTypeId(const ParamTypeId ¶mTypeId) +{ + m_paramTypeId = paramTypeId; +} + /*! Returns the name of this RuleActionParam. */ QString RuleActionParam::paramName() const { return m_paramName; } +void RuleActionParam::setParamName(const QString ¶mName) +{ + m_paramName = paramName; +} + /*! Returns the value of this RuleActionParam. */ QVariant RuleActionParam::value() const { @@ -238,13 +248,13 @@ QDebug operator<<(QDebug dbg, const RuleActionParam &ruleActionParam) */ /*! Returns true if this \l{RuleActionParamList} contains a \l{RuleActionParam} with the given \a ruleActionParamTypeId. */ -bool RuleActionParamList::hasParam(const ParamTypeId &ruleActionParamTypeId) const +bool RuleActionParams::hasParam(const ParamTypeId &ruleActionParamTypeId) const { return m_ids.contains(ruleActionParamTypeId); } /*! Returns true if this \l{RuleActionParamList} contains a \l{RuleActionParam} with the given \a ruleActionParamName. */ -bool RuleActionParamList::hasParam(const QString &ruleActionParamName) const +bool RuleActionParams::hasParam(const QString &ruleActionParamName) const { foreach (const RuleActionParam ¶m, *this) { if (param.paramName() == ruleActionParamName) { @@ -255,7 +265,7 @@ bool RuleActionParamList::hasParam(const QString &ruleActionParamName) const } /*! Returns the value of the \l{RuleActionParam} with the given \a ruleActionParamTypeId. */ -QVariant RuleActionParamList::paramValue(const ParamTypeId &ruleActionParamTypeId) const +QVariant RuleActionParams::paramValue(const ParamTypeId &ruleActionParamTypeId) const { foreach (const RuleActionParam ¶m, *this) { if (param.paramTypeId() == ruleActionParamTypeId) { @@ -267,7 +277,7 @@ QVariant RuleActionParamList::paramValue(const ParamTypeId &ruleActionParamTypeI } /*! Returns true if the \a value of the \l{RuleActionParam} with the given \a ruleActionParamTypeId could be set successfully. */ -bool RuleActionParamList::setParamValue(const ParamTypeId &ruleActionParamTypeId, const QVariant &value) +bool RuleActionParams::setParamValue(const ParamTypeId &ruleActionParamTypeId, const QVariant &value) { for (int i = 0; i < count(); i++) { if (this->operator [](i).paramTypeId() == ruleActionParamTypeId) { @@ -280,7 +290,7 @@ bool RuleActionParamList::setParamValue(const ParamTypeId &ruleActionParamTypeId } /*! Appends the given \a ruleActionParam to a RuleActionParamList. */ -RuleActionParamList RuleActionParamList::operator<<(const RuleActionParam &ruleActionParam) +RuleActionParams RuleActionParams::operator<<(const RuleActionParam &ruleActionParam) { this->append(ruleActionParam); m_ids.append(ruleActionParam.paramTypeId()); @@ -288,7 +298,7 @@ RuleActionParamList RuleActionParamList::operator<<(const RuleActionParam &ruleA } /*! Writes the ruleActionParam of the given \a ruleActionParams to \a dbg. */ -QDebug operator<<(QDebug dbg, const RuleActionParamList &ruleActionParams) +QDebug operator<<(QDebug dbg, const RuleActionParams &ruleActionParams) { dbg.nospace() << "RuleActionParamList (count:" << ruleActionParams.count() << ")" << endl; for (int i = 0; i < ruleActionParams.count(); i++ ) { @@ -297,3 +307,13 @@ QDebug operator<<(QDebug dbg, const RuleActionParamList &ruleActionParams) return dbg.space(); } + +QVariant RuleActionParams::get(int index) const +{ + return QVariant::fromValue(at(index)); +} + +void RuleActionParams::put(const QVariant &variant) +{ + append(variant.value()); +} diff --git a/libnymea-core/ruleengine/ruleactionparam.h b/libnymea-core/ruleengine/ruleactionparam.h index 5608844c..5f1a1407 100644 --- a/libnymea-core/ruleengine/ruleactionparam.h +++ b/libnymea-core/ruleengine/ruleactionparam.h @@ -34,6 +34,15 @@ class LIBNYMEA_EXPORT RuleActionParam { + Q_GADGET + Q_PROPERTY(QUuid paramTypeId READ paramTypeId WRITE setParamTypeId USER true) + Q_PROPERTY(QString paramName READ paramName WRITE setParamName USER true) + Q_PROPERTY(QVariant value READ value WRITE setValue USER true) + Q_PROPERTY(QUuid eventTypeId READ eventTypeId WRITE setEventTypeId USER true) + Q_PROPERTY(QUuid eventParamTypeId READ eventParamTypeId WRITE setEventParamTypeId USER true) + Q_PROPERTY(QUuid stateDeviceId READ stateDeviceId WRITE setStateDeviceId USER true) + Q_PROPERTY(QUuid stateTypeId READ stateTypeId WRITE setStateTypeId USER true) + public: RuleActionParam(const Param ¶m = Param()); RuleActionParam(const ParamTypeId ¶mTypeId, const QVariant &value = QVariant()); @@ -44,7 +53,10 @@ public: RuleActionParam(const QString ¶mName, const DeviceId &stateDeviceId, const StateTypeId &stateTypeId); ParamTypeId paramTypeId() const; + void setParamTypeId(const ParamTypeId ¶mTypeId); + QString paramName() const; + void setParamName(const QString ¶mName); bool isValid() const; bool isValueBased() const; @@ -81,19 +93,23 @@ private: Q_DECLARE_METATYPE(RuleActionParam) QDebug operator<<(QDebug dbg, const RuleActionParam &ruleActionParam); -class LIBNYMEA_EXPORT RuleActionParamList: public QList +class LIBNYMEA_EXPORT RuleActionParams: public QList { + Q_GADGET + Q_PROPERTY(int count READ count) public: bool hasParam(const ParamTypeId &ruleActionParamTypeId) const; bool hasParam(const QString &ruleActionParamName) const; + Q_INVOKABLE QVariant get(int index) const; + Q_INVOKABLE void put(const QVariant &variant); QVariant paramValue(const ParamTypeId &ruleActionParamName) const; bool setParamValue(const ParamTypeId &ruleActionParamTypeId, const QVariant &value); - RuleActionParamList operator<<(const RuleActionParam &ruleActionParam); + RuleActionParams operator<<(const RuleActionParam &ruleActionParam); private: QList m_ids; }; -QDebug operator<<(QDebug dbg, const RuleActionParamList &ruleActionParams); +QDebug operator<<(QDebug dbg, const RuleActionParams &ruleActionParams); #endif // RULEACTIONPARAM_H diff --git a/libnymea-core/ruleengine/ruleengine.cpp b/libnymea-core/ruleengine/ruleengine.cpp index 72f98733..564e7fea 100644 --- a/libnymea-core/ruleengine/ruleengine.cpp +++ b/libnymea-core/ruleengine/ruleengine.cpp @@ -1264,7 +1264,7 @@ QList RuleEngine::loadRuleActions(NymeaSettings *settings) foreach (const QString &actionNumber, settings->childGroups()) { settings->beginGroup(actionNumber); - RuleActionParamList params; + RuleActionParams params; foreach (QString paramTypeIdString, settings->childGroups()) { if (paramTypeIdString.startsWith("RuleActionParam-")) { settings->beginGroup(paramTypeIdString); @@ -1384,7 +1384,7 @@ void RuleEngine::init() settings.beginGroup(childGroup); TimeEventItem timeEventItem; - timeEventItem.setDateTime(settings.value("dateTime", 0).toUInt()); + timeEventItem.setDateTime(QDateTime::fromTime_t(settings.value("dateTime", 0).toUInt())); timeEventItem.setTime(QTime::fromString(settings.value("time").toString())); QList weekDays; diff --git a/libnymea-core/ruleengine/stateevaluator.cpp b/libnymea-core/ruleengine/stateevaluator.cpp index 4a9a7d90..8cb99110 100644 --- a/libnymea-core/ruleengine/stateevaluator.cpp +++ b/libnymea-core/ruleengine/stateevaluator.cpp @@ -63,14 +63,19 @@ StateDescriptor StateEvaluator::stateDescriptor() const return m_stateDescriptor; } +void StateEvaluator::setStateDescriptor(const StateDescriptor &stateDescriptor) +{ + m_stateDescriptor = stateDescriptor; +} + /*! Returns the list of child \l {StateEvaluator}{StateEvaluators} of this \l StateEvaluator. */ -QList StateEvaluator::childEvaluators() const +StateEvaluators StateEvaluator::childEvaluators() const { return m_childEvaluators; } /*! Sets the list of child evaluators of this \l StateEvaluator to the given \a stateEvaluators.*/ -void StateEvaluator::setChildEvaluators(const QList &stateEvaluators) +void StateEvaluator::setChildEvaluators(const StateEvaluators &stateEvaluators) { m_childEvaluators = stateEvaluators; } @@ -372,4 +377,24 @@ QDebug operator<<(QDebug dbg, const StateEvaluator &stateEvaluator) return dbg; } +StateEvaluators::StateEvaluators() +{ + +} + +StateEvaluators::StateEvaluators(const QList &other): QList(other) +{ + +} + +QVariant StateEvaluators::get(int index) const +{ + return QVariant::fromValue(at(index)); +} + +void StateEvaluators::put(const QVariant &variant) +{ + append(variant.value()); +} + } diff --git a/libnymea-core/ruleengine/stateevaluator.h b/libnymea-core/ruleengine/stateevaluator.h index 273b98b9..cdb3a596 100644 --- a/libnymea-core/ruleengine/stateevaluator.h +++ b/libnymea-core/ruleengine/stateevaluator.h @@ -30,17 +30,34 @@ class NymeaSettings; namespace nymeaserver { +class StateEvaluator; + +class StateEvaluators: public QList +{ + Q_GADGET + Q_PROPERTY(int count READ count) +public: + StateEvaluators(); + StateEvaluators(const QList &other); + Q_INVOKABLE QVariant get(int index) const; + Q_INVOKABLE void put(const QVariant &variant); +}; class StateEvaluator { + Q_GADGET + Q_PROPERTY(StateDescriptor stateDescriptor READ stateDescriptor WRITE setStateDescriptor USER true) + Q_PROPERTY(nymeaserver::StateEvaluators childEvaluators READ childEvaluators WRITE setChildEvaluators USER true) + Q_PROPERTY(Types::StateOperator operator READ operatorType WRITE setOperatorType USER true) public: StateEvaluator(const StateDescriptor &stateDescriptor); StateEvaluator(QList childEvaluators = QList(), Types::StateOperator stateOperator = Types::StateOperatorAnd); StateDescriptor stateDescriptor() const; + void setStateDescriptor(const StateDescriptor &stateDescriptor); - QList childEvaluators() const; - void setChildEvaluators(const QList &childEvaluators); + StateEvaluators childEvaluators() const; + void setChildEvaluators(const StateEvaluators &childEvaluators); void appendEvaluator(const StateEvaluator &stateEvaluator); Types::StateOperator operatorType() const; @@ -65,8 +82,11 @@ private: Types::StateOperator m_operatorType; }; + QDebug operator<<(QDebug dbg, const StateEvaluator &stateEvaluator); } +Q_DECLARE_METATYPE(nymeaserver::StateEvaluator) +Q_DECLARE_METATYPE(nymeaserver::StateEvaluators) #endif // STATEEVALUATOR_H diff --git a/libnymea-core/servermanager.cpp b/libnymea-core/servermanager.cpp index ceb023d8..c2406080 100644 --- a/libnymea-core/servermanager.cpp +++ b/libnymea-core/servermanager.cpp @@ -40,7 +40,7 @@ #include "platform/platform.h" #include "platform/platformzeroconfcontroller.h" -#include "jsonrpc/jsonrpcserver.h" +#include "jsonrpc/jsonrpcserverimplementation.h" #include "servers/mocktcpserver.h" #include "servers/tcpserver.h" #include "servers/websocketserver.h" @@ -99,7 +99,7 @@ ServerManager::ServerManager(Platform *platform, NymeaConfiguration *configurati } // Interfaces - m_jsonServer = new JsonRPCServer(m_sslConfiguration, this); + m_jsonServer = new JsonRPCServerImplementation(m_sslConfiguration, this); // Transports MockTcpServer *tcpServer = new MockTcpServer(this); @@ -158,7 +158,7 @@ ServerManager::ServerManager(Platform *platform, NymeaConfiguration *configurati } /*! Returns the pointer to the created \l{JsonRPCServer} in this \l{ServerManager}. */ -JsonRPCServer *ServerManager::jsonServer() const +JsonRPCServerImplementation *ServerManager::jsonServer() const { return m_jsonServer; } diff --git a/libnymea-core/servermanager.h b/libnymea-core/servermanager.h index 78a4cc26..17831f96 100644 --- a/libnymea-core/servermanager.h +++ b/libnymea-core/servermanager.h @@ -34,7 +34,7 @@ namespace nymeaserver { class Platform; class NymeaConfiguration; -class JsonRPCServer; +class JsonRPCServerImplementation; class TcpServer; class WebSocketServer; class WebServer; @@ -50,7 +50,7 @@ public: explicit ServerManager(Platform *platform, NymeaConfiguration *configuration, QObject *parent = nullptr); // Interfaces - JsonRPCServer *jsonServer() const; + JsonRPCServerImplementation *jsonServer() const; BluetoothServer* bluetoothServer() const; @@ -78,7 +78,7 @@ private: Platform *m_platform = nullptr; // Interfaces - JsonRPCServer *m_jsonServer; + JsonRPCServerImplementation *m_jsonServer; BluetoothServer *m_bluetoothServer; QHash m_tcpServers; diff --git a/libnymea-core/tagging/tag.cpp b/libnymea-core/tagging/tag.cpp index a900ab92..df8b2df8 100644 --- a/libnymea-core/tagging/tag.cpp +++ b/libnymea-core/tagging/tag.cpp @@ -24,6 +24,11 @@ namespace nymeaserver { +Tag::Tag() +{ + +} + Tag::Tag(const DeviceId &deviceId, const QString &appId, const QString &tagId, const QString &value): m_deviceId(deviceId), m_appId(appId), @@ -48,21 +53,41 @@ DeviceId Tag::deviceId() const return m_deviceId; } +void Tag::setDeviceId(const DeviceId &deviceId) +{ + m_deviceId = deviceId; +} + RuleId Tag::ruleId() const { return m_ruleId; } +void Tag::setRuleId(const RuleId &ruleId) +{ + m_ruleId = ruleId; +} + QString Tag::appId() const { return m_appId; } +void Tag::setAppId(const QString &appId) +{ + m_appId = appId; +} + QString Tag::tagId() const { return m_tagId; } +void Tag::setTagId(const QString &tagId) +{ + m_tagId = tagId; +} + QString Tag::value() const { return m_value; @@ -92,4 +117,24 @@ QDebug operator<<(QDebug dbg, const Tag &tag) return dbg; } +Tags::Tags() +{ + +} + +Tags::Tags(const QList &other): QList(other) +{ + +} + +QVariant Tags::get(int index) const +{ + return QVariant::fromValue(at(index)); +} + +void Tags::put(const QVariant &variant) +{ + append(variant.value()); +} + } diff --git a/libnymea-core/tagging/tag.h b/libnymea-core/tagging/tag.h index 78e95b51..1a201846 100644 --- a/libnymea-core/tagging/tag.h +++ b/libnymea-core/tagging/tag.h @@ -24,19 +24,34 @@ #include "typeutils.h" #include +#include namespace nymeaserver { class Tag { + Q_GADGET + Q_PROPERTY(QString appId READ appId WRITE setAppId) + Q_PROPERTY(QString tagId READ tagId WRITE setTagId) + Q_PROPERTY(QUuid deviceId READ deviceId WRITE setDeviceId USER true) + Q_PROPERTY(QUuid ruleId READ ruleId WRITE setRuleId USER true) + Q_PROPERTY(QString value READ value WRITE setValue USER true) public: + Tag(); Tag(const DeviceId &deviceId, const QString &appId, const QString &tagId, const QString &value); Tag(const RuleId &ruleId, const QString &appId, const QString &tagId, const QString &value); DeviceId deviceId() const; + void setDeviceId(const DeviceId &deviceId); + RuleId ruleId() const; + void setRuleId(const RuleId &ruleId); + QString appId() const; + void setAppId(const QString &appId); + QString tagId() const; + void setTagId(const QString &tagId); QString value() const; void setValue(const QString &value); @@ -51,7 +66,21 @@ private: QString m_value; }; +class Tags: public QList +{ + Q_GADGET + Q_PROPERTY(int count READ count) +public: + Tags(); + Tags(const QList &other); + Q_INVOKABLE QVariant get(int index) const; + Q_INVOKABLE void put(const QVariant &variant); +}; + QDebug operator<<(QDebug dbg, const Tag &tag); } +Q_DECLARE_METATYPE(nymeaserver::Tag) +Q_DECLARE_METATYPE(nymeaserver::Tags) + #endif // TAG_H diff --git a/libnymea-core/usermanager/tokeninfo.cpp b/libnymea-core/usermanager/tokeninfo.cpp index 03d04c16..0eb385a8 100644 --- a/libnymea-core/usermanager/tokeninfo.cpp +++ b/libnymea-core/usermanager/tokeninfo.cpp @@ -34,6 +34,11 @@ namespace nymeaserver { +TokenInfo::TokenInfo() +{ + +} + /*! Constructs a new token info with the given \a id, \a username, \a creationTime and \a deviceName. */ TokenInfo::TokenInfo(const QUuid &id, const QString &username, const QDateTime &creationTime, const QString &deviceName): m_id(id), diff --git a/libnymea-core/usermanager/tokeninfo.h b/libnymea-core/usermanager/tokeninfo.h index d65cf544..7e3c73ca 100644 --- a/libnymea-core/usermanager/tokeninfo.h +++ b/libnymea-core/usermanager/tokeninfo.h @@ -23,12 +23,20 @@ #include #include +#include namespace nymeaserver { class TokenInfo { + Q_GADGET + Q_PROPERTY(QUuid id READ id) + Q_PROPERTY(QString username READ username) + Q_PROPERTY(QDateTime creationTime READ creationTime) + Q_PROPERTY(QString deviveName READ deviceName) + public: + TokenInfo(); TokenInfo(const QUuid &id, const QString &username, const QDateTime &creationTime, const QString &deviceName); QUuid id() const; @@ -44,5 +52,6 @@ private: }; } +Q_DECLARE_METATYPE(nymeaserver::TokenInfo) #endif // TOKENINFO_H diff --git a/libnymea/devices/device.cpp b/libnymea/devices/device.cpp index 5ed27594..a6126261 100644 --- a/libnymea/devices/device.cpp +++ b/libnymea/devices/device.cpp @@ -271,7 +271,7 @@ void Device::setSettingValue(const ParamTypeId ¶mTypeId, const QVariant &val } /*! Returns the states of this Device. It must match the \l{StateType} description in the associated \l{DeviceClass}. */ -QList Device::states() const +States Device::states() const { return m_states; } @@ -283,7 +283,7 @@ bool Device::hasParam(const ParamTypeId ¶mTypeId) const } /*! Set the \l{State}{States} of this \l{Device} to the given \a states.*/ -void Device::setStates(const QList &states) +void Device::setStates(const States &states) { m_states = states; } @@ -460,3 +460,24 @@ Devices Devices::filterByParentDeviceId(const DeviceId &deviceId) } return ret; } + +Devices Devices::filterByInterface(const QString &interface) +{ + Devices ret; + foreach (Device *device, *this) { + if (device->deviceClass().interfaces().indexOf(interface) >= 0) { + ret.append(device); + } + } + return ret; +} + +QVariant Devices::get(int index) const +{ + return QVariant::fromValue(at(index)); +} + +void Devices::put(const QVariant &variant) +{ + append(variant.value()); +} diff --git a/libnymea/devices/device.h b/libnymea/devices/device.h index acc937ab..f2f14382 100644 --- a/libnymea/devices/device.h +++ b/libnymea/devices/device.h @@ -41,9 +41,14 @@ class DevicePlugin; class LIBNYMEA_EXPORT Device: public QObject { Q_OBJECT - - friend class DeviceManager; - friend class DeviceManagerImplementation; + Q_PROPERTY(QUuid id READ id) + Q_PROPERTY(QUuid deviceClassId READ deviceClassId) + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + Q_PROPERTY(ParamList params READ params WRITE setParams) + Q_PROPERTY(ParamList settings READ settings WRITE setSettings) + Q_PROPERTY(States states READ states WRITE setStates) + Q_PROPERTY(bool setupComplete READ setupComplete WRITE setSetupComplete) + Q_PROPERTY(QUuid parentId READ parentId WRITE setParentId USER true) public: enum DeviceError { @@ -101,9 +106,9 @@ public: QVariant setting(const ParamTypeId ¶mTypeId) const; void setSettingValue(const ParamTypeId ¶mTypeId, const QVariant &value); - QList states() const; + States states() const; bool hasState(const StateTypeId &stateTypeId) const; - void setStates(const QList &states); + void setStates(const States &states); QVariant stateValue(const StateTypeId &stateTypeId) const; void setStateValue(const StateTypeId &stateTypeId, const QVariant &value); @@ -122,6 +127,8 @@ signals: void nameChanged(); private: + friend class DeviceManager; + friend class DeviceManagerImplementation; Device(DevicePlugin *plugin, const DeviceClass &deviceClass, const DeviceId &id, QObject *parent = nullptr); Device(DevicePlugin *plugin, const DeviceClass &deviceClass, QObject *parent = nullptr); @@ -137,7 +144,7 @@ private: QString m_name; ParamList m_params; ParamList m_settings; - QList m_states; + States m_states; bool m_setupComplete = false; bool m_autoCreated = false; }; @@ -146,6 +153,8 @@ QDebug operator<<(QDebug dbg, Device *device); class LIBNYMEA_EXPORT Devices: public QList { + Q_GADGET + Q_PROPERTY(int count READ count) public: Devices() = default; Devices(const QList &other); @@ -154,6 +163,9 @@ public: Devices filterByParam(const ParamTypeId ¶mTypeId, const QVariant &value = QVariant()); Devices filterByDeviceClassId(const DeviceClassId &deviceClassId); Devices filterByParentDeviceId(const DeviceId &deviceId); + Devices filterByInterface(const QString &interface); + Q_INVOKABLE QVariant get(int index) const; + Q_INVOKABLE void put(const QVariant &variant); }; Q_DECLARE_METATYPE(Device::DeviceError) diff --git a/libnymea/devices/devicedescriptor.cpp b/libnymea/devices/devicedescriptor.cpp index 654f5897..2d30d252 100644 --- a/libnymea/devices/devicedescriptor.cpp +++ b/libnymea/devices/devicedescriptor.cpp @@ -143,3 +143,13 @@ void DeviceDescriptor::setParams(const ParamList ¶ms) { m_params = params; } + +QVariant DeviceDescriptors::get(int index) const +{ + return QVariant::fromValue(at(index)); +} + +void DeviceDescriptors::put(const QVariant &variant) +{ + append(variant.value()); +} diff --git a/libnymea/devices/devicedescriptor.h b/libnymea/devices/devicedescriptor.h index 6952cc65..b4032ccf 100644 --- a/libnymea/devices/devicedescriptor.h +++ b/libnymea/devices/devicedescriptor.h @@ -32,6 +32,13 @@ class LIBNYMEA_EXPORT DeviceDescriptor { + Q_GADGET + Q_PROPERTY(QUuid id READ id) + Q_PROPERTY(QUuid deviceId READ deviceId USER true) + Q_PROPERTY(QString title READ title) + Q_PROPERTY(QString description READ description) + Q_PROPERTY(ParamList deviceParams READ params) + public: DeviceDescriptor(); DeviceDescriptor(const DeviceClassId &deviceClassId, const QString &title = QString(), const QString &description = QString(), const DeviceId &parentDeviceId = DeviceId()); @@ -69,10 +76,14 @@ private: class DeviceDescriptors: public QList { + Q_GADGET + Q_PROPERTY(int count READ count) public: DeviceDescriptors() {} inline DeviceDescriptors(std::initializer_list args): QList(args) {} DeviceDescriptors(const QList &other): QList(other) {} + Q_INVOKABLE QVariant get(int index) const; + Q_INVOKABLE void put(const QVariant &variant); }; Q_DECLARE_METATYPE(DeviceDescriptor) diff --git a/libnymea/devices/devicemanager.cpp b/libnymea/devices/devicemanager.cpp index a2bb77e4..eb2044ca 100644 --- a/libnymea/devices/devicemanager.cpp +++ b/libnymea/devices/devicemanager.cpp @@ -37,5 +37,8 @@ DeviceManager::DeviceManager(QObject *parent) : QObject(parent) { - + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); + qRegisterMetaType(); } diff --git a/libnymea/devices/devicemanager.h b/libnymea/devices/devicemanager.h index 2d55f80c..66bfd87a 100644 --- a/libnymea/devices/devicemanager.h +++ b/libnymea/devices/devicemanager.h @@ -125,7 +125,9 @@ public: virtual BrowserItemActionInfo* executeBrowserItemAction(const BrowserItemAction &browserItemAction) = 0; virtual QString translate(const PluginId &pluginId, const QString &string, const QLocale &locale) = 0; - + virtual ParamType translateParamType(const PluginId &pluginId, const ParamType ¶mType, const QLocale &locale) = 0; + virtual DeviceClass translateDeviceClass(const DeviceClass &deviceClass, const QLocale &locale) = 0; + virtual Vendor translateVendor(const Vendor &vendor, const QLocale &locale) = 0; signals: void pluginConfigChanged(const PluginId &id, const ParamList &config); void eventTriggered(const Event &event); diff --git a/libnymea/devices/deviceplugin.cpp b/libnymea/devices/deviceplugin.cpp index c0e00d16..f3409c19 100644 --- a/libnymea/devices/deviceplugin.cpp +++ b/libnymea/devices/deviceplugin.cpp @@ -487,3 +487,13 @@ DevicePlugin *DevicePlugins::findById(const PluginId &id) const } return nullptr; } + +QVariant DevicePlugins::get(int index) const +{ + return QVariant::fromValue(at(index)); +} + +void DevicePlugins::put(const QVariant &variant) +{ + append(variant.value()); +} diff --git a/libnymea/devices/deviceplugin.h b/libnymea/devices/deviceplugin.h index 034f06e6..5efe5563 100644 --- a/libnymea/devices/deviceplugin.h +++ b/libnymea/devices/deviceplugin.h @@ -55,6 +55,7 @@ #include #include #include +#include class DeviceManager; @@ -62,8 +63,10 @@ class LIBNYMEA_EXPORT DevicePlugin: public QObject { Q_OBJECT - friend class DeviceManager; - friend class DeviceManagerImplementation; + Q_PROPERTY(QUuid id READ pluginId) + Q_PROPERTY(QString name READ pluginName) + Q_PROPERTY(QString displayName READ pluginDisplayName) + Q_PROPERTY(ParamTypes paramTypes READ configurationDescription) public: DevicePlugin(QObject *parent = nullptr); @@ -115,6 +118,10 @@ protected: QSettings *pluginStorage() const; private: + friend class DeviceManager; + friend class DeviceManagerImplementation; + + void setMetaData(const PluginMetadata &metaData); void initPlugin(const PluginMetadata &metadata, DeviceManager *deviceManager, HardwareManager *hardwareManager); @@ -134,16 +141,21 @@ private: PluginMetadata m_metaData; ParamList m_config; }; - Q_DECLARE_INTERFACE(DevicePlugin, "io.nymea.DevicePlugin") +Q_DECLARE_METATYPE(DevicePlugin*) class LIBNYMEA_EXPORT DevicePlugins: public QList { + Q_GADGET + Q_PROPERTY(int count READ count) public: DevicePlugins(); DevicePlugins(const QList &other); DevicePlugin* findById(const PluginId &id) const; + Q_INVOKABLE QVariant get(int index) const; + Q_INVOKABLE void put(const QVariant &variant); }; +Q_DECLARE_METATYPE(DevicePlugins) #endif // DEVICEPLUGIN_H diff --git a/libnymea/devices/pluginmetadata.cpp b/libnymea/devices/pluginmetadata.cpp index 00c8b3cb..75aded84 100644 --- a/libnymea/devices/pluginmetadata.cpp +++ b/libnymea/devices/pluginmetadata.cpp @@ -103,7 +103,7 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) return; } - m_pluginId = jsonObject.value("id").toString(); + m_pluginId = PluginId(jsonObject.value("id").toString()); m_pluginName = jsonObject.value("name").toString(); m_pluginDisplayName = jsonObject.value("displayName").toString(); @@ -112,6 +112,10 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) hasError = true; } + if (m_pluginId.isNull()) { + m_validationErrors.append("Plugin \"" + m_pluginName + "\" has invalid UUID: " + jsonObject.value("id").toString()); + hasError = true; + } if (!verifyDuplicateUuid(m_pluginId)) { m_validationErrors.append("Plugin \"" + m_pluginName + "\" has duplicate UUID: " + m_pluginId.toString()); hasError = true; @@ -153,6 +157,10 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) hasError = true; } + if (vendorId.isNull()) { + m_validationErrors.append("Vendor \"" + vendorName + "\" has invalid UUID: " + vendorObject.value("id").toString()); + hasError = true; + } if (!verifyDuplicateUuid(vendorId)) { m_validationErrors.append("Vendor \"" + vendorName + "\" has duplicate UUID: " + vendorId.toString()); hasError = true; @@ -184,7 +192,7 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) continue; } - DeviceClassId deviceClassId = deviceClassObject.value("id").toString(); + DeviceClassId deviceClassId = DeviceClassId(deviceClassObject.value("id").toString()); QString deviceClassName = deviceClassObject.value("name").toString(); // Check if there are any unknown fields @@ -193,6 +201,10 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) hasError = true; } + if (deviceClassId.isNull()) { + m_validationErrors.append("Device class \"" + deviceClassName + "\" has invalid UUID: " + deviceClassObject.value("id").toString()); + hasError = true; + } if (!verifyDuplicateUuid(deviceClassId)) { m_validationErrors.append("Device class \"" + deviceClassName + "\" has duplicate UUID: " + deviceClassName); hasError = true; @@ -292,7 +304,7 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) continue; } - StateTypeId stateTypeId = st.value("id").toString(); + StateTypeId stateTypeId = StateTypeId(st.value("id").toString()); QString stateTypeName = st.value("name").toString(); // Check if there are any unknown fields @@ -316,6 +328,10 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) hasError = true; } + if (stateTypeId.isNull()) { + m_validationErrors.append("Device class \"" + deviceClass.name() + "\" state type \"" + stateTypeName + "\" has invalid UUID: " + st.value("id").toString()); + hasError = true; + } if (!verifyDuplicateUuid(stateTypeId)) { m_validationErrors.append("Device class \"" + deviceClass.name() + "\" state type \"" + stateTypeName + "\" has duplicate UUID: " + stateTypeId.toString()); hasError = true; @@ -408,6 +424,10 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) hasError = true; } + if (actionTypeId.isNull()) { + m_validationErrors.append("Device class \"" + deviceClass.name() + "\" action type \"" + actionTypeName + "\" has invalid UUID: " + at.value("id").toString()); + hasError = true; + } if (!verifyDuplicateUuid(actionTypeId)) { m_validationErrors.append("Device class \"" + deviceClass.name() + "\" action type \"" + actionTypeName + "\" has duplicate UUID: " + actionTypeId.toString()); hasError = true; @@ -452,6 +472,10 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) hasError = true; } + if (eventTypeId.isNull()) { + m_validationErrors.append("Device class \"" + deviceClass.name() + "\" event type \"" + eventTypeName + "\" has invalid UUID: " + et.value("id").toString()); + hasError = true; + } if (!verifyDuplicateUuid(eventTypeId)) { m_validationErrors.append("Device class \"" + deviceClass.name() + "\" event type \"" + eventTypeName + "\" has duplicate UUID: " + eventTypeId.toString()); hasError = true; @@ -493,6 +517,10 @@ void PluginMetadata::parse(const QJsonObject &jsonObject) hasError = true; } + if (actionTypeId.isNull()) { + m_validationErrors.append("Device class \"" + deviceClass.name() + "\" browser action type \"" + actionTypeName + "\" has invalid UUID: " + at.value("id").toString()); + hasError = true; + } if (!verifyDuplicateUuid(actionTypeId)) { m_validationErrors.append("Device class \"" + deviceClass.name() + "\" browser action type \"" + actionTypeName + "\" has duplicate UUID: " + actionTypeId.toString()); hasError = true; @@ -710,6 +738,10 @@ QPair PluginMetadata::parseParamTypes(const QJsonArray &array) hasErrors = true; } + if (paramTypeId.isNull()) { + m_validationErrors.append("Param type \"" + paramName + "\" has invalid UUID: " + pt.value("id").toString()); + hasErrors = true; + } if (!verifyDuplicateUuid(paramTypeId)) { m_validationErrors.append("Param type \"" + paramName + "\" has duplicate UUID: " + paramTypeId.toString()); hasErrors = true; diff --git a/libnymea/experiences/experienceplugin.cpp b/libnymea/experiences/experienceplugin.cpp new file mode 100644 index 00000000..c4356e04 --- /dev/null +++ b/libnymea/experiences/experienceplugin.cpp @@ -0,0 +1,54 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2019 Michael Zanetti * + * * + * This file is part of nymea. * + * * + * nymea 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. * + * * + * nymea 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 nymea. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "experienceplugin.h" + +ExperiencePlugin::ExperiencePlugin(QObject *parent) : QObject(parent) +{ + +} + +/*! This method will be called when the plugin has been completely loaded and experience + logic may start operating. A plugin can reimplment this to do initialisation code. */ +void ExperiencePlugin::init() +{ + +} + +/*! Returns a pointer to the DeviceManager. The pointer won't be valid unless init() has been called. */ +DeviceManager *ExperiencePlugin::deviceManager() +{ + return m_deviceManager; +} + +/*! Returns a pointer to the JsonRPCServer. The pointer won't be valid unless init() has been called. */ +JsonRPCServer *ExperiencePlugin::jsonRpcServer() +{ + return m_jsonRpcServer; +} + + +void ExperiencePlugin::initPlugin(DeviceManager *deviceManager, JsonRPCServer *jsonRPCServer) +{ + m_deviceManager = deviceManager; + m_jsonRpcServer = jsonRPCServer; + + init(); +} diff --git a/libnymea/experiences/experienceplugin.h b/libnymea/experiences/experienceplugin.h new file mode 100644 index 00000000..092db8d9 --- /dev/null +++ b/libnymea/experiences/experienceplugin.h @@ -0,0 +1,56 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2019 Michael Zanetti * + * * + * This file is part of nymea. * + * * + * nymea 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. * + * * + * nymea 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 nymea. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef EXPERIENCEPLUGIN_H +#define EXPERIENCEPLUGIN_H + +#include + +class DeviceManager; +class JsonRPCServer; + +namespace nymeaserver { +class ExperienceManager; +} +class ExperiencePlugin : public QObject +{ + Q_OBJECT +public: + explicit ExperiencePlugin(QObject *parent = nullptr); + + virtual void init() = 0; + +protected: + DeviceManager* deviceManager(); + JsonRPCServer* jsonRpcServer(); + +private: + friend class nymeaserver::ExperienceManager; + void initPlugin(DeviceManager *deviceManager, JsonRPCServer *jsonRPCServer); + + DeviceManager *m_deviceManager = nullptr; + JsonRPCServer *m_jsonRpcServer = nullptr; + +}; + +Q_DECLARE_INTERFACE(ExperiencePlugin, "io.nymea.ExperiencePlugin") + + +#endif // EXPERIENCEPLUGIN_H diff --git a/libnymea/jsonrpc/jsonhandler.cpp b/libnymea/jsonrpc/jsonhandler.cpp new file mode 100644 index 00000000..3ea88515 --- /dev/null +++ b/libnymea/jsonrpc/jsonhandler.cpp @@ -0,0 +1,464 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2019 Michael Zanetti * + * * + * This file is part of nymea. * + * * + * nymea 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. * + * * + * nymea 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 nymea. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "jsonhandler.h" + +#include "loggingcategories.h" + +#include +#include + +JsonHandler::JsonHandler(QObject *parent) : QObject(parent) +{ + qRegisterMetaType(); + registerEnum(); +} + +QVariantMap JsonHandler::jsonEnums() const +{ + return m_enums; +} + +QVariantMap JsonHandler::jsonFlags() const +{ + return m_flags; +} + +QVariantMap JsonHandler::jsonObjects() const +{ + return m_objects; +} + +QVariantMap JsonHandler::jsonMethods() const +{ + return m_methods; +} + +QVariantMap JsonHandler::jsonNotifications() const +{ + return m_notifications; +} + +QString JsonHandler::objectRef(const QString &objectName) +{ + return "$ref:" + objectName; +} + +JsonHandler::BasicType JsonHandler::variantTypeToBasicType(QVariant::Type variantType) +{ + switch (variantType) { + case QVariant::Uuid: + return Uuid; + case QVariant::String: + return String; + case QVariant::StringList: + return StringList; + case QVariant::Int: + return Int; + case QVariant::UInt: + return Uint; + case QVariant::Double: + return Double; + case QVariant::Bool: + return Bool; + case QVariant::Color: + return Color; + case QVariant::Time: + return Time; + case QVariant::Map: + return Object; + case QVariant::DateTime: + return Uint; // DateTime is represented as time_t + default: + return Variant; + } +} + +QVariant::Type JsonHandler::basicTypeToVariantType(JsonHandler::BasicType basicType) +{ + switch (basicType) { + case Uuid: + return QVariant::Uuid; + case String: + return QVariant::String; + case StringList: + return QVariant::StringList; + case Int: + return QVariant::Int; + case Uint: + return QVariant::UInt; + case Double: + return QVariant::Double; + case Bool: + return QVariant::Bool; + case Color: + return QVariant::Color; + case Time: + return QVariant::Time; + case Object: + return QVariant::Map; + case Variant: + return QVariant::Invalid; + } + return QVariant::Invalid; +} + +void JsonHandler::registerObject(const QString &name, const QVariantMap &object) +{ + m_objects.insert(name, object); +} + +void JsonHandler::registerMethod(const QString &name, const QString &description, const QVariantMap ¶ms, const QVariantMap &returns, const QString &deprecationInfo) +{ + QVariantMap methodData; + methodData.insert("description", description); + methodData.insert("params", params); + methodData.insert("returns", returns); + if (!deprecationInfo.isEmpty()) { + methodData.insert("deprecated", deprecationInfo); + } + + m_methods.insert(name, methodData); +} + +void JsonHandler::registerNotification(const QString &name, const QString &description, const QVariantMap ¶ms, const QString &deprecationInfo) +{ + QVariantMap notificationData; + notificationData.insert("description", description); + notificationData.insert("params", params); + if (!deprecationInfo.isEmpty()) { + notificationData.insert("deprecated", deprecationInfo); + } + + m_notifications.insert(name, notificationData); +} + +JsonReply *JsonHandler::createReply(const QVariantMap &data) const +{ + return JsonReply::createReply(const_cast(this), data); +} + +JsonReply *JsonHandler::createAsyncReply(const QString &method) const +{ + return JsonReply::createAsyncReply(const_cast(this), method); +} + +void JsonHandler::registerObject(const QMetaObject &metaObject) +{ + QString className = QString(metaObject.className()).split("::").last(); + QVariantMap description; + for (int i = 0; i < metaObject.propertyCount(); i++) { + QMetaProperty metaProperty = metaObject.property(i); + QString name = metaProperty.name(); + if (name == "objectName") { + continue; // Skip QObject's objectName property + } + if (metaProperty.isUser()) { + name.prepend("o:"); + } + if (!metaProperty.isWritable()) { + name.prepend("r:"); + } + QVariant typeName; + if (metaProperty.type() == QVariant::UserType) { + if (metaProperty.typeName() == QStringLiteral("QVariant::Type")) { + typeName = QString("$ref:BasicType"); + } else if (QString(metaProperty.typeName()).startsWith("QList")) { + QString elementType = QString(metaProperty.typeName()).remove("QList<").remove(">"); + QVariant::Type variantType = QVariant::nameToType(elementType.toUtf8()); + typeName = QVariantList() << enumValueName(variantTypeToBasicType(variantType)); + } else { + typeName = QString("$ref:%1").arg(QString(metaProperty.typeName()).split("::").last()); + } + } else if (metaProperty.isEnumType()) { + typeName = QString("$ref:%1").arg(QString(metaProperty.typeName()).split("::").last()); + } else if (metaProperty.isFlagType()) { + typeName = QVariantList() << "$ref:" + m_flagsEnums.value(metaProperty.name()); + } else if (metaProperty.type() == QVariant::List) { + typeName = QVariantList() << enumValueName(Variant); + } else { + typeName = enumValueName(variantTypeToBasicType(metaProperty.type())); + } + description.insert(name, typeName); + } + m_objects.insert(className, description); + m_metaObjects.insert(className, metaObject); +} + +void JsonHandler::registerObject(const QMetaObject &metaObject, const QMetaObject &listMetaObject) +{ + registerObject(metaObject); + QString listTypeName = QString(listMetaObject.className()).split("::").last(); + QString objectTypeName = QString(metaObject.className()).split("::").last(); + m_objects.insert(listTypeName, QVariantList() << QVariant(QString("$ref:%1").arg(objectTypeName))); + m_metaObjects.insert(listTypeName, listMetaObject); + m_listMetaObjects.insert(listTypeName, listMetaObject); + m_listEntryTypes.insert(listTypeName, objectTypeName); + Q_ASSERT_X(listMetaObject.indexOfProperty("count") >= 0, "JsonHandler", QString("List type %1 does not implement \"count\" property!").arg(listTypeName).toUtf8()); + Q_ASSERT_X(listMetaObject.indexOfMethod("get(int)") >= 0, "JsonHandler", QString("List type %1 does not implement \"Q_INVOKABLE QVariant get(int index)\" method!").arg(listTypeName).toUtf8()); + Q_ASSERT_X(listMetaObject.indexOfMethod("put(QVariant)") >= 0, "JsonHandler", QString("List type %1 does not implement \"Q_INVOKABLE void put(QVariant variant)\" method!").arg(listTypeName).toUtf8()); +} + +QVariant JsonHandler::pack(const QMetaObject &metaObject, const void *value) const +{ + QString className = QString(metaObject.className()).split("::").last(); + if (m_listMetaObjects.contains(className)) { + QVariantList ret; + QMetaProperty countProperty = metaObject.property(metaObject.indexOfProperty("count")); + QMetaObject entryMetaObject = m_metaObjects.value(m_listEntryTypes.value(className)); + int count = countProperty.readOnGadget(value).toInt(); + QMetaMethod getMethod = metaObject.method(metaObject.indexOfMethod("get(int)")); + for (int i = 0; i < count; i++) { + QVariant entry; + getMethod.invokeOnGadget(const_cast(value), Q_RETURN_ARG(QVariant, entry), Q_ARG(int, i)); + ret.append(pack(entryMetaObject, entry.data())); + } + return ret; + } + + if (m_metaObjects.contains(className)) { + QVariantMap ret; + for (int i = 0; i < metaObject.propertyCount(); i++) { + QMetaProperty metaProperty = metaObject.property(i); + + // Skip QObject's objectName property + if (metaProperty.name() == QStringLiteral("objectName")) { + continue; + } + + QVariant propertyValue = metaProperty.readOnGadget(value); + // If it's optional and empty, we may skip it + if (metaProperty.isUser() && (!propertyValue.isValid() || propertyValue.isNull())) { + continue; + } + + // Pack flags + if (metaProperty.isFlagType()) { + QString flagName = QString(metaProperty.typeName()).split("::").last(); + Q_ASSERT_X(m_metaFlags.contains(flagName), this->metaObject()->className(), QString("Cannot pack %1. %2 is not registered in this handler.").arg(className).arg(flagName).toUtf8()); + QMetaEnum metaFlag = m_metaFlags.value(flagName); + int flagValue = propertyValue.toInt(); + QStringList flags; + for (int i = 0; i < metaFlag.keyCount(); i++) { + if ((metaFlag.value(i) & flagValue) > 0) { + flags.append(metaFlag.key(i)); + } + } + ret.insert(metaProperty.name(), flags); + continue; + } + + // Pack enums + if (metaProperty.isEnumType()) { + QString enumName = QString(metaProperty.typeName()).split("::").last(); + Q_ASSERT_X(m_metaEnums.contains(enumName), this->metaObject()->className(), QString("Cannot pack %1. %2 is not registered in this handler.").arg(className).arg(metaProperty.typeName()).toUtf8()); + QMetaEnum metaEnum = m_metaEnums.value(enumName); + ret.insert(metaProperty.name(), metaEnum.key(propertyValue.toInt())); + continue; + } + + // Basic type/Variant type + if (metaProperty.typeName() == QStringLiteral("QVariant::Type")) { + QMetaEnum metaEnum = QMetaEnum::fromType(); + ret.insert(metaProperty.name(), metaEnum.key(variantTypeToBasicType(propertyValue.template value()))); + continue; + } + + // Our own objects + if (metaProperty.type() == QVariant::UserType) { + QString propertyTypeName = QString(metaProperty.typeName()).split("::").last(); + if (m_listMetaObjects.contains(propertyTypeName)) { + QMetaObject entryMetaObject = m_listMetaObjects.value(propertyTypeName); + QVariant packed = pack(entryMetaObject, propertyValue.data()); + if (!metaProperty.isUser() || packed.toList().count() > 0) { + ret.insert(metaProperty.name(), packed); + } + continue; + } + + if (m_metaObjects.contains(propertyTypeName)) { + QMetaObject entryMetaObject = m_metaObjects.value(propertyTypeName); + QVariant packed = pack(entryMetaObject, propertyValue.data()); + int isValidIndex = entryMetaObject.indexOfMethod("isValid()"); + bool isValid = true; + if (isValidIndex >= 0) { + QMetaMethod isValidMethod = entryMetaObject.method(isValidIndex); + isValidMethod.invokeOnGadget(propertyValue.data(), Q_RETURN_ARG(bool, isValid)); + } + if (isValid || !metaProperty.isUser()) { + ret.insert(metaProperty.name(), packed); + } + continue; + } + + // Manually converting QList... Only QVariantList is known to the meta system + if (propertyTypeName.startsWith("QList<")) { + QVariantList list; + if (propertyTypeName == "QList") { + foreach (int entry, propertyValue.value>()) { + list << entry; + } + } else if (propertyTypeName == "QList") { + foreach (const QUuid &entry, propertyValue.value>()) { + list << entry; + } + } else { + Q_ASSERT_X(false, this->metaObject()->className(), QString("Unhandled list type: %1").arg(propertyTypeName).toUtf8()); + qCWarning(dcJsonRpc()) << "Cannot pack property of unhandled list type" << propertyTypeName; + } + + if (!list.isEmpty() || !metaProperty.isUser()) { + ret.insert(metaProperty.name(), list); + } + continue; + } + + Q_ASSERT_X(false, this->metaObject()->className(), QString("Unregistered property type: %1").arg(propertyTypeName).toUtf8()); + qCWarning(dcJsonRpc()) << "Cannot pack property of unregistered object type" << propertyTypeName; + continue; + } + + // Standard properties, QString, int etc... + // Special treatment for QDateTime (converting to time_t) + if (metaProperty.type() == QVariant::DateTime) { + QDateTime dateTime = propertyValue.toDateTime(); + if (metaProperty.isUser() && dateTime.toTime_t() == 0) { + continue; + } + propertyValue = propertyValue.toDateTime().toTime_t(); + } else if (metaProperty.type() == QVariant::Time) { + propertyValue = propertyValue.toTime().toString("hh:mm"); + } + ret.insert(metaProperty.name(), propertyValue); + } + return ret; + } + + Q_ASSERT_X(false, this->metaObject()->className(), QString("Unregistered object type: %1").arg(className).toUtf8()); + qCWarning(dcJsonRpc()) << "Cannot pack object of unregistered type" << className; + return QVariant(); +} + +QVariant JsonHandler::unpack(const QMetaObject &metaObject, const QVariant &value) const +{ + QString typeName = QString(metaObject.className()).split("::").last(); + + // If it's a list object, loop over count + if (m_listMetaObjects.contains(typeName)) { + if (value.type() != QVariant::List) { +// qCWarning(dcJsonRpc()) << "Cannot unpack" << typeName << ". Value is not in list format:" << value; + return QVariant(); + } + + QVariantList list = value.toList(); + + int typeId = QMetaType::type(metaObject.className()); + void* ptr = QMetaType::create(typeId); + Q_ASSERT_X(typeId != 0, this->metaObject()->className(), QString("Cannot handle unregistered meta type %1").arg(metaObject.className()).toUtf8()); + + QMetaObject entryMetaObject = m_metaObjects.value(m_listEntryTypes.value(typeName)); + QMetaMethod putMethod = metaObject.method(metaObject.indexOfMethod("put(QVariant)")); + + foreach (const QVariant &variant, list) { + QVariant value = unpack(entryMetaObject, variant); + putMethod.invokeOnGadget(ptr, Q_ARG(QVariant, value)); + } + + QVariant ret = QVariant(typeId, ptr); + QMetaType::destroy(typeId, ptr); + return ret; + } + + // if it's an object, loop over all properties + if (m_metaObjects.contains(typeName)) { + QVariantMap map = value.toMap(); + int typeId = QMetaType::type(metaObject.className()); + Q_ASSERT_X(typeId != 0, this->metaObject()->className(), QString("Cannot handle unregistered meta type %1").arg(typeName).toUtf8()); + void* ptr = QMetaType::create(typeId); + for (int i = 0; i < metaObject.propertyCount(); i++) { + QMetaProperty metaProperty = metaObject.property(i); + if (metaProperty.name() == QStringLiteral("objectName")) { + continue; + } + if (!metaProperty.isWritable()) { + continue; + } + if (!metaProperty.isUser()) { + Q_ASSERT_X(map.contains(metaProperty.name()), this->metaObject()->className(), QString("Missing property %1 in map.").arg(metaProperty.name()).toUtf8()); + } + + if (map.contains(metaProperty.name())) { + + QString propertyTypeName = QString(metaProperty.typeName()).split("::").last(); + QVariant variant = map.value(metaProperty.name()); + + // recurse into child lists + if (m_listMetaObjects.contains(propertyTypeName)) { + QMetaObject propertyMetaObject = m_listMetaObjects.value(propertyTypeName); + metaProperty.writeOnGadget(ptr, unpack(propertyMetaObject, variant)); + continue; + } + + // recurse into child objects + if (m_metaObjects.contains(propertyTypeName)) { + QMetaObject propertyMetaObject = m_metaObjects.value(propertyTypeName); + metaProperty.writeOnGadget(ptr, unpack(propertyMetaObject, variant)); + continue; + } + + if (QString(metaProperty.typeName()).startsWith("QList<")) { + if (metaProperty.typeName() == QStringLiteral("QList")) { + QList intList; + foreach (const QVariant &val, variant.toList()) { + intList.append(val.toInt()); + } + metaProperty.writeOnGadget(ptr, QVariant::fromValue(intList)); + } else if (metaProperty.typeName() == QStringLiteral("QList")) { + QList uuidList; + foreach (const QVariant &val, variant.toList()) { + uuidList.append(val.toUuid()); + } + metaProperty.writeOnGadget(ptr, QVariant::fromValue(uuidList)); + } + continue; + } + + // Special treatment for QDateTime (convert from time_t) + if (metaProperty.type() == QVariant::DateTime) { + variant = QDateTime::fromTime_t(variant.toUInt()); + } else if (metaProperty.type() == QVariant::Time) { + variant = QTime::fromString(variant.toString(), "hh:mm"); + } + + // For basic properties just write the veriant as is + metaProperty.writeOnGadget(ptr, variant); + } + + } + QVariant ret = QVariant(typeId, ptr); + QMetaType::destroy(typeId, ptr); + return ret; + } + + return QVariant(); +} + + + diff --git a/libnymea/jsonrpc/jsonhandler.h b/libnymea/jsonrpc/jsonhandler.h new file mode 100644 index 00000000..ff4e06b2 --- /dev/null +++ b/libnymea/jsonrpc/jsonhandler.h @@ -0,0 +1,242 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2019 Michael Zanetti * + * * + * This file is part of nymea. * + * * + * nymea 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. * + * * + * nymea 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 nymea. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef JSONHANDLER_H +#define JSONHANDLER_H + +#include +#include +#include +#include +#include +#include + +#include "jsonreply.h" + +class JsonHandler : public QObject +{ + Q_OBJECT +public: + enum BasicType { + Uuid, + String, + StringList, + Int, + Uint, + Double, + Bool, + Variant, + Color, + Time, + Object + }; + Q_ENUM(BasicType) + + explicit JsonHandler(QObject *parent = nullptr); + virtual ~JsonHandler() = default; + + virtual QString name() const = 0; + + QVariantMap jsonEnums() const; + QVariantMap jsonFlags() const; + QVariantMap jsonObjects() const; + QVariantMap jsonMethods() const; + QVariantMap jsonNotifications() const; + + + template static QString enumRef(); + template static QString objectRef(); + static QString objectRef(const QString &objectName); + + template static QString enumValueName(T value); + template static T enumNameToValue(const QString &name); + + static BasicType variantTypeToBasicType(QVariant::Type variantType); + static QVariant::Type basicTypeToVariantType(BasicType basicType); + + template QVariant pack(const T &value) const; + template QVariant pack(T *value) const; + template T unpack(const QVariant &value) const; + +protected: + template void registerEnum(); + template void registerEnum(); + + template void registerObject(); + template void registerObject(); + + template void registerUncreatableObject(); + template void registerUncreatableObject(); + + template void registerList(BasicTypeName typeName); + + // Deprecated QString based registerObject + void registerObject(const QString &name, const QVariantMap &object); + + + void registerMethod(const QString &name, const QString &description, const QVariantMap ¶ms, const QVariantMap &returns, const QString &deprecationInfo = QString()); + void registerNotification(const QString &name, const QString &description, const QVariantMap ¶ms, const QString &deprecationInfo = QString()); + + JsonReply *createReply(const QVariantMap &data) const; + JsonReply *createAsyncReply(const QString &method) const; + +private: + + void registerObject(const QMetaObject &metaObject); + void registerObject(const QMetaObject &metaObject, const QMetaObject &listMetaObject); + + QVariant pack(const QMetaObject &metaObject, const void *gadget) const; + QVariant unpack(const QMetaObject &metaObject, const QVariant &value) const; + +private: + QVariantMap m_enums; + QHash m_metaEnums; + QVariantMap m_flags; + QHash m_metaFlags; + QHash m_flagsEnums; + QVariantMap m_objects; + QHash m_metaObjects; + QHash m_listMetaObjects; + QHash m_listEntryTypes; + QVariantMap m_methods; + QVariantMap m_notifications; +}; +Q_DECLARE_METATYPE(QVariant::Type) + +template +void JsonHandler::registerEnum() +{ + QMetaEnum metaEnum = QMetaEnum::fromType(); + QStringList values; + for (int i = 0; i < metaEnum.keyCount(); i++) { + values << metaEnum.key(i); + } + m_enums.insert(metaEnum.name(), values); + m_metaEnums.insert(metaEnum.name(), metaEnum); +} + +template +void JsonHandler::registerEnum() +{ + registerEnum(); + QMetaEnum metaEnum = QMetaEnum::fromType(); + QMetaEnum metaFlags = QMetaEnum::fromType(); + m_metaFlags.insert(metaFlags.name(), metaFlags); + m_flagsEnums.insert(metaFlags.name(), metaEnum.name()); + m_flags.insert(metaFlags.name(), QVariantList() << QString("$ref:%1").arg(metaEnum.name())); +} + +template +void JsonHandler::registerObject() +{ + qRegisterMetaType(); + QMetaObject metaObject = ObjectType::staticMetaObject; + registerObject(metaObject); +} + +template +void JsonHandler::registerObject() +{ + qRegisterMetaType(); + qRegisterMetaType(); + QMetaObject metaObject = ObjectType::staticMetaObject; + QMetaObject listMetaObject = ListType::staticMetaObject; + registerObject(metaObject, listMetaObject); +} + +template +void JsonHandler::registerUncreatableObject() +{ + QMetaObject metaObject = ObjectType::staticMetaObject; + registerObject(metaObject); +} + +template +void JsonHandler::registerUncreatableObject() +{ + QMetaObject metaObject = ObjectType::staticMetaObject; + QMetaObject listMetaObject = ListType::staticMetaObject; + registerObject(metaObject, listMetaObject); +} + +template +void JsonHandler::registerList(BasicTypeName typeName) +{ + QMetaObject listMetaObject = ListType::staticMetaObject; + QString listTypeName = QString(listMetaObject.className()).split("::").last(); + m_metaObjects.insert(listTypeName, listMetaObject); + m_objects.insert(listTypeName, QVariantList() << QVariant(QString("$ref:%1").arg(enumValueName(typeName)))); + Q_ASSERT_X(listMetaObject.indexOfProperty("count") >= 0, "JsonHandler", QString("List type %1 does not implement \"count\" property!").arg(listTypeName).toUtf8()); + Q_ASSERT_X(listMetaObject.indexOfMethod("get(int)") >= 0, "JsonHandler", QString("List type %1 does not implement \"Q_INVOKABLE QVariant get(int index)\" method!").arg(listTypeName).toUtf8()); + Q_ASSERT_X(listMetaObject.indexOfMethod("put(QVariant)") >= 0, "JsonHandler", QString("List type %1 does not implement \"Q_INVOKABLE void put(QVariant variant)\" method!").arg(listTypeName).toUtf8()); +} + +template +QString JsonHandler::enumRef() +{ + QMetaEnum metaEnum = QMetaEnum::fromType(); + return QString("$ref:%1").arg(metaEnum.name()); +} + +template +QString JsonHandler::objectRef() +{ + QMetaObject metaObject = T::staticMetaObject; + return QString("$ref:%1").arg(QString(metaObject.className()).split("::").last()); +} + +template +QString JsonHandler::enumValueName(T value) +{ + QMetaEnum metaEnum = QMetaEnum::fromType(); + return metaEnum.valueToKey(value); +} + +template +T JsonHandler::enumNameToValue(const QString &name) +{ + QMetaEnum metaEnum = QMetaEnum::fromType(); + return static_cast(metaEnum.keyToValue(name.toUtf8())); +} + +template +QVariant JsonHandler::pack(const T &value) const +{ + QMetaObject metaObject = T::staticMetaObject; + return pack(metaObject, static_cast(&value)); +} + +template +QVariant JsonHandler::pack(T *value) const +{ + QMetaObject metaObject = T::staticMetaObject; + return pack(metaObject, static_cast(value)); +} + +template +T JsonHandler::unpack(const QVariant &value) const +{ + QMetaObject metaObject = T::staticMetaObject; + QVariant ret = unpack(metaObject, value); + return ret.value(); +} + + +#endif // JSONHANDLER_H diff --git a/libnymea/jsonrpc/jsonreply.cpp b/libnymea/jsonrpc/jsonreply.cpp new file mode 100644 index 00000000..45d8b744 --- /dev/null +++ b/libnymea/jsonrpc/jsonreply.cpp @@ -0,0 +1,143 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2019 Michael Zanetti * + * * + * This file is part of nymea. * + * * + * nymea 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. * + * * + * nymea 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 nymea. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "jsonreply.h" + +/*! + \class JsonReply + \brief This class represents a reply for the JSON-RPC API request. + + \ingroup json + \inmodule core + + \sa JsonHandler +*/ + +/*! \enum JsonReply::Type + + This enum type specifies the type of a JsonReply. + + \value TypeSync + The response is synchronous. + \value TypeAsync + The response is asynchronous. +*/ + +/*! \fn void JsonReply::finished(); + This signal will be emitted when a JsonReply is finished. A JsonReply is finished when + the response is ready or then the reply timed out. +*/ + + + +/*! Constructs a new \l JsonReply with the given \a type, \a handler, \a method and \a data. */ +JsonReply::JsonReply(Type type, JsonHandler *handler, const QString &method, const QVariantMap &data): + m_type(type), + m_data(data), + m_handler(handler), + m_method(method), + m_timedOut(false) +{ + connect(&m_timeout, &QTimer::timeout, this, &JsonReply::timeout); +} + +/*! Returns the pointer to a new \l{JsonReply} for the given \a handler and \a data. */ +JsonReply *JsonReply::createReply(JsonHandler *handler, const QVariantMap &data) +{ + return new JsonReply(TypeSync, handler, QString(), data); +} + +/*! Returns the pointer to a new asynchronous \l{JsonReply} for the given \a handler and \a method. */ +JsonReply *JsonReply::createAsyncReply(JsonHandler *handler, const QString &method) +{ + return new JsonReply(TypeAsync, handler, method); +} + +/*! Returns the type of this \l{JsonReply}.*/ +JsonReply::Type JsonReply::type() const +{ + return m_type; +} + +/*! Returns the data of this \l{JsonReply}.*/ +QVariantMap JsonReply::data() const +{ + return m_data; +} + +/*! Sets the \a data of this \l{JsonReply}.*/ +void JsonReply::setData(const QVariantMap &data) +{ + m_data = data; +} + +/*! Returns the handler of this \l{JsonReply}.*/ +JsonHandler *JsonReply::handler() const +{ + return m_handler; +} + +/*! Returns the method of this \l{JsonReply}.*/ +QString JsonReply::method() const +{ + return m_method; +} + +/*! Returns the client ID of this \l{JsonReply}.*/ +QUuid JsonReply::clientId() const +{ + return m_clientId; +} + +/*! Sets the \a clientId of this \l{JsonReply}.*/ +void JsonReply::setClientId(const QUuid &clientId) +{ + m_clientId = clientId; +} + +/*! Returns the command ID of this \l{JsonReply}.*/ +int JsonReply::commandId() const +{ + return m_commandId; +} + +/*! Returns the \a commandId of this \l{JsonReply}.*/ +void JsonReply::setCommandId(int commandId) +{ + m_commandId = commandId; +} + +/*! Start the timeout timer for this \l{JsonReply}. The default timeout is 15 seconds. */ +void JsonReply::startWait() +{ + m_timeout.start(30000); +} + +void JsonReply::timeout() +{ + m_timedOut = true; + emit finished(); +} + +/*! Returns true if this \l{JsonReply} timed out.*/ +bool JsonReply::timedOut() const +{ + return m_timedOut; +} diff --git a/libnymea-core/jsonrpc/jsonhandler.h b/libnymea/jsonrpc/jsonreply.h similarity index 58% rename from libnymea-core/jsonrpc/jsonhandler.h rename to libnymea/jsonrpc/jsonreply.h index bf6f099d..acf1a517 100644 --- a/libnymea-core/jsonrpc/jsonhandler.h +++ b/libnymea/jsonrpc/jsonreply.h @@ -1,7 +1,6 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * - * Copyright (C) 2015 Simon Stürz * - * Copyright (C) 2014 Michael Zanetti * + * Copyright (C) 2019 Michael Zanetti * * * * This file is part of nymea. * * * @@ -19,18 +18,14 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef JSONHANDLER_H -#define JSONHANDLER_H - -#include "jsontypes.h" +#ifndef JSONREPLY_H +#define JSONREPLY_H #include #include -#include +#include #include -namespace nymeaserver { - class JsonHandler; class JsonReply: public QObject @@ -84,43 +79,4 @@ private: }; -class JsonHandler : public QObject -{ - Q_OBJECT -public: - explicit JsonHandler(QObject *parent = nullptr); - - virtual QString name() const = 0; - - QVariantMap introspect(QMetaMethod::MethodType); - - bool hasMethod(const QString &methodName); - QPair validateParams(const QString &methodName, const QVariantMap ¶ms); - QPair validateReturns(const QString &methodName, const QVariantMap &returns); - -signals: - void asyncReply(int id, const QVariantMap ¶ms); - -protected: - void setDescription(const QString &methodName, const QString &description); - void setParams(const QString &methodName, const QVariantMap ¶ms); - void setReturns(const QString &methodName, const QVariantMap &returns); - - JsonReply *createReply(const QVariantMap &data) const; - JsonReply *createAsyncReply(const QString &method) const; - QVariantMap statusToReply(Device::DeviceError status) const; - QVariantMap statusToReply(RuleEngine::RuleError status) const; - QVariantMap statusToReply(Logging::LoggingError status) const; - QVariantMap statusToReply(NymeaConfiguration::ConfigurationError status) const; - QVariantMap statusToReply(NetworkManager::NetworkManagerError status) const; - QVariantMap statusToReply(TagsStorage::TagError status) const; - -private: - QHash m_descriptions; - QHash m_params; - QHash m_returns; -}; - -} - -#endif // JSONHANDLER_H +#endif // JSONREPLY_H diff --git a/libnymea/jsonrpc/jsonrpcserver.cpp b/libnymea/jsonrpc/jsonrpcserver.cpp new file mode 100644 index 00000000..2a72c6a7 --- /dev/null +++ b/libnymea/jsonrpc/jsonrpcserver.cpp @@ -0,0 +1,25 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2019 Michael Zanetti * + * * + * This file is part of nymea. * + * * + * nymea 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. * + * * + * nymea 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 nymea. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "jsonrpcserver.h" + +/*! \fn void JsonRPCServer::registerExperienceHandler(JsonHandler *handler, int majorVersion, int minorVersion) + Register an experience JSON RPC handler on the JSON RPC server. +*/ diff --git a/libnymea/jsonrpc/jsonrpcserver.h b/libnymea/jsonrpc/jsonrpcserver.h new file mode 100644 index 00000000..b8aab9fb --- /dev/null +++ b/libnymea/jsonrpc/jsonrpcserver.h @@ -0,0 +1,36 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2019 Michael Zanetti * + * * + * This file is part of nymea. * + * * + * nymea 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. * + * * + * nymea 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 nymea. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef JSONRPCSERVER_H +#define JSONRPCSERVER_H + +class JsonHandler; + +class JsonRPCServer +{ +public: + explicit JsonRPCServer() = default; + virtual ~JsonRPCServer() = default; + + virtual bool registerExperienceHandler(JsonHandler *handler, int majorVersion, int minorVersion) = 0; + +}; + +#endif // JSONRPCSERVER_H diff --git a/libnymea/libnymea.pro b/libnymea/libnymea.pro index 78bdbae1..0e6ca52d 100644 --- a/libnymea/libnymea.pro +++ b/libnymea/libnymea.pro @@ -3,7 +3,7 @@ include(../nymea.pri) TARGET = nymea TEMPLATE = lib -QT += network bluetooth +QT += network bluetooth dbus QT -= gui DEFINES += LIBNYMEA_LIBRARY @@ -24,6 +24,9 @@ HEADERS += \ devices/devicepairinginfo.h \ devices/deviceactioninfo.h \ devices/browseresult.h \ + jsonrpc/jsonhandler.h \ + jsonrpc/jsonreply.h \ + jsonrpc/jsonrpcserver.h \ libnymea.h \ platform/package.h \ platform/repository.h \ @@ -73,6 +76,10 @@ HEADERS += \ types/paramdescriptor.h \ types/statedescriptor.h \ types/interface.h \ + time/timedescriptor.h \ + time/calendaritem.h \ + time/repeatingoption.h \ + time/timeeventitem.h \ hardwareresource.h \ plugintimer.h \ hardwaremanager.h \ @@ -82,6 +89,7 @@ HEADERS += \ platform/platformsystemcontroller.h \ platform/platformupdatecontroller.h \ platform/platformzeroconfcontroller.h \ + experiences/experienceplugin.h \ SOURCES += \ devices/browseractioninfo.cpp \ @@ -98,6 +106,9 @@ SOURCES += \ devices/devicepairinginfo.cpp \ devices/deviceactioninfo.cpp \ devices/browseresult.cpp \ + jsonrpc/jsonhandler.cpp \ + jsonrpc/jsonreply.cpp \ + jsonrpc/jsonrpcserver.cpp \ loggingcategories.cpp \ nymeasettings.cpp \ platform/package.cpp \ @@ -145,6 +156,10 @@ SOURCES += \ types/paramdescriptor.cpp \ types/statedescriptor.cpp \ types/interface.cpp \ + time/timedescriptor.cpp \ + time/calendaritem.cpp \ + time/repeatingoption.cpp \ + time/timeeventitem.cpp \ hardwareresource.cpp \ plugintimer.cpp \ hardwaremanager.cpp \ @@ -154,6 +169,7 @@ SOURCES += \ platform/platformsystemcontroller.cpp \ platform/platformupdatecontroller.cpp \ platform/platformzeroconfcontroller.cpp \ + experiences/experienceplugin.cpp \ RESOURCES += \ diff --git a/libnymea/loggingcategories.cpp b/libnymea/loggingcategories.cpp index e879bd6d..4b8cc66e 100644 --- a/libnymea/loggingcategories.cpp +++ b/libnymea/loggingcategories.cpp @@ -30,6 +30,7 @@ Q_LOGGING_CATEGORY(dcSystem, "System") Q_LOGGING_CATEGORY(dcPlatform, "Platform") Q_LOGGING_CATEGORY(dcPlatformUpdate, "PlatformUpdate") Q_LOGGING_CATEGORY(dcPlatformZeroConf, "PlatformZeroConf") +Q_LOGGING_CATEGORY(dcExperiences, "Experiences") Q_LOGGING_CATEGORY(dcTimeManager, "TimeManager") Q_LOGGING_CATEGORY(dcRuleEngine, "RuleEngine") Q_LOGGING_CATEGORY(dcRuleEngineDebug, "RuleEngineDebug") diff --git a/libnymea/loggingcategories.h b/libnymea/loggingcategories.h index 1da7b91c..fec359bc 100644 --- a/libnymea/loggingcategories.h +++ b/libnymea/loggingcategories.h @@ -35,6 +35,7 @@ Q_DECLARE_LOGGING_CATEGORY(dcSystem) Q_DECLARE_LOGGING_CATEGORY(dcPlatform) Q_DECLARE_LOGGING_CATEGORY(dcPlatformUpdate) Q_DECLARE_LOGGING_CATEGORY(dcPlatformZeroConf) +Q_DECLARE_LOGGING_CATEGORY(dcExperiences) Q_DECLARE_LOGGING_CATEGORY(dcTimeManager) Q_DECLARE_LOGGING_CATEGORY(dcRuleEngine) Q_DECLARE_LOGGING_CATEGORY(dcRuleEngineDebug) diff --git a/libnymea/platform/package.cpp b/libnymea/platform/package.cpp index 195205ec..42715acf 100644 --- a/libnymea/platform/package.cpp +++ b/libnymea/platform/package.cpp @@ -129,3 +129,23 @@ bool Package::operator!=(const Package &other) const { return !operator==(other); } + +Packages::Packages() +{ + +} + +Packages::Packages(const QList &other): QList(other) +{ + +} + +QVariant Packages::get(int index) const +{ + return QVariant::fromValue(at(index)); +} + +void Packages::put(const QVariant &variant) +{ + append(variant.value()); +} diff --git a/libnymea/platform/package.h b/libnymea/platform/package.h index a0c90ab1..65453251 100644 --- a/libnymea/platform/package.h +++ b/libnymea/platform/package.h @@ -24,9 +24,23 @@ #define PACKAGE_H #include +#include +#include +#include class Package { + Q_GADGET + Q_PROPERTY(QString id READ packageId) + Q_PROPERTY(QString displayName READ displayName) + Q_PROPERTY(QString summary READ summary) + Q_PROPERTY(QString installedVersion READ installedVersion) + Q_PROPERTY(QString candidateVersion READ candidateVersion) + Q_PROPERTY(QString changelog READ changelog) + Q_PROPERTY(bool updateAvailable READ updateAvailable) + Q_PROPERTY(bool rollbackAvailable READ rollbackAvailable) + Q_PROPERTY(bool canRemove READ canRemove) + public: explicit Package(const QString &packageId = QString(), const QString &displayName = QString(), const QString &installedVersion = QString(), const QString &candidateVersion = QString(), const QString &changelog = QString()); @@ -69,5 +83,18 @@ private: bool m_rollbackAvailable = false; bool m_canRemove = false; }; +Q_DECLARE_METATYPE(Package) + +class Packages: public QList +{ + Q_GADGET + Q_PROPERTY(int count READ count) +public: + Packages(); + Packages(const QList &other); + Q_INVOKABLE QVariant get(int index) const; + Q_INVOKABLE void put(const QVariant &variant); +}; +Q_DECLARE_METATYPE(Packages) #endif // PACKAGE_H diff --git a/libnymea/platform/repository.cpp b/libnymea/platform/repository.cpp index c3eeac53..ead662f7 100644 --- a/libnymea/platform/repository.cpp +++ b/libnymea/platform/repository.cpp @@ -54,3 +54,23 @@ void Repository::setEnabled(bool enabled) { m_enabled = enabled; } + +Repositories::Repositories() +{ + +} + +Repositories::Repositories(const QList &other): QList(other) +{ + +} + +QVariant Repositories::get(int index) const +{ + return QVariant::fromValue(at(index)); +} + +void Repositories::put(const QVariant &variant) +{ + append(variant.value()); +} diff --git a/libnymea/platform/repository.h b/libnymea/platform/repository.h index 5ec2b86b..1ba7d6ca 100644 --- a/libnymea/platform/repository.h +++ b/libnymea/platform/repository.h @@ -24,9 +24,14 @@ #define REPOSITORY_H #include +#include class Repository { + Q_GADGET + Q_PROPERTY(QString id READ id) + Q_PROPERTY(QString displayName READ displayName) + Q_PROPERTY(bool enabled READ enabled WRITE setEnabled) public: Repository(); Repository(const QString &id, const QString &displayName, bool enabled); @@ -42,5 +47,17 @@ private: QString m_displayName; bool m_enabled = false; }; +Q_DECLARE_METATYPE(Repository) + +class Repositories: public QList +{ + Q_GADGET + Q_PROPERTY(int count READ count) +public: + Repositories(); + Repositories(const QList &other); + Q_INVOKABLE QVariant get(int index) const; + Q_INVOKABLE void put(const QVariant &variant); +}; #endif // REPOSITORY_H diff --git a/libnymea-core/time/calendaritem.cpp b/libnymea/time/calendaritem.cpp similarity index 96% rename from libnymea-core/time/calendaritem.cpp rename to libnymea/time/calendaritem.cpp index b3a07e5d..9575280a 100644 --- a/libnymea-core/time/calendaritem.cpp +++ b/libnymea/time/calendaritem.cpp @@ -19,8 +19,8 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /*! - \class nymeaserver::CalendarItem - \brief Describes a clendar item for a time based \l{nymeaserver::Rule}{Rule}. + \class CalendarItem + \brief Describes a clendar item. \ingroup rules \inmodule core @@ -33,8 +33,6 @@ #include -namespace nymeaserver { - /*! Construct a invalid \l{CalendarItem}. */ CalendarItem::CalendarItem(): m_duration(0) @@ -275,5 +273,24 @@ QDebug operator<<(QDebug dbg, const CalendarItem &calendarItem) return dbg; } + + +CalendarItems::CalendarItems() +{ + } +CalendarItems::CalendarItems(const QList &other): QList(other) +{ + +} + +QVariant CalendarItems::get(int index) const +{ + return QVariant::fromValue(at(index)); +} + +void CalendarItems::put(const QVariant &variant) +{ + append(variant.value()); +} diff --git a/libnymea-core/time/calendaritem.h b/libnymea/time/calendaritem.h similarity index 79% rename from libnymea-core/time/calendaritem.h rename to libnymea/time/calendaritem.h index c99798b4..a5793fb2 100644 --- a/libnymea-core/time/calendaritem.h +++ b/libnymea/time/calendaritem.h @@ -24,11 +24,15 @@ #include #include "repeatingoption.h" - -namespace nymeaserver { +#include class CalendarItem { + Q_GADGET + Q_PROPERTY(uint duration READ duration WRITE setDuration) + Q_PROPERTY(QDateTime datetime READ dateTime WRITE setDateTime USER true) + Q_PROPERTY(QTime startTime READ startTime WRITE setStartTime USER true) + Q_PROPERTY(RepeatingOption repeating READ repeatingOption WRITE setRepeatingOption USER true) public: CalendarItem(); @@ -63,7 +67,18 @@ private: }; +class CalendarItems: public QList +{ + Q_GADGET + Q_PROPERTY(int count READ count) +public: + CalendarItems(); + CalendarItems(const QList &other); + Q_INVOKABLE QVariant get(int index) const; + Q_INVOKABLE void put(const QVariant &variant); +}; +Q_DECLARE_METATYPE(CalendarItems) + QDebug operator<<(QDebug dbg, const CalendarItem &calendarItem); -} #endif // CALENDARITEM_H diff --git a/libnymea-core/time/repeatingoption.cpp b/libnymea/time/repeatingoption.cpp similarity index 96% rename from libnymea-core/time/repeatingoption.cpp rename to libnymea/time/repeatingoption.cpp index 3a25fd26..6dea237f 100644 --- a/libnymea-core/time/repeatingoption.cpp +++ b/libnymea/time/repeatingoption.cpp @@ -83,8 +83,6 @@ #include -namespace nymeaserver { - /*! Constructs an empty \l{RepeatingOption}. */ RepeatingOption::RepeatingOption() : m_mode(RepeatingModeNone) @@ -107,18 +105,33 @@ RepeatingOption::RepeatingMode RepeatingOption::mode() const return m_mode; } +void RepeatingOption::setMode(RepeatingOption::RepeatingMode mode) +{ + m_mode = mode; +} + /*! Returns the list of week days on which this \l{RepeatingOption} should be valid. */ QList RepeatingOption::weekDays() const { return m_weekDays; } +void RepeatingOption::setWeekDays(const QList &weekDays) +{ + m_weekDays = weekDays; +} + /*! Returns the list of month days on which this \l{RepeatingOption} should be valid. */ QList RepeatingOption::monthDays() const { return m_monthDays; } +void RepeatingOption::setMonthDays(const QList &monthDays) +{ + m_monthDays = monthDays; +} + /*! Returns true if this \l{RepeatingOption} is empty. */ bool RepeatingOption::isEmtpy() const { @@ -197,5 +210,3 @@ QDebug operator<<(QDebug dbg, const RepeatingOption &repeatingOption) dbg.nospace() << "RepeatingOption(Mode:" << repeatingOption.mode() << ", Monthdays:" << repeatingOption.monthDays() << "Weekdays:" << repeatingOption.weekDays() << ")"; return dbg; } - -} diff --git a/libnymea-core/time/repeatingoption.h b/libnymea/time/repeatingoption.h similarity index 86% rename from libnymea-core/time/repeatingoption.h rename to libnymea/time/repeatingoption.h index 28055546..071d1fcb 100644 --- a/libnymea-core/time/repeatingoption.h +++ b/libnymea/time/repeatingoption.h @@ -23,15 +23,16 @@ #include #include +#include class QDateTime; -namespace nymeaserver { - class RepeatingOption { Q_GADGET - + Q_PROPERTY(RepeatingMode mode READ mode WRITE setMode) + Q_PROPERTY(QList weekDays READ weekDays WRITE setWeekDays USER true) + Q_PROPERTY(QList monthDays READ monthDays WRITE setMonthDays USER true) public: enum RepeatingMode { RepeatingModeNone, @@ -47,9 +48,13 @@ public: RepeatingOption(const RepeatingMode &mode, const QList &weekDays = QList(), const QList &monthDays = QList()); RepeatingMode mode() const; + void setMode(RepeatingMode mode); QList weekDays() const; + void setWeekDays(const QList &weekDays); + QList monthDays() const; + void setMonthDays(const QList &monthDays); bool isEmtpy() const; bool isValid() const; @@ -66,6 +71,5 @@ private: }; QDebug operator<<(QDebug dbg, const RepeatingOption &RepeatingOption); -} #endif // REPEATINGOPTION_H diff --git a/libnymea-core/time/timedescriptor.cpp b/libnymea/time/timedescriptor.cpp similarity index 93% rename from libnymea-core/time/timedescriptor.cpp rename to libnymea/time/timedescriptor.cpp index eb00bd46..45c7b764 100644 --- a/libnymea-core/time/timedescriptor.cpp +++ b/libnymea/time/timedescriptor.cpp @@ -36,8 +36,6 @@ #include -namespace nymeaserver { - /*! Constructs an invalid \l{TimeDescriptor}.*/ TimeDescriptor::TimeDescriptor() { @@ -45,25 +43,25 @@ TimeDescriptor::TimeDescriptor() } /*! Returns the list of \l{TimeEventItem}{TimeEventItems} of this \l{TimeDescriptor}.*/ -QList TimeDescriptor::timeEventItems() const +TimeEventItems TimeDescriptor::timeEventItems() const { return m_timeEventItems; } /*! Set the list of \l{TimeEventItem}{TimeEventItems} of this \l{TimeDescriptor} to the given \a timeEventItems.*/ -void TimeDescriptor::setTimeEventItems(const QList &timeEventItems) +void TimeDescriptor::setTimeEventItems(const TimeEventItems &timeEventItems) { m_timeEventItems = timeEventItems; } /*! Returns the list of \l{CalendarItem}{CalendarItems} of this \l{TimeDescriptor}.*/ -QList TimeDescriptor::calendarItems() const +CalendarItems TimeDescriptor::calendarItems() const { return m_calendarItems; } /*! Set the list of \l{CalendarItem}{CalendarItems} of this \l{TimeDescriptor} to the given \a calendarItems.*/ -void TimeDescriptor::setCalendarItems(const QList &calendarItems) +void TimeDescriptor::setCalendarItems(const CalendarItems &calendarItems) { m_calendarItems = calendarItems; } @@ -119,5 +117,3 @@ QDebug operator<<(QDebug dbg, const TimeDescriptor &timeDescriptor) } return dbg; } - -} diff --git a/libnymea-core/time/timedescriptor.h b/libnymea/time/timedescriptor.h similarity index 79% rename from libnymea-core/time/timedescriptor.h rename to libnymea/time/timedescriptor.h index 94efcc7c..78dba4d1 100644 --- a/libnymea-core/time/timedescriptor.h +++ b/libnymea/time/timedescriptor.h @@ -24,20 +24,21 @@ #include "timeeventitem.h" #include "calendaritem.h" -namespace nymeaserver { - class TimeDescriptor { + Q_GADGET + Q_PROPERTY(TimeEventItems timeEventItems READ timeEventItems WRITE setTimeEventItems USER true) + Q_PROPERTY(CalendarItems calendarItems READ calendarItems WRITE setCalendarItems USER true) public: explicit TimeDescriptor(); - QList timeEventItems() const; - void setTimeEventItems(const QList &timeEventItems); + TimeEventItems timeEventItems() const; + void setTimeEventItems(const TimeEventItems &timeEventItems); - QList calendarItems() const; - void setCalendarItems(const QList &calendarItems); + CalendarItems calendarItems() const; + void setCalendarItems(const CalendarItems &calendarItems); - bool isValid() const; + Q_INVOKABLE bool isValid() const; bool isEmpty() const; bool evaluate(const QDateTime &lastEvaluationTime, const QDateTime &dateTime) const; @@ -47,13 +48,12 @@ public: private: - QList m_timeEventItems; - QList m_calendarItems; + TimeEventItems m_timeEventItems; + CalendarItems m_calendarItems; }; QDebug operator<<(QDebug dbg, const TimeDescriptor &timeDescriptor); -} #endif // TIMEDESCRIPTOR_H diff --git a/libnymea-core/time/timeeventitem.cpp b/libnymea/time/timeeventitem.cpp similarity index 93% rename from libnymea-core/time/timeeventitem.cpp rename to libnymea/time/timeeventitem.cpp index b4fa53f8..47bda84c 100644 --- a/libnymea-core/time/timeeventitem.cpp +++ b/libnymea/time/timeeventitem.cpp @@ -33,8 +33,6 @@ #include -namespace nymeaserver { - /*! Constructs an invalid \l{TimeEventItem}. */ TimeEventItem::TimeEventItem() { @@ -48,9 +46,9 @@ QDateTime TimeEventItem::dateTime() const } /*! Sets the dateTime of this \l{TimeEventItem} to the given \a timeStamp. */ -void TimeEventItem::setDateTime(const uint &timeStamp) +void TimeEventItem::setDateTime(const QDateTime &dateTime) { - m_dateTime = QDateTime::fromTime_t(timeStamp); + m_dateTime = dateTime; } /*! Returns the time of this \l{TimeEventItem}. */ @@ -141,4 +139,23 @@ QDebug operator<<(QDebug dbg, const TimeEventItem &timeEventItem) return dbg; } + +TimeEventItems::TimeEventItems() +{ + +} + +TimeEventItems::TimeEventItems(const QList &other): QList(other) +{ + +} + +QVariant TimeEventItems::get(int index) const +{ + return QVariant::fromValue(at(index)); +} + +void TimeEventItems::put(const QVariant &variant) +{ + append(variant.value()); } diff --git a/libnymea-core/time/timeeventitem.h b/libnymea/time/timeeventitem.h similarity index 76% rename from libnymea-core/time/timeeventitem.h rename to libnymea/time/timeeventitem.h index 60a2a82a..016fb0da 100644 --- a/libnymea-core/time/timeeventitem.h +++ b/libnymea/time/timeeventitem.h @@ -22,18 +22,21 @@ #define TIMEEVENTITEM_H #include +#include #include "repeatingoption.h" -namespace nymeaserver { - class TimeEventItem { + Q_GADGET + Q_PROPERTY(QDateTime datetime READ dateTime WRITE setDateTime USER true) + Q_PROPERTY(QTime time READ time WRITE setTime USER true) + Q_PROPERTY(RepeatingOption repeating READ repeatingOption WRITE setRepeatingOption USER true) public: TimeEventItem(); QDateTime dateTime() const; - void setDateTime(const uint &timeStamp); + void setDateTime(const QDateTime &dateTime); QTime time() const; void setTime(const QTime &time); @@ -53,9 +56,21 @@ private: RepeatingOption m_repeatingOption; }; +Q_DECLARE_METATYPE(TimeEventItem) + +class TimeEventItems: public QList +{ + Q_GADGET + Q_PROPERTY(int count READ count) +public: + TimeEventItems(); + TimeEventItems(const QList &other); + Q_INVOKABLE QVariant get(int index) const; + Q_INVOKABLE void put(const QVariant &variant); +}; +Q_DECLARE_METATYPE(TimeEventItems) QDebug operator<<(QDebug dbg, const TimeEventItem &timeEventItem); -} #endif // TIMEEVENTITEM_H diff --git a/libnymea/types/action.cpp b/libnymea/types/action.cpp index a38597c1..95f9c589 100644 --- a/libnymea/types/action.cpp +++ b/libnymea/types/action.cpp @@ -73,12 +73,22 @@ ActionTypeId Action::actionTypeId() const return m_actionTypeId; } +void Action::setActionTypeId(const ActionTypeId &actionTypeId) +{ + m_actionTypeId = actionTypeId; +} + /*! Returns the deviceId this Action is associated with. */ DeviceId Action::deviceId() const { return m_deviceId; } +void Action::setDeviceId(const DeviceId &deviceId) +{ + m_deviceId = deviceId; +} + /*! Returns the parameters for this Action. */ ParamList Action::params() const { diff --git a/libnymea/types/action.h b/libnymea/types/action.h index 85e9c005..bfeda7fd 100644 --- a/libnymea/types/action.h +++ b/libnymea/types/action.h @@ -32,6 +32,11 @@ class LIBNYMEA_EXPORT Action { + Q_GADGET + Q_PROPERTY(QUuid actionTypeId READ actionTypeId WRITE setActionTypeId) + Q_PROPERTY(QUuid deviceId READ deviceId WRITE setDeviceId) + Q_PROPERTY(ParamList params READ params WRITE setParams USER true) + public: explicit Action(const ActionTypeId &actionTypeId = ActionTypeId(), const DeviceId &deviceId = DeviceId()); Action(const Action &other); @@ -41,7 +46,9 @@ public: bool isValid() const; ActionTypeId actionTypeId() const; + void setActionTypeId(const ActionTypeId &actionTypeId); DeviceId deviceId() const; + void setDeviceId(const DeviceId &deviceId); ParamList params() const; void setParams(const ParamList ¶ms); diff --git a/libnymea/types/actiontype.cpp b/libnymea/types/actiontype.cpp index 959183bd..0f3194d0 100644 --- a/libnymea/types/actiontype.cpp +++ b/libnymea/types/actiontype.cpp @@ -123,6 +123,16 @@ ActionTypes::ActionTypes(const QList &other) } } +QVariant ActionTypes::get(int index) const +{ + return QVariant::fromValue(at(index)); +} + +void ActionTypes::put(const QVariant &variant) +{ + append(variant.value()); +} + ActionType ActionTypes::findByName(const QString &name) { foreach (const ActionType &actionType, *this) { diff --git a/libnymea/types/actiontype.h b/libnymea/types/actiontype.h index d809ab4e..5dd44ceb 100644 --- a/libnymea/types/actiontype.h +++ b/libnymea/types/actiontype.h @@ -32,6 +32,13 @@ class LIBNYMEA_EXPORT ActionType { + Q_GADGET + Q_PROPERTY(QUuid id READ id) + Q_PROPERTY(QString name READ name WRITE setName) + Q_PROPERTY(QString displayName READ displayName WRITE setDisplayName) + Q_PROPERTY(int index READ index WRITE setIndex) + Q_PROPERTY(ParamTypes paramTypes READ paramTypes WRITE setParamTypes) + public: ActionType(const ActionTypeId &id = ActionTypeId()); @@ -59,16 +66,22 @@ private: int m_index; ParamTypes m_paramTypes; }; +Q_DECLARE_METATYPE(ActionType) QDebug operator<<(QDebug dbg, const ActionType &actionType); class ActionTypes: public QList { + Q_GADGET + Q_PROPERTY(int count READ count) public: ActionTypes() = default; ActionTypes(const QList &other); + Q_INVOKABLE QVariant get(int index) const; + Q_INVOKABLE void put(const QVariant &variant); ActionType findByName(const QString &name); ActionType findById(const ActionTypeId &id); }; +Q_DECLARE_METATYPE(ActionTypes) #endif // ACTIONTYPE_H diff --git a/libnymea/types/browseritem.h b/libnymea/types/browseritem.h index 466f725e..c32bcaea 100644 --- a/libnymea/types/browseritem.h +++ b/libnymea/types/browseritem.h @@ -33,6 +33,16 @@ class LIBNYMEA_EXPORT BrowserItem { Q_GADGET + Q_PROPERTY(QString id READ id) + Q_PROPERTY(QString displayName READ displayName) + Q_PROPERTY(QString description READ description) + Q_PROPERTY(BrowserIcon icon READ icon) + Q_PROPERTY(QString thumbnail READ thumbnail) + Q_PROPERTY(bool executable READ executable) + Q_PROPERTY(bool browsable READ browsable) + Q_PROPERTY(bool disabled READ disabled) + Q_PROPERTY(QList actionTypeIds READ actionTypeIds) + public: enum BrowserIcon { BrowserIconNone, diff --git a/libnymea/types/deviceclass.cpp b/libnymea/types/deviceclass.cpp index 7a62f26e..986c79cb 100644 --- a/libnymea/types/deviceclass.cpp +++ b/libnymea/types/deviceclass.cpp @@ -375,3 +375,13 @@ DeviceClass DeviceClasses::findById(const DeviceClassId &id) const } return DeviceClass(); } + +QVariant DeviceClasses::get(int index) const +{ + return QVariant::fromValue(at(index)); +} + +void DeviceClasses::put(const QVariant &variant) +{ + append(variant.value()); +} diff --git a/libnymea/types/deviceclass.h b/libnymea/types/deviceclass.h index abf1644e..d65244a2 100644 --- a/libnymea/types/deviceclass.h +++ b/libnymea/types/deviceclass.h @@ -38,6 +38,22 @@ class LIBNYMEA_EXPORT DeviceClass { Q_GADGET + Q_PROPERTY(QUuid id READ id) + Q_PROPERTY(QUuid vendorId READ vendorId) + Q_PROPERTY(QUuid pluginId READ pluginId) + Q_PROPERTY(QString name READ name) + Q_PROPERTY(QString displayName READ displayName) + Q_PROPERTY(QStringList interfaces READ interfaces) + Q_PROPERTY(bool browsable READ browsable) + Q_PROPERTY(SetupMethod setupMethod READ setupMethod) + Q_PROPERTY(CreateMethods createMethods READ createMethods) + Q_PROPERTY(StateTypes stateTypes READ stateTypes) + Q_PROPERTY(EventTypes eventTypes READ eventTypes) + Q_PROPERTY(ActionTypes actionTypes READ actionTypes) + Q_PROPERTY(ActionTypes browserItemActionTypes READ browserItemActionTypes) + Q_PROPERTY(ParamTypes paramTypes READ paramTypes) + Q_PROPERTY(ParamTypes settingsTypes READ settingsTypes) + Q_PROPERTY(ParamTypes discoveryParamTypes READ discoveryParamTypes) public: enum CreateMethod { @@ -47,6 +63,7 @@ public: }; Q_ENUM(CreateMethod) Q_DECLARE_FLAGS(CreateMethods, CreateMethod) + Q_FLAG(CreateMethods) enum SetupMethod { SetupMethodJustAdd, @@ -140,10 +157,14 @@ QDebug operator<<(QDebug &dbg, const DeviceClass &deviceClass); class LIBNYMEA_EXPORT DeviceClasses: public QList { + Q_GADGET + Q_PROPERTY(int count READ count) public: DeviceClasses(); DeviceClasses(const QList &other); DeviceClass findById(const DeviceClassId &id) const; + Q_INVOKABLE QVariant get(int index) const; + Q_INVOKABLE void put(const QVariant &variant); }; #endif diff --git a/libnymea/types/event.cpp b/libnymea/types/event.cpp index 9703c68d..82a50eb4 100644 --- a/libnymea/types/event.cpp +++ b/libnymea/types/event.cpp @@ -108,7 +108,7 @@ Param Event::param(const ParamTypeId ¶mTypeId) const return param; } } - return Param(QString()); + return Param(paramTypeId); } /*! Returns true if this event is autogenerated by a state change. */ diff --git a/libnymea/types/event.h b/libnymea/types/event.h index e88867ab..de2bd947 100644 --- a/libnymea/types/event.h +++ b/libnymea/types/event.h @@ -34,6 +34,10 @@ class LIBNYMEA_EXPORT Event { + Q_GADGET + Q_PROPERTY(QUuid eventTypeId READ eventTypeId) + Q_PROPERTY(QUuid deviceId READ deviceId) + Q_PROPERTY(ParamList params READ params) public: Event(); Event(const EventTypeId &eventTypeId, const DeviceId &deviceId, const ParamList ¶ms = ParamList(), bool isStateChangeEvent = false); diff --git a/libnymea/types/eventdescriptor.cpp b/libnymea/types/eventdescriptor.cpp index f0a2b117..0c57d8f0 100644 --- a/libnymea/types/eventdescriptor.cpp +++ b/libnymea/types/eventdescriptor.cpp @@ -89,24 +89,44 @@ EventTypeId EventDescriptor::eventTypeId() const return m_eventTypeId; } +void EventDescriptor::setEventTypeId(const EventTypeId &eventTypeId) +{ + m_eventTypeId = eventTypeId; +} + /*! Returns the id of the \l{Device} associated with this Event. */ DeviceId EventDescriptor::deviceId() const { return m_deviceId; } +void EventDescriptor::setDeviceId(const DeviceId &deviceId) +{ + m_deviceId = deviceId; +} + /*! Returns the interface associated with this EventDescriptor. */ QString EventDescriptor::interface() const { return m_interface; } +void EventDescriptor::setInterface(const QString &interface) +{ + m_interface = interface; +} + /*! Returns the interface's event name associated with this EventDescriptor.*/ QString EventDescriptor::interfaceEvent() const { return m_interfaceEvent; } +void EventDescriptor::setInterfaceEvent(const QString &interfaceEvent) +{ + m_interfaceEvent = interfaceEvent; +} + /*! Returns the parameters of this Event. */ QList EventDescriptor::paramDescriptors() const { @@ -169,3 +189,23 @@ QDebug operator<<(QDebug dbg, const QList &eventDescriptors) return dbg; } + +EventDescriptors::EventDescriptors() +{ + +} + +EventDescriptors::EventDescriptors(const QList &other): QList(other) +{ + +} + +QVariant EventDescriptors::get(int index) const +{ + return QVariant::fromValue(at(index)); +} + +void EventDescriptors::put(const QVariant &variant) +{ + append(variant.value()); +} diff --git a/libnymea/types/eventdescriptor.h b/libnymea/types/eventdescriptor.h index 97e98f79..378c9daa 100644 --- a/libnymea/types/eventdescriptor.h +++ b/libnymea/types/eventdescriptor.h @@ -35,6 +35,12 @@ class LIBNYMEA_EXPORT EventDescriptor { + Q_GADGET + Q_PROPERTY(QUuid deviceId READ deviceId WRITE setDeviceId USER true) + Q_PROPERTY(QUuid eventTypeId READ eventTypeId WRITE setEventTypeId USER true) + Q_PROPERTY(QString interface READ interface WRITE setInterface USER true) + Q_PROPERTY(QString interfaceEvent READ interfaceEvent WRITE setInterfaceEvent USER true) + Q_PROPERTY(ParamDescriptors paramDescriptors READ paramDescriptors WRITE setParamDescriptors USER true) public: enum Type { TypeDevice, @@ -49,10 +55,16 @@ public: bool isValid() const; EventTypeId eventTypeId() const; + void setEventTypeId(const EventTypeId &eventTypeId); + DeviceId deviceId() const; + void setDeviceId(const DeviceId &deviceId); QString interface() const; + void setInterface(const QString &interface); + QString interfaceEvent() const; + void setInterfaceEvent(const QString &interfaceEvent); QList paramDescriptors() const; void setParamDescriptors(const QList ¶mDescriptors); @@ -67,6 +79,20 @@ private: QString m_interfaceEvent; QList m_paramDescriptors; }; +Q_DECLARE_METATYPE(EventDescriptor) + +class EventDescriptors: public QList +{ + Q_GADGET + Q_PROPERTY(int count READ count) +public: + EventDescriptors(); + EventDescriptors(const QList &other); + Q_INVOKABLE QVariant get(int index) const; + Q_INVOKABLE void put(const QVariant &variant); +}; +Q_DECLARE_METATYPE(EventDescriptors) + QDebug operator<<(QDebug dbg, const EventDescriptor &eventDescriptor); QDebug operator<<(QDebug dbg, const QList &eventDescriptors); diff --git a/libnymea/types/eventtype.cpp b/libnymea/types/eventtype.cpp index b7a10fa1..0241ac43 100644 --- a/libnymea/types/eventtype.cpp +++ b/libnymea/types/eventtype.cpp @@ -33,6 +33,11 @@ #include "eventtype.h" +EventType::EventType() +{ + +} + /*! Constructs a EventType object with the given \a id. */ EventType::EventType(const EventTypeId &id): m_id(id), @@ -123,6 +128,16 @@ EventTypes::EventTypes(const QList &other) } } +QVariant EventTypes::get(int index) const +{ + return QVariant::fromValue(at(index)); +} + +void EventTypes::put(const QVariant &variant) +{ + append(variant.value()); +} + EventType EventTypes::findByName(const QString &name) { foreach (const EventType &eventType, *this) { diff --git a/libnymea/types/eventtype.h b/libnymea/types/eventtype.h index c50ec651..4e4b629c 100644 --- a/libnymea/types/eventtype.h +++ b/libnymea/types/eventtype.h @@ -32,7 +32,15 @@ class LIBNYMEA_EXPORT EventType { + Q_GADGET + Q_PROPERTY(QUuid id READ id) + Q_PROPERTY(QString name READ name WRITE setName) + Q_PROPERTY(QString displayName READ displayName WRITE setDisplayName) + Q_PROPERTY(int index READ index) + Q_PROPERTY(ParamTypes paramTypes READ paramTypes WRITE setParamTypes) + public: + EventType(); EventType(const EventTypeId &id); EventTypeId id() const; @@ -61,14 +69,20 @@ private: int m_index; QList m_paramTypes; }; +Q_DECLARE_METATYPE(EventType) class EventTypes: public QList { + Q_GADGET + Q_PROPERTY(int count READ count) public: EventTypes() = default; EventTypes(const QList &other); + Q_INVOKABLE QVariant get(int index) const; + Q_INVOKABLE void put(const QVariant &variant); EventType findByName(const QString &name); EventType findById(const EventTypeId &id); }; +Q_DECLARE_METATYPE(EventTypes) #endif // TRIGGERTYPE_H diff --git a/libnymea/types/mediabrowseritem.h b/libnymea/types/mediabrowseritem.h index 64df18b2..03ad702e 100644 --- a/libnymea/types/mediabrowseritem.h +++ b/libnymea/types/mediabrowseritem.h @@ -28,6 +28,8 @@ class MediaBrowserItem: public BrowserItem { Q_GADGET + Q_PROPERTY(MediaBrowserIcon mediaIcon READ mediaIcon) + public: enum MediaBrowserIcon { MediaBrowserIconNone = 1, diff --git a/libnymea/types/param.cpp b/libnymea/types/param.cpp index f49f39f6..7c8f70e1 100644 --- a/libnymea/types/param.cpp +++ b/libnymea/types/param.cpp @@ -48,6 +48,11 @@ ParamTypeId Param::paramTypeId() const return m_paramTypeId; } +void Param::setParamTypeId(const ParamTypeId ¶mTypeId) +{ + m_paramTypeId = paramTypeId; +} + /*! Returns the value of this \l Param. */ QVariant Param::value() const { @@ -109,6 +114,16 @@ ParamList::ParamList(const QList &other): QList(other) } +QVariant ParamList::get(int index) +{ + return QVariant::fromValue(at(index)); +} + +void ParamList::put(const QVariant &variant) +{ + append(variant.value()); +} + /*! Returns true if this ParamList contains a Param with the given \a paramTypeId. */ bool ParamList::hasParam(const ParamTypeId ¶mTypeId) const { diff --git a/libnymea/types/param.h b/libnymea/types/param.h index 04c14fe5..a37981e4 100644 --- a/libnymea/types/param.h +++ b/libnymea/types/param.h @@ -32,10 +32,14 @@ class LIBNYMEA_EXPORT Param { + Q_GADGET + Q_PROPERTY(QUuid paramTypeId READ paramTypeId WRITE setParamTypeId USER true) + Q_PROPERTY(QVariant value READ value WRITE setValue) public: Param(const ParamTypeId ¶mTypeId = ParamTypeId(), const QVariant &value = QVariant()); ParamTypeId paramTypeId() const; + void setParamTypeId(const ParamTypeId ¶mTypeId); QVariant value() const; void setValue(const QVariant &value); @@ -52,9 +56,13 @@ QDebug operator<<(QDebug dbg, const Param ¶m); class LIBNYMEA_EXPORT ParamList: public QList { + Q_GADGET + Q_PROPERTY(int count READ count) public: ParamList(); ParamList(const QList &other); + Q_INVOKABLE QVariant get(int index); + Q_INVOKABLE void put(const QVariant &variant); bool hasParam(const ParamTypeId ¶mTypeId) const; QVariant paramValue(const ParamTypeId ¶mTypeId) const; bool setParamValue(const ParamTypeId ¶mTypeId, const QVariant &value); @@ -64,7 +72,7 @@ private: QList m_ids; }; - +Q_DECLARE_METATYPE(ParamList) QDebug operator<<(QDebug dbg, const ParamList ¶ms); #endif // PARAM_H diff --git a/libnymea/types/paramdescriptor.cpp b/libnymea/types/paramdescriptor.cpp index 86a569c0..b8d60cf8 100644 --- a/libnymea/types/paramdescriptor.cpp +++ b/libnymea/types/paramdescriptor.cpp @@ -62,6 +62,12 @@ QString ParamDescriptor::paramName() const return m_paramName; } +/*! Sets the param name of this ParamDescriptor. */ +void ParamDescriptor::setParamName(const QString ¶mName) +{ + m_paramName = paramName; +} + /*! Returns the ValueOperator of this ParamDescriptor. */ Types::ValueOperator ParamDescriptor::operatorType() const { @@ -80,3 +86,23 @@ QDebug operator<<(QDebug dbg, const ParamDescriptor ¶mDescriptor) dbg.nospace() << "ParamDescriptor(ParamTypeId: " << paramDescriptor.paramTypeId().toString() << ", Name:" << paramDescriptor.paramName() << ", Value:" << paramDescriptor.value() << ")" << endl; return dbg; } + +ParamDescriptors::ParamDescriptors() +{ + +} + +ParamDescriptors::ParamDescriptors(const QList &other): QList(other) +{ + +} + +QVariant ParamDescriptors::get(int index) const +{ + return QVariant::fromValue(at(index)); +} + +void ParamDescriptors::put(const QVariant &variant) +{ + append(variant.value()); +} diff --git a/libnymea/types/paramdescriptor.h b/libnymea/types/paramdescriptor.h index 0c038069..4244bb2a 100644 --- a/libnymea/types/paramdescriptor.h +++ b/libnymea/types/paramdescriptor.h @@ -31,11 +31,17 @@ class LIBNYMEA_EXPORT ParamDescriptor : public Param { + Q_GADGET + Q_PROPERTY(QString paramName READ paramName WRITE setParamName USER true) + Q_PROPERTY(Types::ValueOperator operator READ operatorType WRITE setOperatorType) public: + ParamDescriptor() = default; ParamDescriptor(const ParamTypeId ¶mTypeId, const QVariant &value = QVariant()); ParamDescriptor(const QString ¶mName, const QVariant &value = QVariant()); QString paramName() const; + void setParamName(const QString ¶mName); + Types::ValueOperator operatorType() const; void setOperatorType(Types::ValueOperator operatorType); @@ -43,6 +49,19 @@ private: QString m_paramName; Types::ValueOperator m_operatorType; }; +Q_DECLARE_METATYPE(ParamDescriptor) + +class LIBNYMEA_EXPORT ParamDescriptors: public QList +{ + Q_GADGET + Q_PROPERTY(int count READ count) +public: + ParamDescriptors(); + ParamDescriptors(const QList &other); + Q_INVOKABLE QVariant get(int index) const; + Q_INVOKABLE void put(const QVariant &variant); +}; +Q_DECLARE_METATYPE(ParamDescriptors) QDebug operator<<(QDebug dbg, const ParamDescriptor ¶mDescriptor); diff --git a/libnymea/types/paramtype.cpp b/libnymea/types/paramtype.cpp index 246d4a8e..05283b9a 100644 --- a/libnymea/types/paramtype.cpp +++ b/libnymea/types/paramtype.cpp @@ -255,6 +255,16 @@ ParamTypes::ParamTypes(const QList &other): QList(other) { } +QVariant ParamTypes::get(int index) const +{ + return QVariant::fromValue(at(index)); +} + +void ParamTypes::put(const QVariant &variant) +{ + append(variant.value()); +} + ParamType ParamTypes::findByName(const QString &name) { foreach (const ParamType ¶mType, *this) { diff --git a/libnymea/types/paramtype.h b/libnymea/types/paramtype.h index ea80fc00..cb6d5c37 100644 --- a/libnymea/types/paramtype.h +++ b/libnymea/types/paramtype.h @@ -32,6 +32,20 @@ class LIBNYMEA_EXPORT ParamType { + Q_GADGET + Q_PROPERTY(QUuid id READ id) + Q_PROPERTY(QString name READ name WRITE setName) + Q_PROPERTY(QString displayName READ displayName WRITE setDisplayName) + Q_PROPERTY(QVariant::Type type READ type WRITE setType) + Q_PROPERTY(int index READ index WRITE setIndex) + Q_PROPERTY(QVariant defaultValue READ defaultValue WRITE setDefaultValue USER true) + Q_PROPERTY(QVariant minValue READ minValue WRITE setMinValue USER true) + Q_PROPERTY(QVariant maxValue READ maxValue WRITE setMaxValue USER true) + Q_PROPERTY(QVariantList allowedValues READ allowedValues WRITE setAllowedValues USER true) + Q_PROPERTY(Types::InputType inputType READ inputType WRITE setInputType USER true) + Q_PROPERTY(Types::Unit unit READ unit WRITE setUnit USER true) + Q_PROPERTY(bool readOnly READ readOnly WRITE setReadOnly USER true) + public: ParamType() = default; ParamType(const ParamTypeId &id, const QString &name, const QVariant::Type type, const QVariant &defaultValue = QVariant()); @@ -96,12 +110,18 @@ private: class ParamTypes: public QList { + Q_GADGET + Q_PROPERTY(int count READ count) public: ParamTypes() = default; ParamTypes(const QList &other); + Q_INVOKABLE QVariant get(int index) const; + Q_INVOKABLE void put(const QVariant &variant); ParamType findByName(const QString &name); ParamType findById(const ParamTypeId &id); }; +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(ParamTypes) QDebug operator<<(QDebug dbg, const ParamType ¶mType); QDebug operator<<(QDebug dbg, const QList ¶mTypes); diff --git a/libnymea/types/state.cpp b/libnymea/types/state.cpp index 272d670c..b1e582b1 100644 --- a/libnymea/types/state.cpp +++ b/libnymea/types/state.cpp @@ -36,6 +36,11 @@ #include "state.h" +State::State() +{ + +} + /*! Constructs a State reflecting the \l{StateType} given by \a stateTypeId * and associated with the \l{Device} given by \a deviceId */ State::State(const StateTypeId &stateTypeId, const DeviceId &deviceId): @@ -92,3 +97,23 @@ QDebug operator<<(QDebug dbg, const QList &states) return dbg.space(); } + +States::States() +{ + +} + +States::States(const QList &other): QList(other) +{ + +} + +QVariant States::get(int index) const +{ + return QVariant::fromValue(at(index)); +} + +void States::put(const QVariant &variant) +{ + append(variant.value()); +} diff --git a/libnymea/types/state.h b/libnymea/types/state.h index 471115ca..d01bfd8e 100644 --- a/libnymea/types/state.h +++ b/libnymea/types/state.h @@ -32,7 +32,12 @@ class LIBNYMEA_EXPORT State { + Q_GADGET + Q_PROPERTY(QUuid stateTypeId READ stateTypeId) + Q_PROPERTY(QVariant value READ value) + public: + State(); State(const StateTypeId &stateTypeId, const DeviceId &deviceId); StateId id() const; @@ -49,6 +54,19 @@ private: DeviceId m_deviceId; QVariant m_value; }; +Q_DECLARE_METATYPE(State) + +class States: public QList +{ + Q_GADGET + Q_PROPERTY(int count READ count) +public: + States(); + States(const QList &other); + Q_INVOKABLE QVariant get(int index) const; + Q_INVOKABLE void put(const QVariant &variant); +}; +Q_DECLARE_METATYPE(States) QDebug operator<<(QDebug dbg, const State &event); QDebug operator<<(QDebug dbg, const QList &events); diff --git a/libnymea/types/statedescriptor.cpp b/libnymea/types/statedescriptor.cpp index 29b70aac..ece565d4 100644 --- a/libnymea/types/statedescriptor.cpp +++ b/libnymea/types/statedescriptor.cpp @@ -85,36 +85,66 @@ StateTypeId StateDescriptor::stateTypeId() const return m_stateTypeId; } +void StateDescriptor::setStateTypeId(const StateTypeId &stateTypeId) +{ + m_stateTypeId = stateTypeId; +} + /*! Returns the DeviceId of this \l{State}.*/ DeviceId StateDescriptor::deviceId() const { return m_deviceId; } +void StateDescriptor::setDeviceId(const DeviceId &deviceId) +{ + m_deviceId = deviceId; +} + /*! Returns the interface for this \{StateDescriptor}.*/ QString StateDescriptor::interface() const { return m_interface; } +void StateDescriptor::setInterface(const QString &interface) +{ + m_interface = interface; +} + /*! Returns the interface state's name for this \{StateDescriptor}.*/ QString StateDescriptor::interfaceState() const { return m_interfaceState; } +void StateDescriptor::setInterfaceState(const QString &interfaceState) +{ + m_interfaceState = interfaceState; +} + /*! Returns the Value of this \l{State}.*/ QVariant StateDescriptor::stateValue() const { return m_stateValue; } +void StateDescriptor::setStateValue(const QVariant &value) +{ + m_stateValue = value; +} + /*! Returns the ValueOperator of this \l{State}.*/ Types::ValueOperator StateDescriptor::operatorType() const { return m_operatorType; } +void StateDescriptor::setOperatorType(Types::ValueOperator opertatorType) +{ + m_operatorType = opertatorType; +} + /*! Compare this StateDescriptor to \a other. * StateDescriptors are equal (returns true) if stateTypeId, stateValue and operatorType match. */ bool StateDescriptor::operator ==(const StateDescriptor &other) const diff --git a/libnymea/types/statedescriptor.h b/libnymea/types/statedescriptor.h index e53034dd..b0022442 100644 --- a/libnymea/types/statedescriptor.h +++ b/libnymea/types/statedescriptor.h @@ -36,6 +36,13 @@ class LIBNYMEA_EXPORT StateDescriptor { + Q_GADGET + Q_PROPERTY(QUuid stateTypeId READ stateTypeId WRITE setStateTypeId USER true) + Q_PROPERTY(QUuid deviceId READ deviceId WRITE setDeviceId USER true) + Q_PROPERTY(QString interface READ interface WRITE setInterface USER true) + Q_PROPERTY(QString interfaceState READ interfaceState WRITE setInterfaceState USER true) + Q_PROPERTY(QVariant value READ stateValue WRITE setStateValue) + Q_PROPERTY(Types::ValueOperator operator READ operatorType WRITE setOperatorType) public: enum Type { TypeDevice, @@ -49,15 +56,24 @@ public: Type type() const; StateTypeId stateTypeId() const; + void setStateTypeId(const StateTypeId &stateTypeId); + DeviceId deviceId() const; + void setDeviceId(const DeviceId &deviceId); QString interface() const; + void setInterface(const QString &interface); + QString interfaceState() const; + void setInterfaceState(const QString &interfaceState); QVariant stateValue() const; - Types::ValueOperator operatorType() const; + void setStateValue(const QVariant &value); - bool isValid() const; + Types::ValueOperator operatorType() const; + void setOperatorType(Types::ValueOperator opertatorType); + + Q_INVOKABLE bool isValid() const; bool operator ==(const StateDescriptor &other) const; @@ -70,8 +86,9 @@ private: QString m_interface; QString m_interfaceState; QVariant m_stateValue; - Types::ValueOperator m_operatorType; + Types::ValueOperator m_operatorType = Types::ValueOperatorEquals; }; +Q_DECLARE_METATYPE(StateDescriptor) QDebug operator<<(QDebug dbg, const StateDescriptor &stateDescriptor); diff --git a/libnymea/types/statetype.cpp b/libnymea/types/statetype.cpp index acbd55c9..2905bebe 100644 --- a/libnymea/types/statetype.cpp +++ b/libnymea/types/statetype.cpp @@ -34,6 +34,11 @@ #include "statetype.h" +StateType::StateType() +{ + +} + /*! Constructs a StateType with the given \a id. * When creating a \l{DevicePlugin} generate a new uuid for each StateType you define and * hardcode it into the plugin json file. */ @@ -193,6 +198,16 @@ StateTypes::StateTypes(const QList &other) } } +QVariant StateTypes::get(int index) const +{ + return QVariant::fromValue(at(index)); +} + +void StateTypes::put(const QVariant &variant) +{ + append(variant.value()); +} + StateType StateTypes::findByName(const QString &name) { foreach (const StateType &stateType, *this) { diff --git a/libnymea/types/statetype.h b/libnymea/types/statetype.h index 88d65a16..a66486eb 100644 --- a/libnymea/types/statetype.h +++ b/libnymea/types/statetype.h @@ -32,7 +32,20 @@ class LIBNYMEA_EXPORT StateType { + Q_GADGET + Q_PROPERTY(QUuid id READ id) + Q_PROPERTY(QString name READ name WRITE setName) + Q_PROPERTY(QString displayName READ displayName WRITE setDisplayName) + Q_PROPERTY(QVariant::Type type READ type WRITE setType) + Q_PROPERTY(int index READ index WRITE setIndex) + Q_PROPERTY(QVariant defaultValue READ defaultValue WRITE setDefaultValue) + Q_PROPERTY(Types::Unit unit READ unit WRITE setUnit USER true) + Q_PROPERTY(QVariant minValue READ minValue WRITE setMinValue USER true) + Q_PROPERTY(QVariant maxValue READ maxValue WRITE setMaxValue USER true) + Q_PROPERTY(QVariantList possibleValues READ possibleValues WRITE setPossibleValues USER true) + public: + StateType(); StateType(const StateTypeId &id); StateTypeId id() const; @@ -83,14 +96,20 @@ private: Types::Unit m_unit = Types::UnitNone; bool m_cached = true; }; +Q_DECLARE_METATYPE(StateType) class StateTypes: public QList { + Q_GADGET + Q_PROPERTY(int count READ count) public: StateTypes() = default; StateTypes(const QList &other); + Q_INVOKABLE QVariant get(int index) const; + Q_INVOKABLE void put(const QVariant &variant); StateType findByName(const QString &name); StateType findById(const StateTypeId &id); }; +Q_DECLARE_METATYPE(StateTypes) #endif // STATETYPE_H diff --git a/libnymea/types/vendor.cpp b/libnymea/types/vendor.cpp index 1f0faa71..b0d63b84 100644 --- a/libnymea/types/vendor.cpp +++ b/libnymea/types/vendor.cpp @@ -33,6 +33,11 @@ #include "vendor.h" +Vendor::Vendor() +{ + +} + /*! Constructs an Vendor with the given \a id and the given \a name. */ Vendor::Vendor(const VendorId &id, const QString &name): m_id(id), @@ -90,6 +95,16 @@ Vendors::Vendors(const QList &other): QList(other) } +QVariant Vendors::get(int index) const +{ + return QVariant::fromValue(at(index)); +} + +void Vendors::put(const QVariant &variant) +{ + append(variant.value()); +} + Vendor Vendors::findById(const VendorId &vendorId) const { foreach (const Vendor &vendor, *this) { diff --git a/libnymea/types/vendor.h b/libnymea/types/vendor.h index cdbb32ae..d8c383ba 100644 --- a/libnymea/types/vendor.h +++ b/libnymea/types/vendor.h @@ -29,10 +29,17 @@ #include #include +#include class LIBNYMEA_EXPORT Vendor { + Q_GADGET + Q_PROPERTY(QUuid id READ id WRITE setId) + Q_PROPERTY(QString name READ name WRITE setName) + Q_PROPERTY(QString displayName READ displayName WRITE setDisplayName) + public: + Vendor(); Vendor(const VendorId &id, const QString &name = QString()); VendorId id() const; @@ -51,14 +58,19 @@ private: QString m_name; QString m_displayName; }; +Q_DECLARE_METATYPE(Vendor) class LIBNYMEA_EXPORT Vendors: public QList { + Q_GADGET + Q_PROPERTY(int count READ count) public: Vendors(); Vendors(const QList &other); - + Q_INVOKABLE QVariant get(int index) const; + Q_INVOKABLE void put(const QVariant &variant); Vendor findById(const VendorId &vendorId) const; }; +Q_DECLARE_METATYPE(Vendors) #endif // VENDOR_H diff --git a/libnymea/typeutils.h b/libnymea/typeutils.h index d211d9ff..a8439a69 100644 --- a/libnymea/typeutils.h +++ b/libnymea/typeutils.h @@ -32,7 +32,7 @@ #define DECLARE_TYPE_ID(type) class type##Id: public QUuid \ { \ public: \ - type##Id(const QString &uuid): QUuid(uuid) {} \ + type##Id(const QUuid &uuid): QUuid(uuid) {} \ type##Id(): QUuid() {} \ static type##Id create##type##Id() { return type##Id(QUuid::createUuid().toString()); } \ static type##Id fromUuid(const QUuid &uuid) { return type##Id(uuid.toString()); } \ diff --git a/nymea.pri b/nymea.pri index 54a66bca..094a6ce7 100644 --- a/nymea.pri +++ b/nymea.pri @@ -2,9 +2,9 @@ NYMEA_VERSION_STRING=$$system('dpkg-parsechangelog | sed -n -e "s/^Version: //p"') # define protocol versions -JSON_PROTOCOL_VERSION_MAJOR=3 -JSON_PROTOCOL_VERSION_MINOR=2 -LIBNYMEA_API_VERSION_MAJOR=3 +JSON_PROTOCOL_VERSION_MAJOR=4 +JSON_PROTOCOL_VERSION_MINOR=0 +LIBNYMEA_API_VERSION_MAJOR=4 LIBNYMEA_API_VERSION_MINOR=0 LIBNYMEA_API_VERSION_PATCH=0 diff --git a/plugins/mock/devicepluginmock.json b/plugins/mock/devicepluginmock.json index 94bc0551..cf305ab8 100644 --- a/plugins/mock/devicepluginmock.json +++ b/plugins/mock/devicepluginmock.json @@ -279,7 +279,7 @@ ], "actionTypes": [ { - "id": "e6a22f52-1818-46a7-9d15-5ca08b0612c", + "id": "07cd8d5f-2f65-4955-b1f9-05d7f4da488a", "name": "withParams", "displayName": "Mock Action 1 (with params)", "paramTypes": [ diff --git a/plugins/mock/plugininfo.h b/plugins/mock/plugininfo.h index 4930526d..afe1447d 100644 --- a/plugins/mock/plugininfo.h +++ b/plugins/mock/plugininfo.h @@ -9,7 +9,7 @@ #include #include -extern "C" const QString libnymea_api_version() { return QString("3.0.0");} +extern "C" const QString libnymea_api_version() { return QString("4.0.0");} Q_DECLARE_LOGGING_CATEGORY(dcMockDevice) Q_LOGGING_CATEGORY(dcMockDevice, "MockDevice") @@ -69,7 +69,7 @@ ParamTypeId mockDeviceAutoBoolValueEventBoolValueParamTypeId = ParamTypeId("{978 EventTypeId mockDeviceAutoEvent1EventTypeId = EventTypeId("{00f81fca-26f1-4a84-aa2b-4c6a3d953ec6}"); EventTypeId mockDeviceAutoEvent2EventTypeId = EventTypeId("{6e27922d-aa9d-44d1-b9b4-9faf31b6bd97}"); ParamTypeId mockDeviceAutoEvent2EventIntParamParamTypeId = ParamTypeId("{12ed5a15-96b4-4381-9d9c-a24875283d4f}"); -ActionTypeId mockDeviceAutoWithParamsActionTypeId = ActionTypeId("{00000000-0000-0000-0000-000000000000}"); +ActionTypeId mockDeviceAutoWithParamsActionTypeId = ActionTypeId("{07cd8d5f-2f65-4955-b1f9-05d7f4da488a}"); ParamTypeId mockDeviceAutoWithParamsActionMockActionParam1ParamTypeId = ParamTypeId("{b8126ba6-3a54-45a3-be4d-63feb0ddb77b}"); ParamTypeId mockDeviceAutoWithParamsActionMockActionParam2ParamTypeId = ParamTypeId("{df41ba71-e43b-4854-91d1-b19d8066d4f9}"); ActionTypeId mockDeviceAutoMockActionNoParmsActionTypeId = ActionTypeId("{ef518d53-50e2-4ca5-a4b1-e9a8b9309d44}"); @@ -348,7 +348,7 @@ const QString translations[] { //: The name of the ParamType (DeviceClass: mockInputType, Type: device, ID: {a8494faf-3a0f-4cf3-84b7-4b39148a838d}) QT_TRANSLATE_NOOP("mockDevice", "Mail address"), - //: The name of the ActionType ({00000000-0000-0000-0000-000000000000}) of DeviceClass mockDeviceAuto + //: The name of the ActionType ({07cd8d5f-2f65-4955-b1f9-05d7f4da488a}) of DeviceClass mockDeviceAuto QT_TRANSLATE_NOOP("mockDevice", "Mock Action 1 (with params)"), //: The name of the ActionType ({dea0f4e1-65e3-4981-8eaa-2701c53a9185}) of DeviceClass mock diff --git a/server/main.cpp b/server/main.cpp index ce69a08d..d9f1a39e 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -208,11 +208,11 @@ int main(int argc, char *argv[]) bool isWarning = debugArea.endsWith("Warnings"); debugArea.remove(QRegExp("^No")); debugArea.remove(QRegExp("Warnings$")); - if (loggingFilters.contains(debugArea) || loggingFiltersPlugins.contains(debugArea)) { - loggingRules.append(QString("%1.%2=%3").arg(debugArea).arg(isWarning ? "warning" : "debug").arg(enable ? "true": "false")); - } else { - qCWarning(dcApplication) << QCoreApplication::translate("nymea", "No such debug category:") << debugArea; - } + loggingRules.append(QString("%1.%2=%3").arg(debugArea).arg(isWarning ? "warning" : "debug").arg(enable ? "true": "false")); +// if (loggingFilters.contains(debugArea) || loggingFiltersPlugins.contains(debugArea)) { +// } else { +// qCWarning(dcApplication) << QCoreApplication::translate("nymea", "No such debug category:") << debugArea; +// } } // Finally set the rules for the logging diff --git a/tests/auto/actions/testactions.cpp b/tests/auto/actions/testactions.cpp index afb721d3..574561db 100644 --- a/tests/auto/actions/testactions.cpp +++ b/tests/auto/actions/testactions.cpp @@ -20,6 +20,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "nymeatestbase.h" +#include "devices/device.h" using namespace nymeaserver; @@ -75,7 +76,7 @@ void TestActions::executeAction() params.insert("params", actionParams); QVariant response = injectAndWait("Actions.ExecuteAction", params); qDebug() << "executeActionresponse" << response; - verifyDeviceError(response, error); + verifyError(response, "deviceError", enumValueName(error)); // Fetch action execution history from mock device QNetworkAccessManager nam; @@ -132,7 +133,7 @@ void TestActions::getActionType() params.insert("actionTypeId", actionTypeId.toString()); QVariant response = injectAndWait("Actions.GetActionType", params); - verifyDeviceError(response, error); + verifyError(response, "deviceError", enumValueName(error)); if (error == Device::DeviceErrorNoError) { QVERIFY2(ActionTypeId(response.toMap().value("params").toMap().value("actionType").toMap().value("id").toString()) == actionTypeId, "Didn't get a reply for the same actionTypeId as requested."); diff --git a/tests/auto/api.json b/tests/auto/api.json index b703132d..f78a8b5a 100644 --- a/tests/auto/api.json +++ b/tests/auto/api.json @@ -1,14 +1,315 @@ -3.2 +4.0 { + "enums": { + "BasicType": [ + "Uuid", + "String", + "StringList", + "Int", + "Uint", + "Double", + "Bool", + "Variant", + "Color", + "Time", + "Object" + ], + "BrowserIcon": [ + "BrowserIconNone", + "BrowserIconFolder", + "BrowserIconFile", + "BrowserIconMusic", + "BrowserIconVideo", + "BrowserIconPictures", + "BrowserIconApplication", + "BrowserIconDocument", + "BrowserIconPackage", + "BrowserIconFavorites" + ], + "CloudConnectionState": [ + "CloudConnectionStateDisabled", + "CloudConnectionStateUnconfigured", + "CloudConnectionStateConnecting", + "CloudConnectionStateConnected" + ], + "ConfigurationError": [ + "ConfigurationErrorNoError", + "ConfigurationErrorInvalidTimeZone", + "ConfigurationErrorInvalidStationName", + "ConfigurationErrorInvalidId", + "ConfigurationErrorInvalidPort", + "ConfigurationErrorInvalidHostAddress", + "ConfigurationErrorBluetoothHardwareNotAvailable", + "ConfigurationErrorInvalidCertificate" + ], + "CreateMethod": [ + "CreateMethodUser", + "CreateMethodAuto", + "CreateMethodDiscovery" + ], + "DeviceError": [ + "DeviceErrorNoError", + "DeviceErrorPluginNotFound", + "DeviceErrorVendorNotFound", + "DeviceErrorDeviceNotFound", + "DeviceErrorDeviceClassNotFound", + "DeviceErrorActionTypeNotFound", + "DeviceErrorStateTypeNotFound", + "DeviceErrorEventTypeNotFound", + "DeviceErrorDeviceDescriptorNotFound", + "DeviceErrorMissingParameter", + "DeviceErrorInvalidParameter", + "DeviceErrorSetupFailed", + "DeviceErrorDuplicateUuid", + "DeviceErrorCreationMethodNotSupported", + "DeviceErrorSetupMethodNotSupported", + "DeviceErrorHardwareNotAvailable", + "DeviceErrorHardwareFailure", + "DeviceErrorAuthenticationFailure", + "DeviceErrorDeviceInUse", + "DeviceErrorDeviceInRule", + "DeviceErrorDeviceIsChild", + "DeviceErrorPairingTransactionIdNotFound", + "DeviceErrorParameterNotWritable", + "DeviceErrorItemNotFound", + "DeviceErrorItemNotExecutable", + "DeviceErrorUnsupportedFeature", + "DeviceErrorTimeout" + ], + "InputType": [ + "InputTypeNone", + "InputTypeTextLine", + "InputTypeTextArea", + "InputTypePassword", + "InputTypeSearch", + "InputTypeMail", + "InputTypeIPv4Address", + "InputTypeIPv6Address", + "InputTypeUrl", + "InputTypeMacAddress" + ], + "LoggingError": [ + "LoggingErrorNoError", + "LoggingErrorLogEntryNotFound", + "LoggingErrorInvalidFilterParameter" + ], + "LoggingEventType": [ + "LoggingEventTypeTrigger", + "LoggingEventTypeActiveChange", + "LoggingEventTypeEnabledChange", + "LoggingEventTypeActionsExecuted", + "LoggingEventTypeExitActionsExecuted" + ], + "LoggingLevel": [ + "LoggingLevelInfo", + "LoggingLevelAlert" + ], + "LoggingSource": [ + "LoggingSourceSystem", + "LoggingSourceEvents", + "LoggingSourceActions", + "LoggingSourceStates", + "LoggingSourceRules", + "LoggingSourceBrowserActions" + ], + "MediaBrowserIcon": [ + "MediaBrowserIconNone", + "MediaBrowserIconPlaylist", + "MediaBrowserIconRecentlyPlayed", + "MediaBrowserIconLibrary", + "MediaBrowserIconMusicLibrary", + "MediaBrowserIconVideoLibrary", + "MediaBrowserIconPictureLibrary", + "MediaBrowserIconDisk", + "MediaBrowserIconUSB", + "MediaBrowserIconNetwork", + "MediaBrowserIconAux", + "MediaBrowserIconSpotify", + "MediaBrowserIconAmazon", + "MediaBrowserIconTuneIn", + "MediaBrowserIconSiriusXM", + "MediaBrowserIconVTuner", + "MediaBrowserIconTidal", + "MediaBrowserIconAirable", + "MediaBrowserIconDeezer", + "MediaBrowserIconNapster", + "MediaBrowserIconSoundCloud" + ], + "NetworkDeviceState": [ + "NetworkDeviceStateUnknown", + "NetworkDeviceStateUnmanaged", + "NetworkDeviceStateUnavailable", + "NetworkDeviceStateDisconnected", + "NetworkDeviceStatePrepare", + "NetworkDeviceStateConfig", + "NetworkDeviceStateNeedAuth", + "NetworkDeviceStateIpConfig", + "NetworkDeviceStateIpCheck", + "NetworkDeviceStateSecondaries", + "NetworkDeviceStateActivated", + "NetworkDeviceStateDeactivating", + "NetworkDeviceStateFailed" + ], + "NetworkManagerError": [ + "NetworkManagerErrorNoError", + "NetworkManagerErrorUnknownError", + "NetworkManagerErrorWirelessNotAvailable", + "NetworkManagerErrorAccessPointNotFound", + "NetworkManagerErrorNetworkInterfaceNotFound", + "NetworkManagerErrorInvalidNetworkDeviceType", + "NetworkManagerErrorWirelessNetworkingDisabled", + "NetworkManagerErrorWirelessConnectionFailed", + "NetworkManagerErrorNetworkingDisabled", + "NetworkManagerErrorNetworkManagerNotAvailable" + ], + "NetworkManagerState": [ + "NetworkManagerStateUnknown", + "NetworkManagerStateAsleep", + "NetworkManagerStateDisconnected", + "NetworkManagerStateDisconnecting", + "NetworkManagerStateConnecting", + "NetworkManagerStateConnectedLocal", + "NetworkManagerStateConnectedSite", + "NetworkManagerStateConnectedGlobal" + ], + "RemovePolicy": [ + "RemovePolicyCascade", + "RemovePolicyUpdate" + ], + "RepeatingMode": [ + "RepeatingModeNone", + "RepeatingModeHourly", + "RepeatingModeDaily", + "RepeatingModeWeekly", + "RepeatingModeMonthly", + "RepeatingModeYearly" + ], + "RuleError": [ + "RuleErrorNoError", + "RuleErrorInvalidRuleId", + "RuleErrorRuleNotFound", + "RuleErrorDeviceNotFound", + "RuleErrorEventTypeNotFound", + "RuleErrorStateTypeNotFound", + "RuleErrorActionTypeNotFound", + "RuleErrorInvalidParameter", + "RuleErrorInvalidRuleFormat", + "RuleErrorMissingParameter", + "RuleErrorInvalidRuleActionParameter", + "RuleErrorInvalidStateEvaluatorValue", + "RuleErrorTypesNotMatching", + "RuleErrorNotExecutable", + "RuleErrorInvalidTimeDescriptor", + "RuleErrorInvalidRepeatingOption", + "RuleErrorInvalidCalendarItem", + "RuleErrorInvalidTimeEventItem", + "RuleErrorContainsEventBasesAction", + "RuleErrorNoExitActions", + "RuleErrorInterfaceNotFound" + ], + "SetupMethod": [ + "SetupMethodJustAdd", + "SetupMethodDisplayPin", + "SetupMethodEnterPin", + "SetupMethodPushButton", + "SetupMethodUserAndPassword", + "SetupMethodOAuth" + ], + "StateOperator": [ + "StateOperatorAnd", + "StateOperatorOr" + ], + "TagError": [ + "TagErrorNoError", + "TagErrorDeviceNotFound", + "TagErrorRuleNotFound", + "TagErrorTagNotFound" + ], + "Unit": [ + "UnitNone", + "UnitSeconds", + "UnitMinutes", + "UnitHours", + "UnitUnixTime", + "UnitMeterPerSecond", + "UnitKiloMeterPerHour", + "UnitDegree", + "UnitRadiant", + "UnitDegreeCelsius", + "UnitDegreeKelvin", + "UnitMired", + "UnitMilliBar", + "UnitBar", + "UnitPascal", + "UnitHectoPascal", + "UnitAtmosphere", + "UnitLumen", + "UnitLux", + "UnitCandela", + "UnitMilliMeter", + "UnitCentiMeter", + "UnitMeter", + "UnitKiloMeter", + "UnitGram", + "UnitKiloGram", + "UnitDezibel", + "UnitBpm", + "UnitKiloByte", + "UnitMegaByte", + "UnitGigaByte", + "UnitTeraByte", + "UnitMilliWatt", + "UnitWatt", + "UnitKiloWatt", + "UnitKiloWattHour", + "UnitEuroPerMegaWattHour", + "UnitEuroCentPerKiloWattHour", + "UnitPercentage", + "UnitPartsPerMillion", + "UnitEuro", + "UnitDollar", + "UnitHertz", + "UnitAmpere", + "UnitMilliAmpere", + "UnitVolt", + "UnitMilliVolt", + "UnitVoltAmpere", + "UnitVoltAmpereReactive", + "UnitAmpereHour", + "UnitMicroSiemensPerCentimeter", + "UnitDuration" + ], + "UserError": [ + "UserErrorNoError", + "UserErrorBackendError", + "UserErrorInvalidUserId", + "UserErrorDuplicateUserId", + "UserErrorBadPassword", + "UserErrorTokenNotFound", + "UserErrorPermissionDenied" + ], + "ValueOperator": [ + "ValueOperatorEquals", + "ValueOperatorNotEquals", + "ValueOperatorLess", + "ValueOperatorGreater", + "ValueOperatorLessOrEqual", + "ValueOperatorGreaterOrEqual" + ] + }, + "flags": { + "CreateMethods": [ + "$ref:CreateMethod" + ] + }, "methods": { "Actions.ExecuteAction": { + "deprecated": "Please use Devices.ExecuteAction instead.", "description": "Execute a single action.", "params": { "actionTypeId": "Uuid", "deviceId": "Uuid", - "o:params": [ - "$ref:Param" - ] + "o:params": "$ref:ParamList" }, "returns": { "deviceError": "$ref:DeviceError", @@ -16,6 +317,7 @@ } }, "Actions.ExecuteBrowserItem": { + "deprecated": "Please use Devices.ExecuteBrowserItem instead.", "description": "Execute the item identified by itemId on the given device.", "params": { "deviceId": "Uuid", @@ -26,35 +328,27 @@ } }, "Actions.ExecuteBrowserItemAction": { + "deprecated": "Please use Devices.ExecuteBrowserItem instead.", "description": "Execute the action for the browser item identified by actionTypeId and the itemId on the given device.", "params": { "actionTypeId": "Uuid", "deviceId": "Uuid", "itemId": "String", - "o:params": [ - "$ref:Param" - ] + "o:params": "$ref:ParamList" }, "returns": { "deviceError": "$ref:DeviceError" } }, "Actions.GetActionType": { - "description": "Get the ActionType for the given ActionTypeId", + "deprecated": "Please use the Devices namespace instead.", + "description": "Get the ActionType for the given ActionTypeId.", "params": { "actionTypeId": "Uuid" }, "returns": { "deviceError": "$ref:DeviceError", - "o:actionType": { - "displayName": "String", - "id": "Uuid", - "index": "Int", - "name": "String", - "paramTypes": [ - "$ref:ParamType" - ] - } + "o:actionType": "$ref:ActionType" } }, "Configuration.DeleteMqttPolicy": { @@ -265,9 +559,7 @@ "deviceClassId": "Uuid", "name": "String", "o:deviceDescriptorId": "Uuid", - "o:deviceParams": [ - "$ref:Param" - ] + "o:deviceParams": "$ref:ParamList" }, "returns": { "deviceError": "$ref:DeviceError", @@ -311,15 +603,47 @@ "deviceError": "$ref:DeviceError" } }, + "Devices.ExecuteAction": { + "description": "Execute a single action.", + "params": { + "actionTypeId": "Uuid", + "deviceId": "Uuid", + "o:params": "$ref:ParamList" + }, + "returns": { + "deviceError": "$ref:DeviceError", + "o:displayMessage": "String" + } + }, + "Devices.ExecuteBrowserItem": { + "description": "Execute the item identified by itemId on the given device.", + "params": { + "deviceId": "Uuid", + "itemId": "String" + }, + "returns": { + "deviceError": "$ref:DeviceError" + } + }, + "Devices.ExecuteBrowserItemAction": { + "description": "Execute the action for the browser item identified by actionTypeId and the itemId on the given device.", + "params": { + "actionTypeId": "Uuid", + "deviceId": "Uuid", + "itemId": "String", + "o:params": "$ref:ParamList" + }, + "returns": { + "deviceError": "$ref:DeviceError" + } + }, "Devices.GetActionTypes": { "description": "Get action types for a specified deviceClassId.", "params": { "deviceClassId": "Uuid" }, "returns": { - "actionTypes": [ - "$ref:ActionType" - ] + "actionTypes": "$ref:ActionTypes" } }, "Devices.GetBrowserItem": { @@ -339,24 +663,18 @@ "o:deviceId": "Uuid" }, "returns": { - "devices": [ - "$ref:Device" - ] + "devices": "$ref:Devices" } }, "Devices.GetDiscoveredDevices": { "description": "Performs a device discovery and returns the results. This function may take a while to return. Note that this method will include all the found devices, that is, including devices that may already have been added. Those devices will have deviceId set to the device id of the already added device. Such results may be used to reconfigure existing devices and might be filtered in cases where only unknown devices are of interest.", "params": { "deviceClassId": "Uuid", - "o:discoveryParams": [ - "$ref:Param" - ] + "o:discoveryParams": "$ref:ParamList" }, "returns": { "deviceError": "$ref:DeviceError", - "o:deviceDescriptors": [ - "$ref:DeviceDescriptor" - ], + "o:deviceDescriptors": "$ref:DeviceDescriptors", "o:displayMessage": "String" } }, @@ -366,9 +684,7 @@ "deviceClassId": "Uuid" }, "returns": { - "eventTypes": [ - "$ref:EventType" - ] + "eventTypes": "$ref:EventTypes" } }, "Devices.GetPluginConfiguration": { @@ -378,9 +694,7 @@ }, "returns": { "deviceError": "$ref:DeviceError", - "o:configuration": [ - "$ref:Param" - ] + "o:configuration": "$ref:ParamList" } }, "Devices.GetPlugins": { @@ -388,9 +702,7 @@ "params": { }, "returns": { - "plugins": [ - "$ref:Plugin" - ] + "plugins": "$ref:DevicePlugins" } }, "Devices.GetStateTypes": { @@ -399,9 +711,7 @@ "deviceClassId": "Uuid" }, "returns": { - "stateTypes": [ - "$ref:StateType" - ] + "stateTypes": "$ref:StateTypes" } }, "Devices.GetStateValue": { @@ -422,12 +732,7 @@ }, "returns": { "deviceError": "$ref:DeviceError", - "o:values": [ - { - "stateTypeId": "Uuid", - "value": "Variant" - } - ] + "o:values": "$ref:States" } }, "Devices.GetSupportedDevices": { @@ -436,9 +741,7 @@ "o:vendorId": "Uuid" }, "returns": { - "deviceClasses": [ - "$ref:DeviceClass" - ] + "deviceClasses": "$ref:DeviceClasses" } }, "Devices.GetSupportedVendors": { @@ -446,9 +749,7 @@ "params": { }, "returns": { - "vendors": [ - "$ref:Vendor" - ] + "vendors": "$ref:Vendors" } }, "Devices.PairDevice": { @@ -457,9 +758,7 @@ "o:deviceClassId": "Uuid", "o:deviceDescriptorId": "Uuid", "o:deviceId": "Uuid", - "o:deviceParams": [ - "$ref:Param" - ], + "o:deviceParams": "$ref:ParamList", "o:name": "String" }, "returns": { @@ -476,9 +775,7 @@ "params": { "o:deviceDescriptorId": "Uuid", "o:deviceId": "Uuid", - "o:deviceParams": [ - "$ref:Param" - ] + "o:deviceParams": "$ref:ParamList" }, "returns": { "deviceError": "$ref:DeviceError", @@ -508,9 +805,7 @@ "description": "Change the settings of a device.", "params": { "deviceId": "Uuid", - "settings": [ - "$ref:Param" - ] + "settings": "$ref:ParamList" }, "returns": { "deviceError": "$ref:DeviceError" @@ -519,9 +814,7 @@ "Devices.SetPluginConfiguration": { "description": "Set a plugin's params.", "params": { - "configuration": [ - "$ref:Param" - ], + "configuration": "$ref:ParamList", "pluginId": "Uuid" }, "returns": { @@ -529,6 +822,7 @@ } }, "Events.GetEventType": { + "deprecated": "Please use the Devices namespace instead.", "description": "Get the EventType for the given eventTypeId.", "params": { "eventTypeId": "Uuid" @@ -571,6 +865,9 @@ "language": "String", "locale": "String", "name": "String", + "o:experiences": [ + "$ref:Experience" + ], "protocol version": "String", "pushButtonAuthAvailable": "Bool", "server": "String", @@ -630,15 +927,11 @@ "description": "Enable/Disable notifications for this connections. Either \"enabled\" or \"namespaces\" needs to be given but not both of them. The boolean based \"enabled\" parameter will enable/disable all notifications at once. If instead the list-based \"namespaces\" parameter is provided, all given namespaceswill be enabled, the others will be disabled. The return value of \"success\" will indicate success of the operation. The \"enabled\" property in the return value is deprecated and used for legacy compatibilty only. It will be set to true if at least one namespace has been enabled.", "params": { "o:enabled": "Bool", - "o:namespaces": [ - "$ref:Namespace" - ] + "o:namespaces": "StringList" }, "returns": { "enabled": "Bool", - "namespaces": [ - "$ref:Namespace" - ] + "namespaces": "StringList" } }, "JSONRPC.SetupCloudConnection": { @@ -717,9 +1010,7 @@ "returns": { "count": "Int", "loggingError": "$ref:LoggingError", - "o:logEntries": [ - "$ref:LogEntry" - ], + "o:logEntries": "$ref:LogEntries", "offset": "Int" } }, @@ -933,6 +1224,7 @@ } }, "States.GetStateType": { + "deprecated": "Please use the Devices namespace instead.", "description": "Get the StateType for the given stateTypeId.", "params": { "stateTypeId": "Uuid" @@ -974,9 +1266,7 @@ "params": { }, "returns": { - "packages": [ - "$ref:Package" - ] + "packages": "$ref:Packages" } }, "System.GetRepositories": { @@ -984,9 +1274,7 @@ "params": { }, "returns": { - "repositories": [ - "$ref:Repository" - ] + "repositories": "$ref:Repositories" } }, "System.GetUpdateStatus": { @@ -1065,9 +1353,7 @@ "o:tagId": "String" }, "returns": { - "o:tags": [ - "$ref:Tag" - ], + "o:tags": "$ref:Tags", "tagError": "$ref:TagError" } }, @@ -1195,12 +1481,16 @@ "value": "Variant" } }, + "Devices.EventTriggered": { + "description": "Emitted whenever an Event is triggered.", + "params": { + "event": "$ref:Event" + } + }, "Devices.PluginConfigurationChanged": { "description": "Emitted whenever a plugin's configuration is changed.", "params": { - "configuration": [ - "$ref:Param" - ], + "configuration": "$ref:ParamList", "pluginId": "Uuid" } }, @@ -1213,6 +1503,7 @@ } }, "Events.EventTriggered": { + "deprecated": "Please use Devices.EventTriggered instead.", "description": "Emitted whenever an Event is triggered.", "params": { "event": "$ref:Event" @@ -1388,43 +1679,17 @@ "Action": { "actionTypeId": "Uuid", "deviceId": "Uuid", - "o:params": [ - "$ref:Param" - ] + "o:params": "$ref:ParamList" }, "ActionType": { "displayName": "String", - "id": "Uuid", "index": "Int", "name": "String", - "paramTypes": [ - "$ref:ParamType" - ] + "paramTypes": "$ref:ParamTypes", + "r:id": "Uuid" }, - "BasicType": [ - "Uuid", - "String", - "StringList", - "Int", - "Uint", - "Double", - "Bool", - "Variant", - "Color", - "Time", - "Object" - ], - "BrowserIcon": [ - "BrowserIconNone", - "BrowserIconFolder", - "BrowserIconFile", - "BrowserIconMusic", - "BrowserIconVideo", - "BrowserIconPictures", - "BrowserIconApplication", - "BrowserIconDocument", - "BrowserIconPackage", - "BrowserIconFavorites" + "ActionTypes": [ + "$ref:ActionType" ], "BrowserItem": { "actionTypeIds": [ @@ -1446,216 +1711,105 @@ "o:repeating": "$ref:RepeatingOption", "o:startTime": "Time" }, - "CloudConnectionState": [ - "CloudConnectionStateDisabled", - "CloudConnectionStateUnconfigured", - "CloudConnectionStateConnecting", - "CloudConnectionStateConnected" - ], - "ConfigurationError": [ - "ConfigurationErrorNoError", - "ConfigurationErrorInvalidTimeZone", - "ConfigurationErrorInvalidStationName", - "ConfigurationErrorInvalidId", - "ConfigurationErrorInvalidPort", - "ConfigurationErrorInvalidHostAddress", - "ConfigurationErrorBluetoothHardwareNotAvailable", - "ConfigurationErrorInvalidCertificate" - ], - "CreateMethod": [ - "CreateMethodUser", - "CreateMethodAuto", - "CreateMethodDiscovery" + "CalendarItems": [ + "$ref:CalendarItem" ], "Device": { - "deviceClassId": "Uuid", - "id": "Uuid", "name": "String", "o:parentId": "Uuid", - "params": [ - "$ref:Param" - ], - "settings": [ - "$ref:Param" - ], + "params": "$ref:ParamList", + "r:deviceClassId": "Uuid", + "r:id": "Uuid", + "settings": "$ref:ParamList", "setupComplete": "Bool", - "states": [ - { - "stateTypeId": "Uuid", - "value": "Variant" - } - ] + "states": "$ref:States" }, "DeviceClass": { - "actionTypes": [ - "$ref:ActionType" - ], - "browsable": "Bool", - "browserItemActionTypes": [ - "$ref:ActionType" - ], - "createMethods": [ - "$ref:CreateMethod" - ], - "discoveryParamTypes": [ - "$ref:ParamType" - ], - "displayName": "String", - "eventTypes": [ - "$ref:EventType" - ], - "id": "Uuid", - "interfaces": [ - "String" - ], - "name": "String", - "paramTypes": [ - "$ref:ParamType" - ], - "pluginId": "Uuid", - "settingsTypes": [ - "$ref:ParamType" - ], - "setupMethod": "$ref:SetupMethod", - "stateTypes": [ - "$ref:StateType" - ], - "vendorId": "Uuid" + "r:actionTypes": "$ref:ActionTypes", + "r:browsable": "Bool", + "r:browserItemActionTypes": "$ref:ActionTypes", + "r:createMethods": "$ref:CreateMethods", + "r:discoveryParamTypes": "$ref:ParamTypes", + "r:displayName": "String", + "r:eventTypes": "$ref:EventTypes", + "r:id": "Uuid", + "r:interfaces": "StringList", + "r:name": "String", + "r:paramTypes": "$ref:ParamTypes", + "r:pluginId": "Uuid", + "r:settingsTypes": "$ref:ParamTypes", + "r:setupMethod": "$ref:SetupMethod", + "r:stateTypes": "$ref:StateTypes", + "r:vendorId": "Uuid" }, + "DeviceClasses": [ + "$ref:DeviceClass" + ], "DeviceDescriptor": { - "description": "String", - "deviceId": "Uuid", - "deviceParams": [ - "$ref:Param" - ], - "id": "Uuid", - "title": "String" + "r:description": "String", + "r:deviceParams": "$ref:ParamList", + "r:id": "Uuid", + "r:o:deviceId": "Uuid", + "r:title": "String" }, - "DeviceError": [ - "DeviceErrorNoError", - "DeviceErrorPluginNotFound", - "DeviceErrorVendorNotFound", - "DeviceErrorDeviceNotFound", - "DeviceErrorDeviceClassNotFound", - "DeviceErrorActionTypeNotFound", - "DeviceErrorStateTypeNotFound", - "DeviceErrorEventTypeNotFound", - "DeviceErrorDeviceDescriptorNotFound", - "DeviceErrorMissingParameter", - "DeviceErrorInvalidParameter", - "DeviceErrorSetupFailed", - "DeviceErrorDuplicateUuid", - "DeviceErrorCreationMethodNotSupported", - "DeviceErrorSetupMethodNotSupported", - "DeviceErrorHardwareNotAvailable", - "DeviceErrorHardwareFailure", - "DeviceErrorAuthenticationFailure", - "DeviceErrorDeviceInUse", - "DeviceErrorDeviceInRule", - "DeviceErrorDeviceIsChild", - "DeviceErrorPairingTransactionIdNotFound", - "DeviceErrorParameterNotWritable", - "DeviceErrorItemNotFound", - "DeviceErrorItemNotExecutable", - "DeviceErrorUnsupportedFeature", - "DeviceErrorTimeout" + "DeviceDescriptors": [ + "$ref:DeviceDescriptor" + ], + "DevicePlugin": { + "r:displayName": "String", + "r:id": "Uuid", + "r:name": "String", + "r:paramTypes": "$ref:ParamTypes" + }, + "DevicePlugins": [ + "$ref:DevicePlugin" + ], + "Devices": [ + "$ref:Device" ], "Event": { - "deviceId": "Uuid", - "eventTypeId": "Uuid", - "o:params": [ - "$ref:Param" - ] + "r:deviceId": "Uuid", + "r:eventTypeId": "Uuid", + "r:params": "$ref:ParamList" }, "EventDescriptor": { "o:deviceId": "Uuid", "o:eventTypeId": "Uuid", "o:interface": "String", "o:interfaceEvent": "String", - "o:paramDescriptors": [ - "$ref:ParamDescriptor" - ] + "o:paramDescriptors": "$ref:ParamDescriptors" }, + "EventDescriptors": [ + "$ref:EventDescriptor" + ], "EventType": { "displayName": "String", - "id": "Uuid", - "index": "Int", "name": "String", - "paramTypes": [ - "$ref:ParamType" - ] + "paramTypes": "$ref:ParamTypes", + "r:id": "Uuid", + "r:index": "Int" }, - "InputType": [ - "InputTypeNone", - "InputTypeTextLine", - "InputTypeTextArea", - "InputTypePassword", - "InputTypeSearch", - "InputTypeMail", - "InputTypeIPv4Address", - "InputTypeIPv6Address", - "InputTypeUrl", - "InputTypeMacAddress" + "EventTypes": [ + "$ref:EventType" + ], + "Experience": { + "name": "String", + "version": "String" + }, + "LogEntries": [ + "$ref:LogEntry" ], "LogEntry": { - "loggingLevel": "$ref:LoggingLevel", - "o:active": "Bool", - "o:deviceId": "Uuid", - "o:errorCode": "String", - "o:eventType": "$ref:LoggingEventType", - "o:itemId": "String", - "o:typeId": "Uuid", - "o:value": "String", - "source": "$ref:LoggingSource", - "timestamp": "Int" + "r:loggingLevel": "$ref:LoggingLevel", + "r:o:active": "Bool", + "r:o:deviceId": "Uuid", + "r:o:errorCode": "String", + "r:o:eventType": "$ref:LoggingEventType", + "r:o:typeId": "Uuid", + "r:o:value": "Variant", + "r:source": "$ref:LoggingSource", + "r:timestamp": "Uint" }, - "LoggingError": [ - "LoggingErrorNoError", - "LoggingErrorLogEntryNotFound", - "LoggingErrorInvalidFilterParameter" - ], - "LoggingEventType": [ - "LoggingEventTypeTrigger", - "LoggingEventTypeActiveChange", - "LoggingEventTypeEnabledChange", - "LoggingEventTypeActionsExecuted", - "LoggingEventTypeExitActionsExecuted" - ], - "LoggingLevel": [ - "LoggingLevelInfo", - "LoggingLevelAlert" - ], - "LoggingSource": [ - "LoggingSourceSystem", - "LoggingSourceEvents", - "LoggingSourceActions", - "LoggingSourceStates", - "LoggingSourceRules", - "LoggingSourceBrowserActions" - ], - "MediaBrowserIcon": [ - "MediaBrowserIconNone", - "MediaBrowserIconPlaylist", - "MediaBrowserIconRecentlyPlayed", - "MediaBrowserIconLibrary", - "MediaBrowserIconMusicLibrary", - "MediaBrowserIconVideoLibrary", - "MediaBrowserIconPictureLibrary", - "MediaBrowserIconDisk", - "MediaBrowserIconUSB", - "MediaBrowserIconNetwork", - "MediaBrowserIconAux", - "MediaBrowserIconSpotify", - "MediaBrowserIconAmazon", - "MediaBrowserIconTuneIn", - "MediaBrowserIconSiriusXM", - "MediaBrowserIconVTuner", - "MediaBrowserIconTidal", - "MediaBrowserIconAirable", - "MediaBrowserIconDeezer", - "MediaBrowserIconNapster", - "MediaBrowserIconSoundCloud" - ], "MqttPolicy": { "allowedPublishTopicFilters": "StringList", "allowedSubscribeTopicFilters": "StringList", @@ -1663,80 +1817,38 @@ "password": "String", "username": "String" }, - "Namespace": [ - "Actions", - "Configuration", - "Devices", - "Events", - "JSONRPC", - "Logging", - "NetworkManager", - "Rules", - "States", - "System", - "Tags" - ], - "NetworkDeviceState": [ - "NetworkDeviceStateUnknown", - "NetworkDeviceStateUnmanaged", - "NetworkDeviceStateUnavailable", - "NetworkDeviceStateDisconnected", - "NetworkDeviceStatePrepare", - "NetworkDeviceStateConfig", - "NetworkDeviceStateNeedAuth", - "NetworkDeviceStateIpConfig", - "NetworkDeviceStateIpCheck", - "NetworkDeviceStateSecondaries", - "NetworkDeviceStateActivated", - "NetworkDeviceStateDeactivating", - "NetworkDeviceStateFailed" - ], - "NetworkManagerError": [ - "NetworkManagerErrorNoError", - "NetworkManagerErrorUnknownError", - "NetworkManagerErrorWirelessNotAvailable", - "NetworkManagerErrorAccessPointNotFound", - "NetworkManagerErrorNetworkInterfaceNotFound", - "NetworkManagerErrorInvalidNetworkDeviceType", - "NetworkManagerErrorWirelessNetworkingDisabled", - "NetworkManagerErrorWirelessConnectionFailed", - "NetworkManagerErrorNetworkingDisabled", - "NetworkManagerErrorNetworkManagerNotAvailable" - ], - "NetworkManagerState": [ - "NetworkManagerStateUnknown", - "NetworkManagerStateAsleep", - "NetworkManagerStateDisconnected", - "NetworkManagerStateDisconnecting", - "NetworkManagerStateConnecting", - "NetworkManagerStateConnectedLocal", - "NetworkManagerStateConnectedSite", - "NetworkManagerStateConnectedGlobal" - ], "Package": { - "canRemove": "Bool", - "candidateVersion": "String", - "changelog": "String", - "displayName": "String", - "id": "String", - "installedVersion": "String", - "rollbackAvailable": "Bool", - "summary": "String", - "updateAvailable": "Bool" + "r:canRemove": "Bool", + "r:candidateVersion": "String", + "r:changelog": "String", + "r:displayName": "String", + "r:id": "String", + "r:installedVersion": "String", + "r:rollbackAvailable": "Bool", + "r:summary": "String", + "r:updateAvailable": "Bool" }, + "Packages": [ + "$ref:Package" + ], "Param": { - "paramTypeId": "Uuid", - "value": "$ref:BasicType" + "o:paramTypeId": "Uuid", + "value": "Variant" }, "ParamDescriptor": { - "o:paramName": "Uuid", + "o:paramName": "String", "o:paramTypeId": "Uuid", "operator": "$ref:ValueOperator", - "value": "$ref:BasicType" + "value": "Variant" }, + "ParamDescriptors": [ + "$ref:ParamDescriptor" + ], + "ParamList": [ + "$ref:Param" + ], "ParamType": { "displayName": "String", - "id": "Uuid", "index": "Int", "name": "String", "o:allowedValues": [ @@ -1748,27 +1860,11 @@ "o:minValue": "Variant", "o:readOnly": "Bool", "o:unit": "$ref:Unit", + "r:id": "Uuid", "type": "$ref:BasicType" }, - "Plugin": { - "displayName": "String", - "id": "Uuid", - "name": "String", - "paramTypes": [ - "$ref:ParamType" - ] - }, - "RemovePolicy": [ - "RemovePolicyCascade", - "RemovePolicyUpdate" - ], - "RepeatingMode": [ - "RepeatingModeNone", - "RepeatingModeHourly", - "RepeatingModeDaily", - "RepeatingModeWeekly", - "RepeatingModeMonthly", - "RepeatingModeYearly" + "ParamTypes": [ + "$ref:ParamType" ], "RepeatingOption": { "mode": "$ref:RepeatingMode", @@ -1779,28 +1875,25 @@ "Int" ] }, + "Repositories": [ + "$ref:Repository" + ], "Repository": { - "displayName": "String", "enabled": "Bool", - "id": "String" + "r:displayName": "String", + "r:id": "String" }, "Rule": { - "actions": [ - "$ref:RuleAction" - ], - "active": "Bool", - "enabled": "Bool", - "eventDescriptors": [ - "$ref:EventDescriptor" - ], - "executable": "Bool", - "exitActions": [ - "$ref:RuleAction" - ], - "id": "Uuid", + "actions": "$ref:RuleActions", "name": "String", - "stateEvaluator": "$ref:StateEvaluator", - "timeDescriptor": "$ref:TimeDescriptor" + "o:enabled": "Bool", + "o:eventDescriptors": "$ref:EventDescriptors", + "o:executable": "Bool", + "o:exitActions": "$ref:RuleActions", + "o:id": "Uuid", + "o:stateEvaluator": "$ref:StateEvaluator", + "o:timeDescriptor": "$ref:TimeDescriptor", + "r:o:active": "Bool" }, "RuleAction": { "o:actionTypeId": "Uuid", @@ -1808,9 +1901,7 @@ "o:deviceId": "Uuid", "o:interface": "String", "o:interfaceAction": "String", - "o:ruleActionParams": [ - "$ref:RuleActionParam" - ] + "o:ruleActionParams": "$ref:RuleActionParams" }, "RuleActionParam": { "o:eventParamTypeId": "Uuid", @@ -1819,8 +1910,14 @@ "o:paramTypeId": "Uuid", "o:stateDeviceId": "Uuid", "o:stateTypeId": "Uuid", - "o:value": "$ref:BasicType" + "o:value": "Variant" }, + "RuleActionParams": [ + "$ref:RuleActionParam" + ], + "RuleActions": [ + "$ref:RuleAction" + ], "RuleDescription": { "active": "Bool", "enabled": "Bool", @@ -1828,28 +1925,8 @@ "id": "Uuid", "name": "String" }, - "RuleError": [ - "RuleErrorNoError", - "RuleErrorInvalidRuleId", - "RuleErrorRuleNotFound", - "RuleErrorDeviceNotFound", - "RuleErrorEventTypeNotFound", - "RuleErrorStateTypeNotFound", - "RuleErrorActionTypeNotFound", - "RuleErrorInvalidParameter", - "RuleErrorInvalidRuleFormat", - "RuleErrorMissingParameter", - "RuleErrorInvalidRuleActionParameter", - "RuleErrorInvalidStateEvaluatorValue", - "RuleErrorTypesNotMatching", - "RuleErrorNotExecutable", - "RuleErrorInvalidTimeDescriptor", - "RuleErrorInvalidRepeatingOption", - "RuleErrorInvalidCalendarItem", - "RuleErrorInvalidTimeEventItem", - "RuleErrorContainsEventBasesAction", - "RuleErrorNoExitActions", - "RuleErrorInterfaceNotFound" + "Rules": [ + "$ref:Rule" ], "ServerConfiguration": { "address": "String", @@ -1858,18 +1935,9 @@ "port": "Uint", "sslEnabled": "Bool" }, - "SetupMethod": [ - "SetupMethodJustAdd", - "SetupMethodDisplayPin", - "SetupMethodEnterPin", - "SetupMethodPushButton", - "SetupMethodUserAndPassword", - "SetupMethodOAuth" - ], "State": { - "deviceId": "Uuid", - "stateTypeId": "Uuid", - "value": "Variant" + "r:stateTypeId": "Uuid", + "r:value": "Variant" }, "StateDescriptor": { "o:deviceId": "Uuid", @@ -1880,20 +1948,16 @@ "value": "Variant" }, "StateEvaluator": { - "o:childEvaluators": [ - "$ref:StateEvaluator" - ], + "o:childEvaluators": "$ref:StateEvaluators", "o:operator": "$ref:StateOperator", "o:stateDescriptor": "$ref:StateDescriptor" }, - "StateOperator": [ - "StateOperatorAnd", - "StateOperatorOr" + "StateEvaluators": [ + "$ref:StateEvaluator" ], "StateType": { "defaultValue": "Variant", "displayName": "String", - "id": "Uuid", "index": "Int", "name": "String", "o:maxValue": "Variant", @@ -1902,8 +1966,15 @@ "Variant" ], "o:unit": "$ref:Unit", + "r:id": "Uuid", "type": "$ref:BasicType" }, + "StateTypes": [ + "$ref:StateType" + ], + "States": [ + "$ref:State" + ], "Tag": { "appId": "String", "o:deviceId": "Uuid", @@ -1911,127 +1982,56 @@ "o:value": "String", "tagId": "String" }, - "TagError": [ - "TagErrorNoError", - "TagErrorDeviceNotFound", - "TagErrorRuleNotFound", - "TagErrorTagNotFound" + "Tags": [ + "$ref:Tag" ], "TimeDescriptor": { - "o:calendarItems": [ - "$ref:CalendarItem" - ], - "o:timeEventItems": [ - "$ref:TimeEventItem" - ] + "o:calendarItems": "$ref:CalendarItems", + "o:timeEventItems": "$ref:TimeEventItems" }, "TimeEventItem": { "o:datetime": "Uint", "o:repeating": "$ref:RepeatingOption", "o:time": "Time" }, + "TimeEventItems": [ + "$ref:TimeEventItem" + ], "TokenInfo": { - "creationTime": "Uint", - "deviceName": "String", - "id": "Uuid", - "userName": "String" + "r:creationTime": "Uint", + "r:deviveName": "String", + "r:id": "Uuid", + "r:username": "String" }, - "Unit": [ - "UnitNone", - "UnitSeconds", - "UnitMinutes", - "UnitHours", - "UnitUnixTime", - "UnitMeterPerSecond", - "UnitKiloMeterPerHour", - "UnitDegree", - "UnitRadiant", - "UnitDegreeCelsius", - "UnitDegreeKelvin", - "UnitMired", - "UnitMilliBar", - "UnitBar", - "UnitPascal", - "UnitHectoPascal", - "UnitAtmosphere", - "UnitLumen", - "UnitLux", - "UnitCandela", - "UnitMilliMeter", - "UnitCentiMeter", - "UnitMeter", - "UnitKiloMeter", - "UnitGram", - "UnitKiloGram", - "UnitDezibel", - "UnitBpm", - "UnitKiloByte", - "UnitMegaByte", - "UnitGigaByte", - "UnitTeraByte", - "UnitMilliWatt", - "UnitWatt", - "UnitKiloWatt", - "UnitKiloWattHour", - "UnitEuroPerMegaWattHour", - "UnitEuroCentPerKiloWattHour", - "UnitPercentage", - "UnitPartsPerMillion", - "UnitEuro", - "UnitDollar", - "UnitHertz", - "UnitAmpere", - "UnitMilliAmpere", - "UnitVolt", - "UnitMilliVolt", - "UnitVoltAmpere", - "UnitVoltAmpereReactive", - "UnitAmpereHour", - "UnitMicroSiemensPerCentimeter", - "UnitDuration" - ], - "UserError": [ - "UserErrorNoError", - "UserErrorBackendError", - "UserErrorInvalidUserId", - "UserErrorDuplicateUserId", - "UserErrorBadPassword", - "UserErrorTokenNotFound", - "UserErrorPermissionDenied" - ], - "ValueOperator": [ - "ValueOperatorEquals", - "ValueOperatorNotEquals", - "ValueOperatorLess", - "ValueOperatorGreater", - "ValueOperatorLessOrEqual", - "ValueOperatorGreaterOrEqual" - ], "Vendor": { "displayName": "String", "id": "Uuid", "name": "String" }, + "Vendors": [ + "$ref:Vendor" + ], "WebServerConfiguration": { "address": "String", "authenticationEnabled": "Bool", "id": "String", "port": "Uint", + "publicFolder": "String", "sslEnabled": "Bool" }, "WiredNetworkDevice": { - "bitRate": "String", - "interface": "String", - "macAddress": "String", - "pluggedIn": "Bool", - "state": "$ref:NetworkDeviceState" + "r:bitRate": "String", + "r:interface": "String", + "r:macAddress": "String", + "r:pluggedIn": "Bool", + "r:state": "$ref:NetworkDeviceState" }, "WirelessAccessPoint": { - "frequency": "Double", - "macAddress": "String", - "protected": "Bool", - "signalStrength": "Int", - "ssid": "String" + "r:frequency": "Double", + "r:macAddress": "String", + "r:protected": "Bool", + "r:signalStrength": "Int", + "r:ssid": "String" }, "WirelessNetworkDevice": { "bitRate": "String", diff --git a/tests/auto/configurations/testconfigurations.cpp b/tests/auto/configurations/testconfigurations.cpp index 5680e6d0..3bcdb4de 100644 --- a/tests/auto/configurations/testconfigurations.cpp +++ b/tests/auto/configurations/testconfigurations.cpp @@ -30,6 +30,11 @@ class TestConfigurations: public NymeaTestBase { Q_OBJECT +private: + inline void verifyConfigurationError(const QVariant &response, NymeaConfiguration::ConfigurationError error = NymeaConfiguration::ConfigurationErrorNoError) { + verifyError(response, "configurationError", enumValueName(error)); + } + protected slots: void initTestCase(); @@ -316,7 +321,7 @@ void TestConfigurations::testDebugServerConfiguration() QVariantMap basicConfigurationMap = loadBasicConfiguration(); bool debugServerEnabled = basicConfigurationMap.value("debugServerEnabled").toBool(); - qDebug() << "Debug server enabled" << debugServerEnabled; + qCDebug(dcTests) << "Debug server enabled" << debugServerEnabled; QSignalSpy notificationSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray))); @@ -336,6 +341,8 @@ void TestConfigurations::testDebugServerConfiguration() params.clear(); response.clear(); configurationChangedNotifications.clear(); params.insert("enabled", newValue); + qCDebug(dcTests()) << "Enabling debug server"; + notificationSpy.clear(); response = injectAndWait("Configuration.SetDebugServerEnabled", params); verifyConfigurationError(response); @@ -356,7 +363,7 @@ void TestConfigurations::testDebugServerConfiguration() QVERIFY2(basicConfigurationNotificationMap.contains("debugServerEnabled"), "Notification does not contain key debugServerEnabled"); QVERIFY2(basicConfigurationNotificationMap.value("debugServerEnabled").toBool() == newValue, "Notification does not contain the new debugServerEnabled"); - qDebug() << "TestWebserver starting"; + qCDebug(dcTests()) << "TestWebserver starting"; foreach (const WebServerConfiguration &config, NymeaCore::instance()->configuration()->webServerConfigurations()) { if (config.port == 3333 && (config.address == QHostAddress("127.0.0.1") || config.address == QHostAddress("0.0.0.0"))) { qDebug() << "Already have a webserver listening on 127.0.0.1:3333"; @@ -364,7 +371,7 @@ void TestConfigurations::testDebugServerConfiguration() } } - qDebug() << "Creating new webserver instance on 127.0.0.1:3333"; + qCDebug(dcTests) << "Creating new webserver instance on 127.0.0.1:3333"; WebServerConfiguration config; config.id = "Testwebserver for debug server interface"; config.address = QHostAddress("127.0.0.1"); diff --git a/tests/auto/devices/testdevices.cpp b/tests/auto/devices/testdevices.cpp index 33120650..6a4a771a 100644 --- a/tests/auto/devices/testdevices.cpp +++ b/tests/auto/devices/testdevices.cpp @@ -26,6 +26,8 @@ #include "devices/devicediscoveryinfo.h" #include "devices/devicesetupinfo.h" +#include "servers/mocktcpserver.h" + using namespace nymeaserver; class TestDevices : public NymeaTestBase @@ -35,6 +37,10 @@ class TestDevices : public NymeaTestBase private: DeviceId m_mockDeviceAsyncId; + inline void verifyDeviceError(const QVariant &response, Device::DeviceError error = Device::DeviceErrorNoError) { + verifyError(response, "deviceError", enumValueName(error)); + } + private slots: void initTestCase(); @@ -113,6 +119,14 @@ private slots: void testExecuteBrowserItemAction_data(); void testExecuteBrowserItemAction(); + void executeAction_data(); + void executeAction(); + + void triggerEvent(); + void triggerStateChangeEvent(); + + void params(); + // Keep those at last as they will remove devices void removeDevice_data(); void removeDevice(); @@ -287,7 +301,7 @@ void TestDevices::verifyInterfaces() QVariantMap mockDevice; foreach (const QVariant &deviceClass, supportedDevices) { - if (deviceClass.toMap().value("id") == mockDeviceClassId) { + if (deviceClass.toMap().value("id").toUuid() == mockDeviceClassId) { mockDevice = deviceClass.toMap(); } } @@ -308,6 +322,7 @@ void TestDevices::addConfiguredDevice_data() { QTest::addColumn("deviceClassId"); QTest::addColumn("deviceParams"); + QTest::addColumn("jsonValidation"); QTest::addColumn("deviceError"); QVariantMap httpportParam; @@ -323,32 +338,35 @@ void TestDevices::addConfiguredDevice_data() QVariantList deviceParams; deviceParams.clear(); deviceParams << httpportParam; - QTest::newRow("User, JustAdd") << mockDeviceClassId << deviceParams << Device::DeviceErrorNoError; + QTest::newRow("User, JustAdd") << mockDeviceClassId << deviceParams << true << Device::DeviceErrorNoError; deviceParams.clear(); deviceParams << httpportParam << asyncParam; - QTest::newRow("User, JustAdd, Async") << mockDeviceClassId << deviceParams << Device::DeviceErrorNoError; - QTest::newRow("Invalid DeviceClassId") << DeviceClassId::createDeviceClassId() << deviceParams << Device::DeviceErrorDeviceClassNotFound; + QTest::newRow("User, JustAdd, Async") << mockDeviceClassId << deviceParams << true << Device::DeviceErrorNoError; + QTest::newRow("Invalid DeviceClassId") << DeviceClassId::createDeviceClassId() << deviceParams << true << Device::DeviceErrorDeviceClassNotFound; deviceParams.clear(); deviceParams << httpportParam << brokenParam; - QTest::newRow("Setup failure") << mockDeviceClassId << deviceParams << Device::DeviceErrorSetupFailed; + QTest::newRow("Setup failure") << mockDeviceClassId << deviceParams << true << Device::DeviceErrorSetupFailed; deviceParams.clear(); deviceParams << httpportParam << asyncParam << brokenParam; - QTest::newRow("Setup failure, Async") << mockDeviceClassId << deviceParams << Device::DeviceErrorSetupFailed; + QTest::newRow("Setup failure, Async") << mockDeviceClassId << deviceParams << true << Device::DeviceErrorSetupFailed; QVariantList invalidDeviceParams; - QTest::newRow("User, JustAdd, missing params") << mockDeviceClassId << invalidDeviceParams << Device::DeviceErrorMissingParameter; + QTest::newRow("User, JustAdd, missing params") << mockDeviceClassId << invalidDeviceParams << true << Device::DeviceErrorMissingParameter; QVariantMap fakeparam; fakeparam.insert("paramTypeId", ParamTypeId::createParamTypeId()); invalidDeviceParams.append(fakeparam); - QTest::newRow("User, JustAdd, invalid param") << mockDeviceClassId << invalidDeviceParams << Device::DeviceErrorMissingParameter; + QTest::newRow("User, JustAdd, invalid param") << mockDeviceClassId << invalidDeviceParams << false << Device::DeviceErrorMissingParameter; QVariantMap fakeparam2; fakeparam2.insert("paramTypeId", mockDeviceHttpportParamTypeId.toString()); fakeparam2.insert("value", "blabla"); invalidDeviceParams.clear(); invalidDeviceParams.append(fakeparam2); - QTest::newRow("User, JustAdd, wrong param") << mockDeviceClassId << invalidDeviceParams << Device::DeviceErrorInvalidParameter; + QTest::newRow("User, JustAdd, wrong param") << mockDeviceClassId << invalidDeviceParams << true << Device::DeviceErrorInvalidParameter; deviceParams.clear(); deviceParams << httpportParam << fakeparam; - QTest::newRow("USer, JustAdd, additional invalid param") << mockDeviceClassId << deviceParams << Device::DeviceErrorNoError; + QTest::newRow("USer, JustAdd, additional invalid param") << mockDeviceClassId << deviceParams << false << Device::DeviceErrorNoError; + + deviceParams.clear(); deviceParams << httpportParam << fakeparam2; + QTest::newRow("USer, JustAdd, additional param, valid but unused") << mockDeviceClassId << deviceParams << true << Device::DeviceErrorNoError; } @@ -356,6 +374,7 @@ void TestDevices::addConfiguredDevice() { QFETCH(DeviceClassId, deviceClassId); QFETCH(QVariantList, deviceParams); + QFETCH(bool, jsonValidation); QFETCH(Device::DeviceError, deviceError); QVariantMap params; @@ -363,8 +382,11 @@ void TestDevices::addConfiguredDevice() params.insert("name", "Test Add Device"); params.insert("deviceParams", deviceParams); QVariant response = injectAndWait("Devices.AddConfiguredDevice", params); - qDebug() << "response is" << response; + if (!jsonValidation) { + QCOMPARE(response.toMap().value("status").toString(), QString("error")); + return; + } verifyDeviceError(response, deviceError); if (deviceError == Device::DeviceErrorNoError) { @@ -646,8 +668,8 @@ void TestDevices::parentChildDevices() if (deviceMap.value("deviceClassId").toString() == mockChildDeviceClassId.toString()) { if (deviceMap.value("parentId") == parentDeviceId.toString()) { - //qDebug() << QJsonDocument::fromVariant(deviceVariant).toJson(); childDeviceId = DeviceId(deviceMap.value("id").toString()); + break; } } } @@ -775,7 +797,7 @@ void TestDevices::getStateTypes() QVariantList stateTypes = response.toMap().value("params").toMap().value("stateTypes").toList(); QCOMPARE(stateTypes.count(), resultCount); if (resultCount > 0) { - QCOMPARE(stateTypes.first().toMap().value("id").toString(), mockIntStateTypeId.toString()); + QCOMPARE(stateTypes.first().toMap().value("id").toUuid().toString(), mockIntStateTypeId.toString()); } } @@ -804,10 +826,8 @@ void TestDevices::getStateType() QVariantMap stateType = response.toMap().value("params").toMap().value("stateType").toMap(); - qDebug() << QJsonDocument::fromVariant(stateType).toJson(); - QVERIFY2(!stateType.isEmpty(), "Got no stateType"); - QCOMPARE(stateType.value("id").toString(), stateTypeId.toString()); + QCOMPARE(stateType.value("id").toUuid().toString(), stateTypeId.toString()); } void TestDevices::getStateValue_data() @@ -832,7 +852,7 @@ void TestDevices::getStateValue() params.insert("stateTypeId", stateTypeId); QVariant response = injectAndWait("Devices.GetStateValue", params); - QCOMPARE(response.toMap().value("params").toMap().value("deviceError").toString(), JsonTypes::deviceErrorToString(statusCode)); + QCOMPARE(response.toMap().value("params").toMap().value("deviceError").toString(), enumValueName(statusCode)); if (statusCode == Device::DeviceErrorNoError) { QVariant value = response.toMap().value("params").toMap().value("value"); QCOMPARE(value.toInt(), 10); // Mock device has value 10 by default... @@ -857,7 +877,7 @@ void TestDevices::getStateValues() params.insert("deviceId", deviceId); QVariant response = injectAndWait("Devices.GetStateValues", params); - QCOMPARE(response.toMap().value("params").toMap().value("deviceError").toString(), JsonTypes::deviceErrorToString(statusCode)); + QCOMPARE(response.toMap().value("params").toMap().value("deviceError").toString(), enumValueName(statusCode)); if (statusCode == Device::DeviceErrorNoError) { QVariantList values = response.toMap().value("params").toMap().value("values").toList(); QCOMPARE(values.count(), 6); // Mock device has 6 states... @@ -1767,6 +1787,181 @@ void TestDevices::testExecuteBrowserItemAction() } +void TestDevices::executeAction_data() +{ + QTest::addColumn("deviceId"); + QTest::addColumn("actionTypeId"); + QTest::addColumn("actionParams"); + QTest::addColumn("error"); + + QVariantList params; + QVariantMap param1; + param1.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId); + param1.insert("value", 5); + params.append(param1); + QVariantMap param2; + param2.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId); + param2.insert("value", true); + params.append(param2); + + QTest::newRow("valid action") << m_mockDeviceId << mockWithParamsActionTypeId << params << Device::DeviceErrorNoError; + QTest::newRow("invalid deviceId") << DeviceId::createDeviceId() << mockWithParamsActionTypeId << params << Device::DeviceErrorDeviceNotFound; + QTest::newRow("invalid actionTypeId") << m_mockDeviceId << ActionTypeId::createActionTypeId() << params << Device::DeviceErrorActionTypeNotFound; + QTest::newRow("missing params") << m_mockDeviceId << mockWithParamsActionTypeId << QVariantList() << Device::DeviceErrorMissingParameter; + QTest::newRow("async action") << m_mockDeviceId << mockAsyncActionTypeId << QVariantList() << Device::DeviceErrorNoError; + QTest::newRow("broken action") << m_mockDeviceId << mockFailingActionTypeId << QVariantList() << Device::DeviceErrorSetupFailed; + QTest::newRow("async broken action") << m_mockDeviceId << mockAsyncFailingActionTypeId << QVariantList() << Device::DeviceErrorSetupFailed; +} + +void TestDevices::executeAction() +{ + QFETCH(DeviceId, deviceId); + QFETCH(ActionTypeId, actionTypeId); + QFETCH(QVariantList, actionParams); + QFETCH(Device::DeviceError, error); + + QVariantMap params; + params.insert("actionTypeId", actionTypeId); + params.insert("deviceId", deviceId); + params.insert("params", actionParams); + QVariant response = injectAndWait("Devices.ExecuteAction", params); + qDebug() << "executeActionresponse" << response; + verifyError(response, "deviceError", enumValueName(error)); + + // Fetch action execution history from mock device + QNetworkAccessManager nam; + QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*))); + + QNetworkRequest request(QUrl(QString("http://localhost:%1/actionhistory").arg(m_mockDevice1Port))); + QNetworkReply *reply = nam.get(request); + spy.wait(); + QCOMPARE(spy.count(), 1); + reply->deleteLater(); + QByteArray data = reply->readAll(); + + if (error == Device::DeviceErrorNoError) { + QVERIFY2(actionTypeId == ActionTypeId(data), QString("ActionTypeId mismatch. Got %1, Expected: %2") + .arg(ActionTypeId(data).toString()).arg(actionTypeId.toString()).toLatin1().data()); + } else { + QVERIFY2(data.length() == 0, QString("Data is %1, should be empty.").arg(QString(data)).toLatin1().data()); + } + + // cleanup for the next run + spy.clear(); + request.setUrl(QUrl(QString("http://localhost:%1/clearactionhistory").arg(m_mockDevice1Port))); + reply = nam.get(request); + spy.wait(); + QCOMPARE(spy.count(), 1); + reply->deleteLater(); + + spy.clear(); + request.setUrl(QUrl(QString("http://localhost:%1/actionhistory").arg(m_mockDevice1Port))); + reply = nam.get(request); + spy.wait(); + QCOMPARE(spy.count(), 1); + reply->deleteLater(); + data = reply->readAll(); + qDebug() << "cleared data:" << data; + +} + +void TestDevices::triggerEvent() +{ + enableNotifications({"Devices"}); + QList devices = NymeaCore::instance()->deviceManager()->findConfiguredDevices(mockDeviceClassId); + QVERIFY2(devices.count() > 0, "There needs to be at least one configured Mock Device for this test"); + Device *device = devices.first(); + + + QSignalSpy spy(NymeaCore::instance(), SIGNAL(eventTriggered(const Event&))); + QSignalSpy notificationSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray))); + + // Setup connection to mock client + QNetworkAccessManager nam; + + // trigger event in mock device + int port = device->paramValue(mockDeviceHttpportParamTypeId).toInt(); + QNetworkRequest request(QUrl(QString("http://localhost:%1/generateevent?eventtypeid=%2").arg(port).arg(mockEvent1EventTypeId.toString()))); + QNetworkReply *reply = nam.get(request); + connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); + + // Lets wait for the notification + spy.wait(); + QVERIFY(spy.count() > 0); + for (int i = 0; i < spy.count(); i++ ){ + Event event = spy.at(i).at(0).value(); + if (event.deviceId() == device->id()) { + // Make sure the event contains all the stuff we expect + QCOMPARE(event.eventTypeId(), mockEvent1EventTypeId); + } + } + + // Check for the notification on JSON API + QVariantList notifications; + notifications = checkNotifications(notificationSpy, "Devices.EventTriggered"); + QVERIFY2(notifications.count() == 1, "Should get Devices.EventTriggered notification"); + QVariantMap notificationContent = notifications.first().toMap().value("params").toMap(); + + QCOMPARE(notificationContent.value("event").toMap().value("deviceId").toUuid().toString(), device->id().toString()); + QCOMPARE(notificationContent.value("event").toMap().value("eventTypeId").toUuid().toString(), mockEvent1EventTypeId.toString()); +} + +void TestDevices::triggerStateChangeEvent() +{ + enableNotifications({"Devices"}); + + QList devices = NymeaCore::instance()->deviceManager()->findConfiguredDevices(mockDeviceClassId); + QVERIFY2(devices.count() > 0, "There needs to be at least one configured Mock Device for this test"); + Device *device = devices.first(); + + QSignalSpy spy(NymeaCore::instance(), SIGNAL(eventTriggered(const Event&))); + QSignalSpy notificationSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray))); + + // Setup connection to mock client + QNetworkAccessManager nam; + + // trigger state changed event in mock device + int port = device->paramValue(mockDeviceHttpportParamTypeId).toInt(); + QNetworkRequest request(QUrl(QString("http://localhost:%1/setstate?%2=%3").arg(port).arg(mockIntStateTypeId.toString()).arg(11))); + QNetworkReply *reply = nam.get(request); + connect(reply, &QNetworkReply::finished, reply, &QNetworkReply::deleteLater); + + // Lets wait for the notification + spy.wait(); + QVERIFY(spy.count() > 0); + for (int i = 0; i < spy.count(); i++ ){ + Event event = spy.at(i).at(0).value(); + if (event.deviceId() == device->id()) { + // Make sure the event contains all the stuff we expect + QCOMPARE(event.eventTypeId().toString(), mockIntStateTypeId.toString()); + QCOMPARE(event.param(ParamTypeId(mockIntStateTypeId.toString())).value().toInt(), 11); + } + } + + // Check for the notification on JSON API + QVariantList notifications; + notifications = checkNotifications(notificationSpy, "Devices.EventTriggered"); + QVERIFY2(notifications.count() == 1, "Should get Devices.EventTriggered notification"); + QVariantMap notificationContent = notifications.first().toMap().value("params").toMap(); + + QCOMPARE(notificationContent.value("event").toMap().value("deviceId").toUuid().toString(), device->id().toString()); + QCOMPARE(notificationContent.value("event").toMap().value("eventTypeId").toUuid().toString(), mockIntEventTypeId.toString()); + +} + +void TestDevices::params() +{ + Event event; + ParamList params; + ParamTypeId id = ParamTypeId::createParamTypeId(); + Param p(id, "foo bar"); + params.append(p); + event.setParams(params); + + QVERIFY(event.param(id).value().toString() == "foo bar"); + QVERIFY(!event.param(ParamTypeId::createParamTypeId()).value().isValid()); +} + #include "testdevices.moc" QTEST_MAIN(TestDevices) diff --git a/tests/auto/events/testevents.cpp b/tests/auto/events/testevents.cpp index d18c124d..6edf2b86 100644 --- a/tests/auto/events/testevents.cpp +++ b/tests/auto/events/testevents.cpp @@ -22,6 +22,8 @@ #include "nymeatestbase.h" #include "nymeacore.h" +#include "servers/mocktcpserver.h" + using namespace nymeaserver; class TestEvents: public NymeaTestBase @@ -40,11 +42,14 @@ private slots: void TestEvents::triggerEvent() { + enableNotifications({"Events"}); + QList devices = NymeaCore::instance()->deviceManager()->findConfiguredDevices(mockDeviceClassId); QVERIFY2(devices.count() > 0, "There needs to be at least one configured Mock Device for this test"); Device *device = devices.first(); QSignalSpy spy(NymeaCore::instance(), SIGNAL(eventTriggered(const Event&))); + QSignalSpy notificationSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray))); // Setup connection to mock client QNetworkAccessManager nam; @@ -65,15 +70,28 @@ void TestEvents::triggerEvent() QCOMPARE(event.eventTypeId(), mockEvent1EventTypeId); } } + + // Check for the notification on JSON API + QVariantList notifications; + notifications = checkNotifications(notificationSpy, "Events.EventTriggered"); + QVERIFY2(notifications.count() == 1, "Should get Events.EventTriggered notification"); + QVERIFY2(notifications.first().toMap().contains("deprecationWarning"), "Deprecation warning not included in notification"); + + QVariantMap notificationContent = notifications.first().toMap().value("params").toMap(); + QCOMPARE(notificationContent.value("event").toMap().value("deviceId").toUuid().toString(), device->id().toString()); + QCOMPARE(notificationContent.value("event").toMap().value("eventTypeId").toUuid().toString(), mockEvent1EventTypeId.toString()); } void TestEvents::triggerStateChangeEvent() { + enableNotifications({"Events"}); + QList devices = NymeaCore::instance()->deviceManager()->findConfiguredDevices(mockDeviceClassId); QVERIFY2(devices.count() > 0, "There needs to be at least one configured Mock Device for this test"); Device *device = devices.first(); QSignalSpy spy(NymeaCore::instance(), SIGNAL(eventTriggered(const Event&))); + QSignalSpy notificationSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray))); // Setup connection to mock client QNetworkAccessManager nam; @@ -95,6 +113,17 @@ void TestEvents::triggerStateChangeEvent() QCOMPARE(event.param(ParamTypeId(mockIntStateTypeId.toString())).value().toInt(), 11); } } + + // Check for the notification on JSON API + QVariantList notifications; + notifications = checkNotifications(notificationSpy, "Events.EventTriggered"); + QVERIFY2(notifications.count() == 1, "Should get Devices.EventTriggered notification"); + QVERIFY2(notifications.first().toMap().contains("deprecationWarning"), "Deprecation warning not included in notification!"); + + QVariantMap notificationContent = notifications.first().toMap().value("params").toMap(); + + QCOMPARE(notificationContent.value("event").toMap().value("deviceId").toUuid().toString(), device->id().toString()); + QCOMPARE(notificationContent.value("event").toMap().value("eventTypeId").toUuid().toString(), mockIntEventTypeId.toString()); } void TestEvents::params() @@ -128,7 +157,10 @@ void TestEvents::getEventType() params.insert("eventTypeId", eventTypeId.toString()); QVariant response = injectAndWait("Events.GetEventType", params); - verifyDeviceError(response, error); + verifyError(response, "deviceError", enumValueName(error)); + + qCDebug(dcTests()) << "*content" << response; + QVERIFY2(response.toMap().contains("deprecationWarning"), "Deprecation warning not shown in reply"); if (error == Device::DeviceErrorNoError) { QVERIFY2(EventTypeId(response.toMap().value("params").toMap().value("eventType").toMap().value("id").toString()) == eventTypeId, "Didn't get a reply for the same actionTypeId as requested."); diff --git a/tests/auto/jsonrpc/testjsonrpc.cpp b/tests/auto/jsonrpc/testjsonrpc.cpp index fd03a559..e1c69d14 100644 --- a/tests/auto/jsonrpc/testjsonrpc.cpp +++ b/tests/auto/jsonrpc/testjsonrpc.cpp @@ -23,6 +23,7 @@ #include "../../utils/pushbuttonagent.h" #include "nymeacore.h" #include "servers/mocktcpserver.h" +#include "usermanager/usermanager.h" using namespace nymeaserver; @@ -30,6 +31,14 @@ class TestJSONRPC: public NymeaTestBase { Q_OBJECT +private: + inline void verifyDeviceError(const QVariant &response, Device::DeviceError error = Device::DeviceErrorNoError) { + verifyError(response, "deviceError", enumValueName(error)); + } + inline void verifyRuleError(const QVariant &response, RuleEngine::RuleError error = RuleEngine::RuleErrorNoError) { + verifyError(response, "ruleError", enumValueName(error)); + } + private slots: void initTestCase(); @@ -603,6 +612,8 @@ void TestJSONRPC::introspect() QVariant response = injectAndWait("JSONRPC.Introspect"); QVariantMap methods = response.toMap().value("params").toMap().value("methods").toMap(); QVariantMap notifications = response.toMap().value("params").toMap().value("notifications").toMap(); + QVariantMap enums = response.toMap().value("params").toMap().value("enums").toMap(); + QVariantMap flags = response.toMap().value("params").toMap().value("flags").toMap(); QVariantMap types = response.toMap().value("params").toMap().value("types").toMap(); QVERIFY2(methods.count() > 0, "No methods in Introspect response!"); @@ -615,8 +626,11 @@ void TestJSONRPC::introspect() foreach (const QString &ref, extractRefs(item)) { QString typeId = ref; typeId.remove("$ref:"); - QVERIFY2(types.contains(typeId), QString("Undefined ref: %1. Did you forget to add it to JsonTypes::allTypes()?").arg(ref).toLatin1().data()); - QVERIFY2(!types.value(typeId).toString().startsWith("$ref:"), QString("Definition for %1 must not be a reference itself").arg(ref).toLatin1().data()); + QVERIFY2(enums.contains(typeId) || types.contains(typeId) || flags.contains(typeId), + QString("Undefined ref: %1. Did you forget to add it to JsonTypes::allTypes()?").arg(ref).toLatin1().data()); + QVERIFY2(!types.value(typeId).toString().startsWith("$ref:") + && !flags.value(typeId).toString().startsWith("$ref:") + && !enums.value(typeId).toString().startsWith("$ref:"), QString("Definition for %1 must not be a reference itself").arg(ref).toLatin1().data()); } } } @@ -714,7 +728,7 @@ void TestJSONRPC::ruleAddedRemovedNotifications() QVariantMap stateDescriptor; stateDescriptor.insert("stateTypeId", mockIntStateTypeId); stateDescriptor.insert("deviceId", m_mockDeviceId); - stateDescriptor.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorLess)); + stateDescriptor.insert("operator", enumValueName(Types::ValueOperatorLess)); stateDescriptor.insert("value", "20"); QVariantMap stateEvaluator; @@ -724,18 +738,17 @@ void TestJSONRPC::ruleAddedRemovedNotifications() QVariantMap actionNoParams; actionNoParams.insert("actionTypeId", mockWithoutParamsActionTypeId); actionNoParams.insert("deviceId", m_mockDeviceId); - actionNoParams.insert("ruleActionParams", QVariantList()); // EventDescriptor QVariantMap eventDescriptor; eventDescriptor.insert("eventTypeId", mockEvent1EventTypeId); eventDescriptor.insert("deviceId", m_mockDeviceId); - eventDescriptor.insert("paramDescriptors", QVariantList()); + QVariantList eventDescriptors = QVariantList() << eventDescriptor; QVariantMap params; params.insert("name", "Test Rule notifications"); params.insert("actions", QVariantList() << actionNoParams); - params.insert("eventDescriptors", QVariantList() << eventDescriptor); + params.insert("eventDescriptors", eventDescriptors); params.insert("stateEvaluator", stateEvaluator); QVariant response = injectAndWait("Rules.AddRule", params); @@ -751,7 +764,11 @@ void TestJSONRPC::ruleAddedRemovedNotifications() QCOMPARE(notificationRuleMap.value("id").toString(), ruleId.toString()); QCOMPARE(notificationRuleMap.value("actions").toList(), QVariantList() << actionNoParams); QCOMPARE(notificationRuleMap.value("stateEvaluator").toMap().value("stateDescriptor").toMap(), stateDescriptor); - QCOMPARE(notificationRuleMap.value("eventDescriptors").toList(), QVariantList() << eventDescriptor); + QVERIFY2(notificationRuleMap.value("eventDescriptors").toList() == eventDescriptors, + QString("eventDescriptors not matching.\nExpected: %1\nGot %2") + .arg(QString(QJsonDocument::fromVariant(eventDescriptors).toJson())) + .arg(QString(QJsonDocument::fromVariant(notificationRuleMap.value("eventDescriptors").toList()).toJson())) + .toUtf8()); QCOMPARE(notificationRuleMap.value("exitActions").toList(), QVariantList()); // now remove the rule and check the RuleRemoved notification @@ -778,7 +795,7 @@ void TestJSONRPC::ruleActiveChangedNotifications() QVariantMap stateDescriptor; stateDescriptor.insert("stateTypeId", mockIntStateTypeId); stateDescriptor.insert("deviceId", m_mockDeviceId); - stateDescriptor.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals)); + stateDescriptor.insert("operator", enumValueName(Types::ValueOperatorEquals)); stateDescriptor.insert("value", "20"); QVariantMap stateEvaluator; @@ -788,7 +805,6 @@ void TestJSONRPC::ruleActiveChangedNotifications() QVariantMap actionNoParams; actionNoParams.insert("actionTypeId", mockWithoutParamsActionTypeId); actionNoParams.insert("deviceId", m_mockDeviceId); - actionNoParams.insert("ruleActionParams", QVariantList()); params.clear(); response.clear(); params.insert("name", "Test Rule notifications"); @@ -827,7 +843,7 @@ void TestJSONRPC::ruleActiveChangedNotifications() notificationVariant = checkNotification(clientSpy, "Rules.RuleActiveChanged"); verifyRuleError(response); - QCOMPARE(notificationVariant.toMap().value("params").toMap().value("ruleId").toString(), ruleId.toString()); + QCOMPARE(notificationVariant.toMap().value("params").toMap().value("ruleId").toUuid().toString(), ruleId.toString()); QCOMPARE(notificationVariant.toMap().value("params").toMap().value("active").toBool(), true); spy.clear(); clientSpy.clear(); @@ -845,7 +861,7 @@ void TestJSONRPC::ruleActiveChangedNotifications() notificationVariant = checkNotification(clientSpy, "Rules.RuleActiveChanged"); verifyRuleError(response); - QCOMPARE(notificationVariant.toMap().value("params").toMap().value("ruleId").toString(), ruleId.toString()); + QCOMPARE(notificationVariant.toMap().value("params").toMap().value("ruleId").toUuid().toString(), ruleId.toString()); QCOMPARE(notificationVariant.toMap().value("params").toMap().value("active").toBool(), false); // now remove the rule and check the RuleRemoved notification @@ -858,7 +874,7 @@ void TestJSONRPC::ruleActiveChangedNotifications() checkNotification(clientSpy, "Logging.LogDatabaseUpdated"); verifyRuleError(response); - QCOMPARE(notificationVariant.toMap().value("params").toMap().value("ruleId").toString(), ruleId.toString()); + QCOMPARE(notificationVariant.toMap().value("params").toMap().value("ruleId").toUuid().toString(), ruleId.toString()); } void TestJSONRPC::deviceChangedNotifications() diff --git a/tests/auto/logging/testlogging.cpp b/tests/auto/logging/testlogging.cpp index 8fc94b9e..abd0753d 100644 --- a/tests/auto/logging/testlogging.cpp +++ b/tests/auto/logging/testlogging.cpp @@ -35,6 +35,13 @@ class TestLogging : public NymeaTestBase private: + inline void verifyLoggingError(const QVariant &response, Logging::LoggingError error = Logging::LoggingErrorNoError) { + verifyError(response, "loggingError", enumValueName(error)); + } + inline void verifyDeviceError(const QVariant &response, Device::DeviceError error = Device::DeviceErrorNoError) { + verifyError(response, "deviceError", enumValueName(error)); + } + private slots: void initTestCase(); @@ -148,8 +155,8 @@ void TestLogging::systemLogs() { // check the active system log at boot QVariantMap params; - params.insert("loggingSources", QVariantList() << JsonTypes::loggingSourceToString(Logging::LoggingSourceSystem)); - params.insert("eventTypes", QVariantList() << JsonTypes::loggingEventTypeToString(Logging::LoggingEventTypeActiveChange)); + params.insert("loggingSources", QVariantList() << enumValueName(Logging::LoggingSourceSystem)); + params.insert("eventTypes", QVariantList() << enumValueName(Logging::LoggingEventTypeActiveChange)); // there should be 2 logs, one for shutdown, one for startup (from server restart) QVariant response = injectAndWait("Logging.GetLogEntries", params); @@ -166,15 +173,15 @@ void TestLogging::systemLogs() } QCOMPARE(logEntryShutdown.value("active").toBool(), false); - QCOMPARE(logEntryShutdown.value("eventType").toString(), JsonTypes::loggingEventTypeToString(Logging::LoggingEventTypeActiveChange)); - QCOMPARE(logEntryShutdown.value("source").toString(), JsonTypes::loggingSourceToString(Logging::LoggingSourceSystem)); - QCOMPARE(logEntryShutdown.value("loggingLevel").toString(), JsonTypes::loggingLevelToString(Logging::LoggingLevelInfo)); + QCOMPARE(logEntryShutdown.value("eventType").toString(), enumValueName(Logging::LoggingEventTypeActiveChange)); + QCOMPARE(logEntryShutdown.value("source").toString(), enumValueName(Logging::LoggingSourceSystem)); + QCOMPARE(logEntryShutdown.value("loggingLevel").toString(), enumValueName(Logging::LoggingLevelInfo)); QCOMPARE(logEntryStartup.value("active").toBool(), true); - QCOMPARE(logEntryStartup.value("eventType").toString(), JsonTypes::loggingEventTypeToString(Logging::LoggingEventTypeActiveChange)); - QCOMPARE(logEntryStartup.value("source").toString(), JsonTypes::loggingSourceToString(Logging::LoggingSourceSystem)); - QCOMPARE(logEntryStartup.value("loggingLevel").toString(), JsonTypes::loggingLevelToString(Logging::LoggingLevelInfo)); + QCOMPARE(logEntryStartup.value("eventType").toString(), enumValueName(Logging::LoggingEventTypeActiveChange)); + QCOMPARE(logEntryStartup.value("source").toString(), enumValueName(Logging::LoggingSourceSystem)); + QCOMPARE(logEntryStartup.value("loggingLevel").toString(), enumValueName(Logging::LoggingLevelInfo)); } void TestLogging::invalidFilter_data() @@ -189,7 +196,7 @@ void TestLogging::invalidFilter_data() invalidTypeIds.insert("typeId", QVariantList() << "bla" << "blub"); QVariantMap invalidEventTypes; - invalidEventTypes.insert("eventTypes", QVariantList() << JsonTypes::loggingEventTypeToString(Logging::LoggingEventTypeTrigger) << "blub"); + invalidEventTypes.insert("eventTypes", QVariantList() << enumValueName(Logging::LoggingEventTypeTrigger) << "blub"); QTest::addColumn("filter"); @@ -243,13 +250,13 @@ void TestLogging::eventLogs() qDebug() << "got" << loggEntryAddedVariants.count() << "Logging.LogEntryAdded"; foreach (const QVariant &loggEntryAddedVariant, loggEntryAddedVariants) { QVariantMap logEntry = loggEntryAddedVariant.toMap().value("params").toMap().value("logEntry").toMap(); - if (logEntry.value("deviceId").toString() == device->id().toString()) { + if (logEntry.value("deviceId").toUuid() == device->id()) { found = true; // Make sure the notification contains all the stuff we expect - QCOMPARE(logEntry.value("typeId").toString(), mockEvent1EventTypeId.toString()); - QCOMPARE(logEntry.value("eventType").toString(), JsonTypes::loggingEventTypeToString(Logging::LoggingEventTypeTrigger)); - QCOMPARE(logEntry.value("source").toString(), JsonTypes::loggingSourceToString(Logging::LoggingSourceEvents)); - QCOMPARE(logEntry.value("loggingLevel").toString(), JsonTypes::loggingLevelToString(Logging::LoggingLevelInfo)); + QCOMPARE(logEntry.value("typeId").toUuid().toString(), mockEvent1EventTypeId.toString()); + QCOMPARE(logEntry.value("eventType").toString(), enumValueName(Logging::LoggingEventTypeTrigger)); + QCOMPARE(logEntry.value("source").toString(), enumValueName(Logging::LoggingSourceEvents)); + QCOMPARE(logEntry.value("loggingLevel").toString(), enumValueName(Logging::LoggingLevelInfo)); break; } } @@ -261,8 +268,8 @@ void TestLogging::eventLogs() // get this logentry with filter QVariantMap params; params.insert("deviceIds", QVariantList() << device->id()); - params.insert("loggingSources", QVariantList() << JsonTypes::loggingSourceToString(Logging::LoggingSourceEvents)); - params.insert("eventTypes", QVariantList() << JsonTypes::loggingEventTypeToString(Logging::LoggingEventTypeTrigger)); + params.insert("loggingSources", QVariantList() << enumValueName(Logging::LoggingSourceEvents)); + params.insert("eventTypes", QVariantList() << enumValueName(Logging::LoggingEventTypeTrigger)); params.insert("typeIds", QVariantList() << mockEvent1EventTypeId); QVariant response = injectAndWait("Logging.GetLogEntries", params); @@ -313,13 +320,13 @@ void TestLogging::actionLog() qDebug() << "got" << loggEntryAddedVariants.count() << "Logging.LogEntryAdded"; foreach (const QVariant &loggEntryAddedVariant, loggEntryAddedVariants) { QVariantMap logEntry = loggEntryAddedVariant.toMap().value("params").toMap().value("logEntry").toMap(); - if (logEntry.value("deviceId").toString() == m_mockDeviceId.toString()) { + if (logEntry.value("deviceId").toUuid() == m_mockDeviceId) { found = true; // Make sure the notification contains all the stuff we expect - QCOMPARE(logEntry.value("typeId").toString(), mockWithParamsActionTypeId.toString()); - QCOMPARE(logEntry.value("eventType").toString(), JsonTypes::loggingEventTypeToString(Logging::LoggingEventTypeTrigger)); - QCOMPARE(logEntry.value("source").toString(), JsonTypes::loggingSourceToString(Logging::LoggingSourceActions)); - QCOMPARE(logEntry.value("loggingLevel").toString(), JsonTypes::loggingLevelToString(Logging::LoggingLevelInfo)); + QCOMPARE(logEntry.value("typeId").toUuid().toString(), mockWithParamsActionTypeId.toString()); + QCOMPARE(logEntry.value("eventType").toString(), enumValueName(Logging::LoggingEventTypeTrigger)); + QCOMPARE(logEntry.value("source").toString(), enumValueName(Logging::LoggingSourceActions)); + QCOMPARE(logEntry.value("loggingLevel").toString(), enumValueName(Logging::LoggingLevelInfo)); break; } } @@ -343,8 +350,8 @@ void TestLogging::actionLog() // get this logentry with filter params.clear(); params.insert("deviceIds", QVariantList() << m_mockDeviceId); - params.insert("loggingSources", QVariantList() << JsonTypes::loggingSourceToString(Logging::LoggingSourceActions)); - params.insert("eventTypes", QVariantList() << JsonTypes::loggingEventTypeToString(Logging::LoggingEventTypeTrigger)); + params.insert("loggingSources", QVariantList() << enumValueName(Logging::LoggingSourceActions)); + params.insert("eventTypes", QVariantList() << enumValueName(Logging::LoggingEventTypeTrigger)); // FIXME: currently is filtering for values not supported //params.insert("values", QVariantList() << "7, true"); @@ -372,14 +379,14 @@ void TestLogging::actionLog() qDebug() << "got" << loggEntryAddedVariants.count() << "Logging.LogEntryAdded"; foreach (const QVariant &loggEntryAddedVariant, loggEntryAddedVariants) { QVariantMap logEntry = loggEntryAddedVariant.toMap().value("params").toMap().value("logEntry").toMap(); - if (logEntry.value("deviceId").toString() == m_mockDeviceId.toString()) { + if (logEntry.value("deviceId").toUuid() == m_mockDeviceId) { found = true; // Make sure the notification contains all the stuff we expect - QCOMPARE(logEntry.value("typeId").toString(), mockFailingActionTypeId.toString()); - QCOMPARE(logEntry.value("eventType").toString(), JsonTypes::loggingEventTypeToString(Logging::LoggingEventTypeTrigger)); - QCOMPARE(logEntry.value("source").toString(), JsonTypes::loggingSourceToString(Logging::LoggingSourceActions)); - QCOMPARE(logEntry.value("loggingLevel").toString(), JsonTypes::loggingLevelToString(Logging::LoggingLevelAlert)); - QCOMPARE(logEntry.value("errorCode").toString(), JsonTypes::deviceErrorToString(Device::DeviceErrorSetupFailed)); + QCOMPARE(logEntry.value("typeId").toUuid().toString(), mockFailingActionTypeId.toString()); + QCOMPARE(logEntry.value("eventType").toString(), enumValueName(Logging::LoggingEventTypeTrigger)); + QCOMPARE(logEntry.value("source").toString(), enumValueName(Logging::LoggingSourceActions)); + QCOMPARE(logEntry.value("loggingLevel").toString(), enumValueName(Logging::LoggingLevelAlert)); + QCOMPARE(logEntry.value("errorCode").toString(), enumValueName(Device::DeviceErrorSetupFailed)); break; } } @@ -391,8 +398,8 @@ void TestLogging::actionLog() // get this logentry with filter params.clear(); params.insert("deviceIds", QVariantList() << m_mockDeviceId); - params.insert("loggingSources", QVariantList() << JsonTypes::loggingSourceToString(Logging::LoggingSourceActions)); - params.insert("eventTypes", QVariantList() << JsonTypes::loggingEventTypeToString(Logging::LoggingEventTypeTrigger)); + params.insert("loggingSources", QVariantList() << enumValueName(Logging::LoggingSourceActions)); + params.insert("eventTypes", QVariantList() << enumValueName(Logging::LoggingEventTypeTrigger)); // FIXME: filter for values currently not working //params.insert("values", QVariantList() << "7, true"); @@ -406,8 +413,8 @@ void TestLogging::actionLog() // check different filters params.clear(); params.insert("deviceIds", QVariantList() << m_mockDeviceId); - params.insert("loggingSources", QVariantList() << JsonTypes::loggingSourceToString(Logging::LoggingSourceActions)); - params.insert("eventTypes", QVariantList() << JsonTypes::loggingEventTypeToString(Logging::LoggingEventTypeTrigger)); + params.insert("loggingSources", QVariantList() << enumValueName(Logging::LoggingSourceActions)); + params.insert("eventTypes", QVariantList() << enumValueName(Logging::LoggingEventTypeTrigger)); params.insert("typeIds", QVariantList() << mockWithoutParamsActionTypeId); response = injectAndWait("Logging.GetLogEntries", params); @@ -418,8 +425,8 @@ void TestLogging::actionLog() params.clear(); params.insert("deviceIds", QVariantList() << m_mockDeviceId); - params.insert("loggingSources", QVariantList() << JsonTypes::loggingSourceToString(Logging::LoggingSourceActions)); - params.insert("eventTypes", QVariantList() << JsonTypes::loggingEventTypeToString(Logging::LoggingEventTypeTrigger)); + params.insert("loggingSources", QVariantList() << enumValueName(Logging::LoggingSourceActions)); + params.insert("eventTypes", QVariantList() << enumValueName(Logging::LoggingEventTypeTrigger)); params.insert("typeIds", QVariantList() << mockWithoutParamsActionTypeId << mockWithParamsActionTypeId << mockFailingActionTypeId); response = injectAndWait("Logging.GetLogEntries", params); @@ -447,11 +454,11 @@ void TestLogging::deviceLogs() // get this logentry with filter params.clear(); params.insert("deviceIds", QVariantList() << m_mockDeviceId << deviceId); - params.insert("loggingSources", QVariantList() << JsonTypes::loggingSourceToString(Logging::LoggingSourceActions) - << JsonTypes::loggingSourceToString(Logging::LoggingSourceEvents) - << JsonTypes::loggingSourceToString(Logging::LoggingSourceStates)); - params.insert("loggingLevels", QVariantList() << JsonTypes::loggingLevelToString(Logging::LoggingLevelInfo) - << JsonTypes::loggingLevelToString(Logging::LoggingLevelAlert)); + params.insert("loggingSources", QVariantList() << enumValueName(Logging::LoggingSourceActions) + << enumValueName(Logging::LoggingSourceEvents) + << enumValueName(Logging::LoggingSourceStates)); + params.insert("loggingLevels", QVariantList() << enumValueName(Logging::LoggingLevelInfo) + << enumValueName(Logging::LoggingLevelAlert)); params.insert("values", QVariantList() << "7, true" << "9, false"); QVariantMap timeFilter; @@ -539,14 +546,14 @@ void TestLogging::testDoubleValues() if (logNotification.value("typeId").toString() == mockDisplayPinDoubleActionDoubleParamTypeId.toString()) { // If state source - if (logNotification.value("source").toString() == JsonTypes::loggingSourceToString(Logging::LoggingSourceStates)) { + if (logNotification.value("source").toString() == enumValueName(Logging::LoggingSourceStates)) { QString logValue = logNotification.value("value").toString(); qDebug() << QString::number(value) << logValue; QCOMPARE(logValue, QString::number(value)); } // If action source notification - if (logNotification.value("source").toString() == JsonTypes::loggingSourceToString(Logging::LoggingSourceActions)) { + if (logNotification.value("source").toString() == enumValueName(Logging::LoggingSourceActions)) { QString logValue = logNotification.value("value").toString(); qDebug() << QString::number(value) << logValue; QCOMPARE(logValue, QString::number(value)); diff --git a/tests/auto/rules/testrules.cpp b/tests/auto/rules/testrules.cpp index 3d6ddc4f..113664c9 100644 --- a/tests/auto/rules/testrules.cpp +++ b/tests/auto/rules/testrules.cpp @@ -23,6 +23,7 @@ #include "nymeasettings.h" #include "servers/mocktcpserver.h" #include "nymeacore.h" +#include "jsonrpc/jsonhandler.h" using namespace nymeaserver; @@ -49,6 +50,13 @@ private: void generateEvent(const EventTypeId &eventTypeId); + inline void verifyRuleError(const QVariant &response, RuleEngine::RuleError error = RuleEngine::RuleErrorNoError) { + verifyError(response, "ruleError", enumValueName(error)); + } + inline void verifyDeviceError(const QVariant &response, Device::DeviceError error = Device::DeviceErrorNoError) { + verifyError(response, "deviceError", enumValueName(error)); + } + private slots: void initTestCase(); @@ -331,13 +339,13 @@ QVariant TestRules::validIntStateBasedRule(const QString &name, const bool &exec QVariantMap stateDescriptor; stateDescriptor.insert("stateTypeId", mockIntStateTypeId); stateDescriptor.insert("deviceId", m_mockDeviceId); - stateDescriptor.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorLess)); + stateDescriptor.insert("operator", enumValueName(Types::ValueOperatorLess)); stateDescriptor.insert("value", 25); // StateEvaluator QVariantMap stateEvaluator; stateEvaluator.insert("stateDescriptor", stateDescriptor); - stateEvaluator.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd)); + stateEvaluator.insert("operator", enumValueName(Types::StateOperatorAnd)); // RuleAction QVariantMap action; @@ -392,6 +400,7 @@ void TestRules::initTestCase() "Tests.debug=true\n" "RuleEngine.debug=true\n" // "RuleEngineDebug.debug=true\n" + "JsonRpc.debug=true\n" "MockDevice.*=true"); } @@ -401,35 +410,31 @@ void TestRules::addRemoveRules_data() QVariantMap validActionNoParams; validActionNoParams.insert("actionTypeId", mockWithoutParamsActionTypeId); validActionNoParams.insert("deviceId", m_mockDeviceId); - validActionNoParams.insert("ruleActionParams", QVariantList()); QVariantMap invalidAction; - invalidAction.insert("actionTypeId", ActionTypeId()); + invalidAction.insert("actionTypeId", ActionTypeId("f32c7efb-38b6-4576-a496-c75bbb23132f")); invalidAction.insert("deviceId", m_mockDeviceId); - invalidAction.insert("ruleActionParams", QVariantList()); // RuleExitAction QVariantMap validExitActionNoParams; validExitActionNoParams.insert("actionTypeId", mockWithoutParamsActionTypeId); validExitActionNoParams.insert("deviceId", m_mockDeviceId); - validExitActionNoParams.insert("ruleActionParams", QVariantList()); QVariantMap invalidExitAction; - invalidExitAction.insert("actionTypeId", ActionTypeId()); + invalidExitAction.insert("actionTypeId", ActionTypeId("f32c7efb-38b6-4576-a496-c75bbb23132f")); invalidExitAction.insert("deviceId", m_mockDeviceId); - invalidExitAction.insert("ruleActionParams", QVariantList()); // StateDescriptor QVariantMap stateDescriptor; stateDescriptor.insert("stateTypeId", mockIntStateTypeId); stateDescriptor.insert("deviceId", m_mockDeviceId); - stateDescriptor.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorLess)); + stateDescriptor.insert("operator", enumValueName(Types::ValueOperatorLess)); stateDescriptor.insert("value", 20); // StateEvaluator QVariantMap validStateEvaluator; validStateEvaluator.insert("stateDescriptor", stateDescriptor); - validStateEvaluator.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd)); + validStateEvaluator.insert("operator", enumValueName(Types::StateOperatorAnd)); QVariantMap invalidStateEvaluator; stateDescriptor.remove("deviceId"); @@ -439,7 +444,6 @@ void TestRules::addRemoveRules_data() QVariantMap validEventDescriptor1; validEventDescriptor1.insert("eventTypeId", mockEvent1EventTypeId); validEventDescriptor1.insert("deviceId", m_mockDeviceId); - validEventDescriptor1.insert("paramDescriptors", QVariantList()); QVariantMap validEventDescriptor2; validEventDescriptor2.insert("eventTypeId", mockEvent2EventTypeId); @@ -448,14 +452,13 @@ void TestRules::addRemoveRules_data() QVariantMap param1; param1.insert("paramTypeId", mockEvent2EventIntParamParamTypeId); param1.insert("value", 3); - param1.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals)); + param1.insert("operator", enumValueName(Types::ValueOperatorEquals)); params.append(param1); validEventDescriptor2.insert("paramDescriptors", params); QVariantMap validEventDescriptor3; validEventDescriptor3.insert("eventTypeId", mockEvent2EventTypeId); validEventDescriptor3.insert("deviceId", m_mockDeviceId); - validEventDescriptor3.insert("paramDescriptors", QVariantList()); // EventDescriptorList QVariantList eventDescriptorList; @@ -464,8 +467,7 @@ void TestRules::addRemoveRules_data() QVariantMap invalidEventDescriptor; invalidEventDescriptor.insert("eventTypeId", mockEvent1EventTypeId); - invalidEventDescriptor.insert("deviceId", DeviceId()); - invalidEventDescriptor.insert("paramDescriptors", QVariantList()); + invalidEventDescriptor.insert("deviceId", DeviceId("2c4825c8-dfb9-4ba4-bd0e-1d827d945d41")); // RuleAction event based QVariantMap validActionEventBased; @@ -493,7 +495,7 @@ void TestRules::addRemoveRules_data() QVariantMap invalidActionEventBasedParam2; invalidActionEventBasedParam2.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId); invalidActionEventBasedParam2.insert("eventTypeId", mockEvent1EventTypeId); - invalidActionEventBasedParam2.insert("eventParamTypeId", "value"); + invalidActionEventBasedParam2.insert("eventParamTypeId", ParamTypeId("7dbf5266-5179-4e09-ac31-631cc63f1d7b")); QVariantMap invalidActionEventBasedParam3; invalidActionEventBasedParam3.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId); invalidActionEventBasedParam3.insert("value", 2); @@ -524,9 +526,9 @@ void TestRules::addRemoveRules_data() QTest::newRow("invalid rule. enabled, 1 Action (eventBased), types not matching, name") << true << invalidActionEventBased3 << QVariantMap() << validEventDescriptor1 << QVariantList() << QVariantMap() << RuleEngine::RuleErrorTypesNotMatching << false << "TestRule"; - QTest::newRow("invalid rule. enabled, 1 Action (eventBased), 1 EventDescriptor, name") << true << invalidActionEventBased << QVariantMap() << validEventDescriptor2 << QVariantList() << QVariantMap() << RuleEngine::RuleErrorTypesNotMatching << false << "TestRule"; + QTest::newRow("invalid rule. enabled, 1 invalid Action (eventBased), 1 EventDescriptor, name") << true << invalidActionEventBased << QVariantMap() << validEventDescriptor2 << QVariantList() << QVariantMap() << RuleEngine::RuleErrorTypesNotMatching << false << "TestRule"; QTest::newRow("invalid rule. enabled, 1 Action (eventBased), 1 StateEvaluator, name") << true << validActionEventBased << QVariantMap() << QVariantMap() << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorInvalidRuleActionParameter << false << "TestRule"; - QTest::newRow("invalid rule. enabled, 1 Action (eventBased), 1 EventDescriptor, name") << true << validActionEventBased << validActionEventBased << validEventDescriptor2 << QVariantList() << QVariantMap() << RuleEngine::RuleErrorInvalidRuleFormat << false << "TestRule"; + QTest::newRow("invalid rule. enabled, invalid rule format") << true << validActionEventBased << validActionEventBased << validEventDescriptor2 << QVariantList() << QVariantMap() << RuleEngine::RuleErrorInvalidRuleFormat << false << "TestRule"; QTest::newRow("invalid rule. enabled, 1 Action, 1 ExitAction (EventBased), name") << true << validActionNoParams << validActionEventBased << validEventDescriptor2 << QVariantList() << QVariantMap() << RuleEngine::RuleErrorInvalidRuleFormat << false << "TestRule"; // Rules with exit actions @@ -542,7 +544,7 @@ void TestRules::addRemoveRules_data() QTest::newRow("valid rule. disabled, 1 EventDescriptor, StateEvaluator, 1 Action, name") << false << validActionNoParams << QVariantMap() << validEventDescriptor1 << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorNoError << true << "TestRule"; QTest::newRow("valid rule. 2 EventDescriptors, 1 Action, name") << true << validActionNoParams << QVariantMap() << QVariantMap() << eventDescriptorList << validStateEvaluator << RuleEngine::RuleErrorNoError << true << "TestRule"; QTest::newRow("invalid action") << true << invalidAction << QVariantMap() << validEventDescriptor1 << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorActionTypeNotFound << false << "TestRule"; - QTest::newRow("invalid event descriptor") << true << validActionNoParams << QVariantMap() << invalidEventDescriptor << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorEventTypeNotFound << false << "TestRule"; + QTest::newRow("invalid event descriptor") << true << validActionNoParams << QVariantMap() << invalidEventDescriptor << QVariantList() << validStateEvaluator << RuleEngine::RuleErrorDeviceNotFound << false << "TestRule"; } void TestRules::addRemoveRules() @@ -579,6 +581,7 @@ void TestRules::addRemoveRules() if (!enabled) { params.insert("enabled", enabled); } + qCDebug(dcTests()) << "Calling with params:" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson()); QVariant response = injectAndWait("Rules.AddRule", params); if (!jsonError) { verifyRuleError(response, error); @@ -607,7 +610,10 @@ void TestRules::addRemoveRules() QVariantList eventDescriptors = rule.value("eventDescriptors").toList(); if (!eventDescriptor.isEmpty()) { QVERIFY2(eventDescriptors.count() == 1, "There should be exactly one eventDescriptor"); - QVERIFY2(eventDescriptors.first().toMap() == eventDescriptor, "Event descriptor doesn't match"); + QVERIFY2(eventDescriptors.first().toMap() == eventDescriptor, + QString("Event descriptor doesn't match:\nExpected: %1\nGot: %2") + .arg(QString(QJsonDocument::fromVariant(eventDescriptor).toJson())) + .arg(QString(QJsonDocument::fromVariant(eventDescriptors.first().toMap()).toJson())).toUtf8()); } else if (eventDescriptorList.isEmpty()){ QVERIFY2(eventDescriptors.count() == eventDescriptorList.count(), QString("There should be exactly %1 eventDescriptor").arg(eventDescriptorList.count()).toLatin1().data()); foreach (const QVariant &eventDescriptorVariant, eventDescriptorList) { @@ -624,7 +630,11 @@ void TestRules::addRemoveRules() } QVariantList replyActions = rule.value("actions").toList(); - QVERIFY2(actions == replyActions, "Actions don't match"); + QVERIFY2(actions == replyActions, + QString("Actions don't match.\nExpected: %1\nGot: %2") + .arg(QString(QJsonDocument::fromVariant(actions).toJson())) + .arg(QString(QJsonDocument::fromVariant(replyActions).toJson())) + .toUtf8()); QVariantList replyExitActions = rule.value("exitActions").toList(); QVERIFY2(exitActions == replyExitActions, "ExitActions don't match"); @@ -645,35 +655,31 @@ void TestRules::editRules_data() QVariantMap validActionNoParams; validActionNoParams.insert("actionTypeId", mockWithoutParamsActionTypeId); validActionNoParams.insert("deviceId", m_mockDeviceId); - validActionNoParams.insert("ruleActionParams", QVariantList()); QVariantMap invalidAction; invalidAction.insert("actionTypeId", ActionTypeId()); invalidAction.insert("deviceId", m_mockDeviceId); - invalidAction.insert("ruleActionParams", QVariantList()); // RuleExitAction QVariantMap validExitActionNoParams; validExitActionNoParams.insert("actionTypeId", mockWithoutParamsActionTypeId); validExitActionNoParams.insert("deviceId", m_mockDeviceId); - validExitActionNoParams.insert("ruleActionParams", QVariantList()); QVariantMap invalidExitAction; invalidExitAction.insert("actionTypeId", ActionTypeId()); invalidExitAction.insert("deviceId", m_mockDeviceId); - invalidExitAction.insert("ruleActionParams", QVariantList()); // StateDescriptor QVariantMap stateDescriptor; stateDescriptor.insert("stateTypeId", mockIntStateTypeId); stateDescriptor.insert("deviceId", m_mockDeviceId); - stateDescriptor.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorLess)); + stateDescriptor.insert("operator", enumValueName(Types::ValueOperatorLess)); stateDescriptor.insert("value", 20); // StateEvaluator QVariantMap validStateEvaluator; validStateEvaluator.insert("stateDescriptor", stateDescriptor); - validStateEvaluator.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd)); + validStateEvaluator.insert("operator", enumValueName(Types::StateOperatorAnd)); QVariantMap invalidStateEvaluator; stateDescriptor.remove("deviceId"); @@ -683,7 +689,6 @@ void TestRules::editRules_data() QVariantMap validEventDescriptor1; validEventDescriptor1.insert("eventTypeId", mockEvent1EventTypeId); validEventDescriptor1.insert("deviceId", m_mockDeviceId); - validEventDescriptor1.insert("paramDescriptors", QVariantList()); QVariantMap validEventDescriptor2; validEventDescriptor2.insert("eventTypeId", mockEvent2EventTypeId); @@ -692,14 +697,13 @@ void TestRules::editRules_data() QVariantMap param1; param1.insert("paramTypeId", mockEvent2EventIntParamParamTypeId); param1.insert("value", 3); - param1.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals)); + param1.insert("operator", enumValueName(Types::ValueOperatorEquals)); params.append(param1); validEventDescriptor2.insert("paramDescriptors", params); QVariantMap validEventDescriptor3; validEventDescriptor3.insert("eventTypeId", mockEvent2EventTypeId); validEventDescriptor3.insert("deviceId", m_mockDeviceId); - validEventDescriptor3.insert("paramDescriptors", QVariantList()); // EventDescriptorList QVariantList eventDescriptorList; @@ -709,7 +713,6 @@ void TestRules::editRules_data() QVariantMap invalidEventDescriptor; invalidEventDescriptor.insert("eventTypeId", mockEvent1EventTypeId); invalidEventDescriptor.insert("deviceId", DeviceId()); - invalidEventDescriptor.insert("paramDescriptors", QVariantList()); // RuleAction event based QVariantMap validActionEventBased; @@ -736,7 +739,7 @@ void TestRules::editRules_data() QVariantMap invalidActionEventBasedParam2; invalidActionEventBasedParam2.insert("paramTypeId", mockWithParamsActionParam1ParamTypeId); invalidActionEventBasedParam2.insert("eventTypeId", mockEvent1EventTypeId); - invalidActionEventBasedParam2.insert("eventParamTypeId", "value"); + invalidActionEventBasedParam2.insert("eventParamTypeId", ParamTypeId("2c4825c8-dfb9-4ba4-bd0e-1d827d945d41")); QVariantMap invalidActionEventBasedParam3; invalidActionEventBasedParam3.insert("paramTypeId", mockWithParamsActionParam2ParamTypeId); invalidActionEventBasedParam3.insert("value", 2); @@ -799,15 +802,13 @@ void TestRules::editRules() QVariantMap eventDescriptor1; eventDescriptor1.insert("eventTypeId", mockEvent1EventTypeId); eventDescriptor1.insert("deviceId", m_mockDeviceId); - eventDescriptor1.insert("paramDescriptors", QVariantList()); QVariantMap eventDescriptor2; eventDescriptor2.insert("eventTypeId", mockEvent2EventTypeId); eventDescriptor2.insert("deviceId", m_mockDeviceId); - eventDescriptor2.insert("paramDescriptors", QVariantList()); QVariantMap eventParam1; eventParam1.insert("paramTypeId", mockEvent2EventIntParamParamTypeId); eventParam1.insert("value", 3); - eventParam1.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals)); + eventParam1.insert("operator", enumValueName(Types::ValueOperatorEquals)); eventParamDescriptors.append(eventParam1); eventDescriptor2.insert("paramDescriptors", eventParamDescriptors); @@ -818,25 +819,25 @@ void TestRules::editRules() QVariantMap stateEvaluator0; QVariantMap stateDescriptor1; stateDescriptor1.insert("deviceId", m_mockDeviceId); - stateDescriptor1.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals)); + stateDescriptor1.insert("operator", enumValueName(Types::ValueOperatorEquals)); stateDescriptor1.insert("stateTypeId", mockIntStateTypeId); stateDescriptor1.insert("value", 1); QVariantMap stateDescriptor2; stateDescriptor2.insert("deviceId", m_mockDeviceId); - stateDescriptor2.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals)); + stateDescriptor2.insert("operator", enumValueName(Types::ValueOperatorEquals)); stateDescriptor2.insert("stateTypeId", mockBoolStateTypeId); stateDescriptor2.insert("value", true); QVariantMap stateEvaluator1; stateEvaluator1.insert("stateDescriptor", stateDescriptor1); - stateEvaluator1.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd)); + stateEvaluator1.insert("operator", enumValueName(Types::StateOperatorAnd)); QVariantMap stateEvaluator2; stateEvaluator2.insert("stateDescriptor", stateDescriptor2); - stateEvaluator2.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd)); + stateEvaluator2.insert("operator", enumValueName(Types::StateOperatorAnd)); QVariantList childEvaluators; childEvaluators.append(stateEvaluator1); childEvaluators.append(stateEvaluator2); stateEvaluator0.insert("childEvaluators", childEvaluators); - stateEvaluator0.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd)); + stateEvaluator0.insert("operator", enumValueName(Types::StateOperatorAnd)); QVariantMap action1; action1.insert("actionTypeId", mockWithoutParamsActionTypeId); @@ -938,7 +939,10 @@ void TestRules::editRules() QVariantList eventDescriptors = rule.value("eventDescriptors").toList(); if (!eventDescriptor.isEmpty()) { QVERIFY2(eventDescriptors.count() == 1, "There should be exactly one eventDescriptor"); - QVERIFY2(eventDescriptors.first().toMap() == eventDescriptor, "Event descriptor doesn't match"); + QVERIFY2(eventDescriptors.first().toMap() == eventDescriptor, + QString("Event descriptor doesn't match.\nExpected:%1\nGot:%2") + .arg(QString(QJsonDocument::fromVariant(eventDescriptor).toJson())) + .arg(QString(QJsonDocument::fromVariant(eventDescriptors.first().toMap()).toJson())).toUtf8()); } else if (eventDescriptorList.isEmpty()){ QVERIFY2(eventDescriptors.count() == eventDescriptorList.count(), QString("There should be exactly %1 eventDescriptor").arg(eventDescriptorList.count()).toLatin1().data()); foreach (const QVariant &eventDescriptorVariant, eventDescriptorList) { @@ -955,7 +959,11 @@ void TestRules::editRules() } QVariantList replyActions = rule.value("actions").toList(); - QVERIFY2(actions == replyActions, "Actions don't match"); + QVERIFY2(actions == replyActions, + QString("Actions don't match.\nExpected: %1\nGot: %2") + .arg(QString(QJsonDocument::fromVariant(actions).toJson())) + .arg(QString(QJsonDocument::fromVariant(replyActions).toJson())) + .toUtf8()); QVariantList replyExitActions = rule.value("exitActions").toList(); QVERIFY2(exitActions == replyExitActions, "ExitActions don't match"); @@ -1070,7 +1078,7 @@ void TestRules::findRule() response = injectAndWait("Rules.FindRules", params); QCOMPARE(response.toMap().value("params").toMap().value("ruleIds").toList().count(), 1); - QCOMPARE(response.toMap().value("params").toMap().value("ruleIds").toList().first().toString(), ruleId.toString()); + QCOMPARE(response.toMap().value("params").toMap().value("ruleIds").toList().first().toUuid().toString(), ruleId.toString()); // REMOVE rule QVariantMap removeParams; @@ -1093,17 +1101,15 @@ void TestRules::loadStoreConfig() QVariantMap eventDescriptor1; eventDescriptor1.insert("eventTypeId", mockEvent1EventTypeId); eventDescriptor1.insert("deviceId", m_mockDeviceId); - eventDescriptor1.insert("paramDescriptors", QVariantList()); QVariantMap eventDescriptor2; eventDescriptor2.insert("eventTypeId", mockEvent2EventTypeId); eventDescriptor2.insert("deviceId", m_mockDeviceId); - eventDescriptor2.insert("paramDescriptors", QVariantList()); QVariantList eventParamDescriptors; QVariantMap eventParam1; eventParam1.insert("paramTypeId", mockEvent2EventIntParamParamTypeId); eventParam1.insert("value", 3); - eventParam1.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals)); + eventParam1.insert("operator", enumValueName(Types::ValueOperatorEquals)); eventParamDescriptors.append(eventParam1); eventDescriptor2.insert("paramDescriptors", eventParamDescriptors); @@ -1116,38 +1122,38 @@ void TestRules::loadStoreConfig() QVariantMap stateDescriptor2; stateDescriptor2.insert("deviceId", m_mockDeviceId); - stateDescriptor2.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals)); + stateDescriptor2.insert("operator", enumValueName(Types::ValueOperatorEquals)); stateDescriptor2.insert("stateTypeId", mockIntStateTypeId); stateDescriptor2.insert("value", 1); QVariantMap stateEvaluator2; stateEvaluator2.insert("stateDescriptor", stateDescriptor2); - stateEvaluator2.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd)); + stateEvaluator2.insert("operator", enumValueName(Types::StateOperatorAnd)); QVariantMap stateDescriptor3; stateDescriptor3.insert("deviceId", m_mockDeviceId); - stateDescriptor3.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals)); + stateDescriptor3.insert("operator", enumValueName(Types::ValueOperatorEquals)); stateDescriptor3.insert("stateTypeId", mockBoolStateTypeId); stateDescriptor3.insert("value", true); QVariantMap stateEvaluator3; stateEvaluator3.insert("stateDescriptor", stateDescriptor3); - stateEvaluator3.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd)); + stateEvaluator3.insert("operator", enumValueName(Types::StateOperatorAnd)); QVariantMap stateDescriptor4; stateDescriptor4.insert("interface", "battery"); stateDescriptor4.insert("interfaceState", "batteryCritical"); - stateDescriptor4.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals)); + stateDescriptor4.insert("operator", enumValueName(Types::ValueOperatorEquals)); stateDescriptor4.insert("value", true); QVariantMap stateEvaluator4; stateEvaluator4.insert("stateDescriptor", stateDescriptor4); - stateEvaluator4.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd)); + stateEvaluator4.insert("operator", enumValueName(Types::StateOperatorAnd)); childEvaluators.append(stateEvaluator2); childEvaluators.append(stateEvaluator3); childEvaluators.append(stateEvaluator4); stateEvaluator1.insert("childEvaluators", childEvaluators); - stateEvaluator1.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd)); + stateEvaluator1.insert("operator", enumValueName(Types::StateOperatorAnd)); QVariantMap action1; action1.insert("actionTypeId", mockWithoutParamsActionTypeId); @@ -1185,7 +1191,6 @@ void TestRules::loadStoreConfig() QVariantMap validEventDescriptor3; validEventDescriptor3.insert("eventTypeId", mockEvent2EventTypeId); validEventDescriptor3.insert("deviceId", m_mockDeviceId); - validEventDescriptor3.insert("paramDescriptors", QVariantList()); validEventDescriptors3.append(validEventDescriptor3); // Interface based event descriptor @@ -1322,7 +1327,11 @@ void TestRules::loadStoreConfig() expectedEventDescriptorVariant.toMap().value("deviceId") == replyEventDescriptorVariant.toMap().value("deviceId")) { found = true; qDebug() << endl << replyEventDescriptorVariant << endl << expectedEventDescriptorVariant; - QVERIFY2(replyEventDescriptorVariant == expectedEventDescriptorVariant, "EventDescriptor doesn't match"); + QVERIFY2(replyEventDescriptorVariant == expectedEventDescriptorVariant, + QString("EventDescriptor doesn't match.\nExpected: %1\nGot: %2") + .arg(QString(QJsonDocument::fromVariant(expectedEventDescriptorVariant).toJson())) + .arg(QString(QJsonDocument::fromVariant(replyEventDescriptorVariant).toJson())) + .toUtf8()); } } QVERIFY2(found, "missing eventdescriptor"); @@ -1657,7 +1666,7 @@ void TestRules::testStateChange() { QVariantMap stateEvaluator; QVariantMap stateDescriptor; stateDescriptor.insert("deviceId", m_mockDeviceId); - stateDescriptor.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorGreaterOrEqual)); + stateDescriptor.insert("operator", enumValueName(Types::ValueOperatorGreaterOrEqual)); stateDescriptor.insert("stateTypeId", mockIntStateTypeId); stateDescriptor.insert("value", 42); stateEvaluator.insert("stateDescriptor", stateDescriptor); @@ -1884,38 +1893,38 @@ void TestRules::testChildEvaluator_data() // Stateevaluators QVariantMap stateDescriptorPercentage; stateDescriptorPercentage.insert("deviceId", testDeviceId); - stateDescriptorPercentage.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorGreaterOrEqual)); + stateDescriptorPercentage.insert("operator", enumValueName(Types::ValueOperatorGreaterOrEqual)); stateDescriptorPercentage.insert("stateTypeId", mockDisplayPinPercentageStateTypeId); stateDescriptorPercentage.insert("value", 50); QVariantMap stateDescriptorDouble; stateDescriptorDouble.insert("deviceId", testDeviceId); - stateDescriptorDouble.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals)); + stateDescriptorDouble.insert("operator", enumValueName(Types::ValueOperatorEquals)); stateDescriptorDouble.insert("stateTypeId", mockDisplayPinDoubleActionDoubleParamTypeId); stateDescriptorDouble.insert("value", 20.5); QVariantMap stateDescriptorAllowedValues; stateDescriptorAllowedValues.insert("deviceId", testDeviceId); - stateDescriptorAllowedValues.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals)); + stateDescriptorAllowedValues.insert("operator", enumValueName(Types::ValueOperatorEquals)); stateDescriptorAllowedValues.insert("stateTypeId", mockDisplayPinAllowedValuesStateTypeId); stateDescriptorAllowedValues.insert("value", "String value 2"); QVariantMap stateDescriptorColor; stateDescriptorColor.insert("deviceId", testDeviceId); - stateDescriptorColor.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals)); + stateDescriptorColor.insert("operator", enumValueName(Types::ValueOperatorEquals)); stateDescriptorColor.insert("stateTypeId", mockDisplayPinColorStateTypeId); stateDescriptorColor.insert("value", "#00FF00"); QVariantMap firstStateEvaluator; - firstStateEvaluator.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorOr)); + firstStateEvaluator.insert("operator", enumValueName(Types::StateOperatorOr)); firstStateEvaluator.insert("childEvaluators", QVariantList() << createStateEvaluatorFromSingleDescriptor(stateDescriptorPercentage) << createStateEvaluatorFromSingleDescriptor(stateDescriptorDouble)); QVariantMap secondStateEvaluator; - secondStateEvaluator.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd)); + secondStateEvaluator.insert("operator", enumValueName(Types::StateOperatorAnd)); secondStateEvaluator.insert("childEvaluators", QVariantList() << createStateEvaluatorFromSingleDescriptor(stateDescriptorAllowedValues) << createStateEvaluatorFromSingleDescriptor(stateDescriptorColor)); QVariantMap stateEvaluator; - stateEvaluator.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd)); + stateEvaluator.insert("operator", enumValueName(Types::StateOperatorAnd)); stateEvaluator.insert("childEvaluators", QVariantList() << firstStateEvaluator << secondStateEvaluator); // The rule @@ -3001,7 +3010,6 @@ void TestRules::testLoopingRules() addRuleParams.insert("eventDescriptors", QVariantList() << offEvent); addRuleParams.insert("actions", QVariantList() << onAction); QVariant response = injectAndWait("Rules.AddRule", addRuleParams); - qWarning() << response; verifyRuleError(response); // Add rule 1 diff --git a/tests/auto/states/teststates.cpp b/tests/auto/states/teststates.cpp index 16ba8e73..18b34bdd 100644 --- a/tests/auto/states/teststates.cpp +++ b/tests/auto/states/teststates.cpp @@ -73,7 +73,7 @@ void TestStates::getStateValue() QVariant response = injectAndWait("Devices.GetStateValue", params); - verifyDeviceError(response, error); + verifyError(response, "deviceError", enumValueName(error)); } void TestStates::save_load_states() diff --git a/tests/auto/tags/testtags.cpp b/tests/auto/tags/testtags.cpp index a626dbe4..0384afd0 100644 --- a/tests/auto/tags/testtags.cpp +++ b/tests/auto/tags/testtags.cpp @@ -20,6 +20,7 @@ #include "nymeatestbase.h" #include "servers/mocktcpserver.h" +#include "tagging/tagsstorage.h" using namespace nymeaserver; @@ -27,6 +28,11 @@ class TestTags: public NymeaTestBase { Q_OBJECT +private: + inline void verifyTagError(const QVariant &response, TagsStorage::TagError error = TagsStorage::TagErrorNoError) { + verifyError(response, "tagError", enumValueName(error)); + } + private slots: void addTag_data(); void addTag(); @@ -37,7 +43,7 @@ private slots: private: QVariantMap createDeviceTag(const QString &deviceId, const QString &appId, const QString &tagId, const QString &value); - bool compareDeviceTag(const QVariantMap &tag, const QString &deviceId, const QString &appId, const QString &tagId, const QString &value); + bool compareDeviceTag(const QVariantMap &tag, const QUuid &deviceId, const QString &appId, const QString &tagId, const QString &value); QVariantMap createRuleTag(const QString &ruleId, const QString &appId, const QString &tagId, const QString &value); bool comapreRuleTag(const QVariantMap &tag, const QString &ruleId, const QString &appId, const QString &tagId, const QString &value); }; @@ -62,9 +68,9 @@ QVariantMap TestTags::createRuleTag(const QString &ruleId, const QString &appId, return tag; } -bool TestTags::compareDeviceTag(const QVariantMap &tag, const QString &deviceId, const QString &appId, const QString &tagId, const QString &value) +bool TestTags::compareDeviceTag(const QVariantMap &tag, const QUuid &deviceId, const QString &appId, const QString &tagId, const QString &value) { - return tag.value("deviceId").toString() == deviceId && + return tag.value("deviceId").toUuid() == deviceId && tag.value("appId").toString() == appId && tag.value("tagId").toString() == tagId && tag.value("value").toString() == value; @@ -108,7 +114,7 @@ void TestTags::addTag() // Make sure the TagAdded notification is emitted. QVariantMap notificationTagMap = checkNotification(clientSpy, "Tags.TagAdded").toMap().value("params").toMap().value("tag").toMap(); QJsonDocument jsonDoc = QJsonDocument::fromVariant(notificationTagMap); - QVERIFY2(compareDeviceTag(notificationTagMap, deviceId.toString(), appId, tagId, value), QString("Tag in notification not matching: %1").arg(qUtf8Printable(jsonDoc.toJson())).toLatin1()); + QVERIFY2(compareDeviceTag(notificationTagMap, deviceId, appId, tagId, value), QString("Tag in notification not matching: %1").arg(qUtf8Printable(jsonDoc.toJson())).toLatin1()); // Try getting the tag via GetTag params.clear(); @@ -118,7 +124,7 @@ void TestTags::addTag() response = injectAndWait("Tags.GetTags", params); QVariantList tagsList = response.toMap().value("params").toMap().value("tags").toList(); QCOMPARE(tagsList.count(), 1); - QVERIFY2(compareDeviceTag(tagsList.first().toMap(), deviceId.toString(), appId, tagId, value), "Fetched tag isn't matching the one we added"); + QVERIFY2(compareDeviceTag(tagsList.first().toMap(), deviceId, appId, tagId, value), "Fetched tag isn't matching the one we added"); } void TestTags::updateTagValue() diff --git a/tests/auto/timemanager/testtimemanager.cpp b/tests/auto/timemanager/testtimemanager.cpp index c5fd81c9..e15336f4 100644 --- a/tests/auto/timemanager/testtimemanager.cpp +++ b/tests/auto/timemanager/testtimemanager.cpp @@ -29,6 +29,11 @@ class TestTimeManager: public NymeaTestBase { Q_OBJECT +private: + inline void verifyRuleError(const QVariant &response, RuleEngine::RuleError error = RuleEngine::RuleErrorNoError) { + verifyError(response, "ruleError", enumValueName(error)); + } + private slots: void initTestCase(); @@ -41,6 +46,9 @@ private slots: void addTimeDescriptor_data(); void addTimeDescriptor(); + void addTimeDescriptorInvalidTimes_data(); + void addTimeDescriptorInvalidTimes(); + // CalendarItems void testCalendarDateTime_data(); void testCalendarDateTime(); @@ -196,7 +204,7 @@ void TestTimeManager::loadSaveTimeDescriptor_data() QTest::addColumn("timeDescriptor"); QTest::newRow("calendarItems") << createTimeDescriptorCalendar(calendarItems); - QTest::newRow("timeEventItems") << createTimeDescriptorTimeEvent(timeEventItems); +// QTest::newRow("timeEventItems") << createTimeDescriptorTimeEvent(timeEventItems); } void TestTimeManager::loadSaveTimeDescriptor() @@ -217,6 +225,7 @@ void TestTimeManager::loadSaveTimeDescriptor() ruleMap.insert("actions", QVariantList() << action); // Add the rule + qCDebug(dcTests()) << "Adding rule:" << qUtf8Printable(QJsonDocument::fromVariant(ruleMap).toJson()); QVariant response = injectAndWait("Rules.AddRule", ruleMap); verifyRuleError(response); @@ -229,6 +238,12 @@ void TestTimeManager::loadSaveTimeDescriptor() QVariantMap timeDescriptorMap = response.toMap().value("params").toMap().value("rule").toMap().value("timeDescriptor").toMap(); + QVERIFY2(timeDescriptorMap == timeDescriptor, + QString("TimeDescriptor not matching:\nExpected: %1\nGot: %2") + .arg(QString(QJsonDocument::fromVariant(timeDescriptor).toJson())) + .arg(QString(QJsonDocument::fromVariant(timeDescriptorMap).toJson())) + .toUtf8()); + // Restart the server restartServer(); @@ -238,7 +253,11 @@ void TestTimeManager::loadSaveTimeDescriptor() QVariantMap timeDescriptorMapLoaded = response.toMap().value("params").toMap().value("rule").toMap().value("timeDescriptor").toMap(); - QCOMPARE(timeDescriptorMap, timeDescriptorMapLoaded); + QVERIFY2(timeDescriptorMap == timeDescriptorMapLoaded, + QString("TimeDescriptor not matching:\nExpected: %1\nGot: %2") + .arg(QString(QJsonDocument::fromVariant(timeDescriptorMap).toJson())) + .arg(QString(QJsonDocument::fromVariant(timeDescriptorMapLoaded).toJson())) + .toUtf8()); // REMOVE rule QVariantMap removeParams; @@ -330,10 +349,8 @@ void TestTimeManager::addTimeDescriptor_data() QTest::newRow("valid: timeEventItem - weekly - multiple days") << createTimeDescriptorTimeEvent(timeEventItems) << RuleEngine::RuleErrorNoError; QTest::newRow("valid: timeEventItem - monthly - multiple days") << createTimeDescriptorTimeEvent(createTimeEventItem("23:00", repeatingOptionMonthlyMultiple)) << RuleEngine::RuleErrorNoError; - QTest::newRow("invalid: calendarItem empty") << createTimeDescriptorCalendar(createCalendarItem()) << RuleEngine::RuleErrorInvalidCalendarItem; QTest::newRow("invalid: calendarItem none") << createTimeDescriptorCalendar(createCalendarItem("00:12", 12, repeatingOptionInvalidNone)) << RuleEngine::RuleErrorInvalidRepeatingOption; QTest::newRow("invalid: calendarItem dateTime - daily") << createTimeDescriptorCalendar(createCalendarItem(QDateTime::currentDateTime().toTime_t(), 5, repeatingOptionDaily)) << RuleEngine::RuleErrorInvalidCalendarItem; - QTest::newRow("invalid: calendarItem invalid time") << createTimeDescriptorCalendar(createCalendarItem("35:80", 5)) << RuleEngine::RuleErrorInvalidCalendarItem; QTest::newRow("invalid: calendarItem invalid duration") << createTimeDescriptorCalendar(createCalendarItem("12:00", 0)) << RuleEngine::RuleErrorInvalidCalendarItem; QTest::newRow("invalid: calendarItem - monthly - weekDays") << createTimeDescriptorCalendar(createCalendarItem("13:13", 5, repeatingOptionInvalidMonthly)) << RuleEngine::RuleErrorInvalidRepeatingOption; QTest::newRow("invalid: calendarItem - weekly - monthDays") << createTimeDescriptorCalendar(createCalendarItem("15:30", 20, repeatingOptionInvalidWeekly)) << RuleEngine::RuleErrorInvalidRepeatingOption; @@ -342,10 +359,8 @@ void TestTimeManager::addTimeDescriptor_data() QTest::newRow("invalid: calendarItem - invalid monthdays (negative)") << createTimeDescriptorCalendar(createCalendarItem("13:13", 5, repeatingOptionInvalidMonthDays)) << RuleEngine::RuleErrorInvalidRepeatingOption; QTest::newRow("invalid: calendarItem - invalid monthdays (to big)") << createTimeDescriptorCalendar(createCalendarItem("13:13", 5, repeatingOptionInvalidMonthDays2)) << RuleEngine::RuleErrorInvalidRepeatingOption; - QTest::newRow("invalid: timeEventItem empty") << createTimeDescriptorTimeEvent(createTimeEventItem()) << RuleEngine::RuleErrorInvalidTimeEventItem; QTest::newRow("invalid: timeEventItem none") << createTimeDescriptorTimeEvent(createTimeEventItem("00:12", repeatingOptionInvalidNone)) << RuleEngine::RuleErrorInvalidRepeatingOption; QTest::newRow("invalid: timeEventItem - dateTime + repeatingOption") << createTimeDescriptorTimeEvent(createTimeEventItem(QDateTime::currentDateTime().toTime_t(), repeatingOptionDaily)) << RuleEngine::RuleErrorInvalidTimeEventItem; - QTest::newRow("invalid: timeEventItem invalid time") << createTimeDescriptorTimeEvent(createTimeEventItem("35:80")) << RuleEngine::RuleErrorInvalidTimeEventItem; QTest::newRow("invalid: timeEventItem - monthly - weekDays") << createTimeDescriptorTimeEvent(createTimeEventItem("13:13", repeatingOptionInvalidMonthly)) << RuleEngine::RuleErrorInvalidRepeatingOption; QTest::newRow("invalid: timeEventItem - weekly - monthDays") << createTimeDescriptorTimeEvent(createTimeEventItem("15:30", repeatingOptionInvalidWeekly)) << RuleEngine::RuleErrorInvalidRepeatingOption; QTest::newRow("invalid: timeEventItem - invalid weekdays (negative)") << createTimeDescriptorTimeEvent(createTimeEventItem("13:13", repeatingOptionInvalidWeekDays)) << RuleEngine::RuleErrorInvalidRepeatingOption; @@ -382,6 +397,34 @@ void TestTimeManager::addTimeDescriptor() verifyRuleError(response); } +void TestTimeManager::addTimeDescriptorInvalidTimes_data() +{ + QTest::addColumn("timeDescriptor"); + + QTest::newRow("invalid: calendarItem empty") << createTimeDescriptorCalendar(createCalendarItem()); + QTest::newRow("invalid: calendarItem invalid time") << createTimeDescriptorCalendar(createCalendarItem("35:80", 5)); + + QTest::newRow("invalid: timeEventItem empty") << createTimeDescriptorTimeEvent(createTimeEventItem()); + QTest::newRow("invalid: timeEventItem invalid time") << createTimeDescriptorTimeEvent(createTimeEventItem("35:80")); +} + +void TestTimeManager::addTimeDescriptorInvalidTimes() +{ + QFETCH(QVariantMap, timeDescriptor); + + // ADD the rule + QVariantMap ruleMap; QVariantMap action; + action.insert("actionTypeId", mockWithoutParamsActionTypeId); + action.insert("deviceId", m_mockDeviceId); + action.insert("ruleActionParams", QVariantList()); + ruleMap.insert("name", "TimeBased rule"); + ruleMap.insert("timeDescriptor", timeDescriptor); + ruleMap.insert("actions", QVariantList() << action); + + QVariant response = injectAndWait("Rules.AddRule", ruleMap); + QVERIFY2(response.toMap().value("status").toString() == "error", "Invalid time must fail JSON verification."); +} + void TestTimeManager::testCalendarDateTime_data() { QTest::addColumn("dateTime"); @@ -1078,25 +1121,25 @@ void TestTimeManager::testCalendarItemStates_data() QVariantMap stateEvaluator; QVariantMap stateDescriptorInt; stateDescriptorInt.insert("deviceId", m_mockDeviceId); - stateDescriptorInt.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorGreaterOrEqual)); + stateDescriptorInt.insert("operator", enumValueName(Types::ValueOperatorGreaterOrEqual)); stateDescriptorInt.insert("stateTypeId", mockIntStateTypeId); stateDescriptorInt.insert("value", 65); QVariantMap stateDescriptorBool; stateDescriptorBool.insert("deviceId", m_mockDeviceId); - stateDescriptorBool.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals)); + stateDescriptorBool.insert("operator", enumValueName(Types::ValueOperatorEquals)); stateDescriptorBool.insert("stateTypeId", mockBoolStateTypeId); stateDescriptorBool.insert("value", true); QVariantMap stateEvaluatorInt; stateEvaluatorInt.insert("stateDescriptor", stateDescriptorInt); - stateEvaluatorInt.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd)); + stateEvaluatorInt.insert("operator", enumValueName(Types::StateOperatorAnd)); QVariantMap stateEvaluatorBool; stateEvaluatorBool.insert("stateDescriptor", stateDescriptorBool); - stateEvaluatorBool.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd)); + stateEvaluatorBool.insert("operator", enumValueName(Types::StateOperatorAnd)); QVariantList childEvaluators; childEvaluators.append(stateEvaluatorInt); childEvaluators.append(stateEvaluatorBool); stateEvaluator.insert("childEvaluators", childEvaluators); - stateEvaluator.insert("operator", JsonTypes::stateOperatorToString(Types::StateOperatorAnd)); + stateEvaluator.insert("operator", enumValueName(Types::StateOperatorAnd)); // The rule @@ -1246,7 +1289,7 @@ void TestTimeManager::testCalendarItemStatesEvent_data() // State evaluator QVariantMap stateDescriptorBool; stateDescriptorBool.insert("deviceId", m_mockDeviceId); - stateDescriptorBool.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals)); + stateDescriptorBool.insert("operator", enumValueName(Types::ValueOperatorEquals)); stateDescriptorBool.insert("stateTypeId", mockBoolStateTypeId); stateDescriptorBool.insert("value", true); @@ -1880,7 +1923,7 @@ void TestTimeManager::testEventItemStates_data() // State evaluator QVariantMap stateDescriptorBool; stateDescriptorBool.insert("deviceId", m_mockDeviceId); - stateDescriptorBool.insert("operator", JsonTypes::valueOperatorToString(Types::ValueOperatorEquals)); + stateDescriptorBool.insert("operator", enumValueName(Types::ValueOperatorEquals)); stateDescriptorBool.insert("stateTypeId", mockBoolStateTypeId); stateDescriptorBool.insert("value", true); @@ -2042,7 +2085,6 @@ void TestTimeManager::verifyRuleNotExecuted() QCOMPARE(spy.count(), 1); QByteArray actionHistory = reply->readAll(); - qWarning() << "actionHistory" << actionHistory; QVERIFY2(actionHistory.isEmpty(), "Actfdsfadsion is triggered while it should not have been."); reply->deleteLater(); } @@ -2078,7 +2120,7 @@ void TestTimeManager::setIntState(const int &value) params.insert("deviceId", m_mockDeviceId); params.insert("stateTypeId", mockIntStateTypeId); QVariant response = injectAndWait("Devices.GetStateValue", params); - verifyDeviceError(response); + verifyError(response, "deviceError", "DeviceErrorNoError"); int currentStateValue = response.toMap().value("params").toMap().value("value").toInt(); bool shouldGetNotification = currentStateValue != value; @@ -2119,7 +2161,7 @@ void TestTimeManager::setBoolState(const bool &value) params.insert("deviceId", m_mockDeviceId); params.insert("stateTypeId", mockBoolStateTypeId); QVariant response = injectAndWait("Devices.GetStateValue", params); - verifyDeviceError(response); + verifyError(response, "deviceError", "DeviceErrorNoError"); bool currentStateValue = response.toMap().value("params").toMap().value("value").toBool(); bool shouldGetNotification = currentStateValue != value; diff --git a/tests/auto/usermanager/testusermanager.cpp b/tests/auto/usermanager/testusermanager.cpp index d9f9b150..629139e0 100644 --- a/tests/auto/usermanager/testusermanager.cpp +++ b/tests/auto/usermanager/testusermanager.cpp @@ -23,6 +23,7 @@ #include "logging/logengine.h" #include "nymeacore.h" #include "nymeatestbase.h" +#include "usermanager/usermanager.h" using namespace nymeaserver; diff --git a/tests/auto/webserver/testwebserver.cpp b/tests/auto/webserver/testwebserver.cpp index 24b896c9..264479c1 100644 --- a/tests/auto/webserver/testwebserver.cpp +++ b/tests/auto/webserver/testwebserver.cpp @@ -586,7 +586,7 @@ void TestWebserver::getDebugServer() QVariantMap params; QVariant response; params.insert("enabled", serverEnabled); response = injectAndWait("Configuration.SetDebugServerEnabled", params); - verifyConfigurationError(response); + verifyError(response, "configurationError", "ConfigurationErrorNoError"); QNetworkAccessManager nam; bool ok = false; diff --git a/tests/scripts/getactiontype.sh b/tests/scripts/getactiontype.sh index 94f8d2be..38f5447f 100755 --- a/tests/scripts/getactiontype.sh +++ b/tests/scripts/getactiontype.sh @@ -2,6 +2,10 @@ if [ -z $2 ]; then echo "usage: $0 host actionTypeId" -else - (echo '{"id":1, "method":"Actions.GetActionType", "params":{"actionTypeId":"'$2'"}}'; sleep 1) | nc $1 2222 + exit 1; fi + +cat << EOD | nc $1 2222 +{"id":0, "method":"JSONRPC.Hello"} +{"id":1, "method":"Actions.GetActionType", "params":{"actionTypeId":"$2"}} +EOD diff --git a/tests/scripts/getactiontypes.sh b/tests/scripts/getactiontypes.sh index 0557d377..fb03af88 100755 --- a/tests/scripts/getactiontypes.sh +++ b/tests/scripts/getactiontypes.sh @@ -2,6 +2,11 @@ if [ -z $2 ]; then echo "usage: $0 host deviceClassId" -else - (echo '{"id":1, "method":"Devices.GetActionTypes", "params":{"deviceClassId":"'$2'"}}'; sleep 1) | nc $1 2222 + exit 1 fi + + +cat <" + exit 1 fi + +if [ -z $2 ]; then +cat <init(); // Wait unitl the server is initialized QSignalSpy coreInitializedSpy(NymeaCore::instance(), SIGNAL(initialized())); QVERIFY(coreInitializedSpy.wait()); + qApp->processEvents(); + qCDebug(dcTests()) << "Nymea core instance initialized. Creating dummy user."; // Yes, we're intentionally mixing upper/lower case email here... username should not be case sensitive NymeaCore::instance()->userManager()->removeUser("dummy@guh.io"); @@ -77,7 +80,7 @@ void NymeaTestBase::initTestCase() m_apiToken = NymeaCore::instance()->userManager()->authenticate("Dummy@guh.io", "DummyPW1!", "testcase"); if (MockTcpServer::servers().isEmpty()) { - qWarning() << "no mock tcp server found"; + qCWarning(dcTests) << "no mock tcp server found"; exit(-1); } @@ -86,6 +89,7 @@ void NymeaTestBase::initTestCase() m_clientId = QUuid::createUuid(); m_mockTcpServer->clientConnected(m_clientId); + qCDebug(dcTests()) << "Starting JSON handshake"; QVariant response = injectAndWait("JSONRPC.Hello"); createMockDevice(); @@ -423,7 +427,7 @@ void NymeaTestBase::createMockDevice() QVariant response = injectAndWait("Devices.AddConfiguredDevice", params); - verifyDeviceError(response); + verifyError(response, "deviceError", "DeviceErrorNoError"); m_mockDeviceId = DeviceId(response.toMap().value("params").toMap().value("deviceId").toString()); QVERIFY2(!m_mockDeviceId.isNull(), "Newly created mock device must not be null."); diff --git a/tests/testlib/nymeatestbase.h b/tests/testlib/nymeatestbase.h index 5926462a..fea66f96 100644 --- a/tests/testlib/nymeatestbase.h +++ b/tests/testlib/nymeatestbase.h @@ -22,8 +22,6 @@ #ifndef NYMEATESTBASE_H #define NYMEATESTBASE_H -#include "jsonrpc/jsontypes.h" - #include #include #include @@ -78,25 +76,17 @@ protected: .toLatin1().data()); } - inline void verifyRuleError(const QVariant &response, RuleEngine::RuleError error = RuleEngine::RuleErrorNoError) { - verifyError(response, "ruleError", JsonTypes::ruleErrorToString(error)); + template QString enumValueName(T value) + { + QMetaEnum metaEnum = QMetaEnum::fromType(); + return metaEnum.valueToKey(value); } - inline void verifyDeviceError(const QVariant &response, Device::DeviceError error = Device::DeviceErrorNoError) { - verifyError(response, "deviceError", JsonTypes::deviceErrorToString(error)); + template T enumNameToValue(const QString &name) { + QMetaEnum metaEnum = QMetaEnum::fromType(); + return static_cast(metaEnum.keyToValue(name.toUtf8())); } - inline void verifyLoggingError(const QVariant &response, Logging::LoggingError error = Logging::LoggingErrorNoError) { - verifyError(response, "loggingError", JsonTypes::loggingErrorToString(error)); - } - - inline void verifyConfigurationError(const QVariant &response, NymeaConfiguration::ConfigurationError error = NymeaConfiguration::ConfigurationErrorNoError) { - verifyError(response, "configurationError", JsonTypes::configurationErrorToString(error)); - } - - inline void verifyTagError(const QVariant &response, TagsStorage::TagError error = TagsStorage::TagErrorNoError) { - verifyError(response, "tagError", JsonTypes::tagErrorToString(error)); - } inline void verifyParams(const QVariantList &requestList, const QVariantList &responseList, bool allRequired = true) {