Merge PR #228: Experience plugins

This commit is contained in:
Jenkins nymea 2019-12-01 00:05:00 +01:00
commit b4984d442b
153 changed files with 5669 additions and 5117 deletions

5
debian/changelog vendored
View File

@ -1,3 +1,8 @@
nymea (0.17.0) UNRELEASED; urgency=medium
-- Michael Zanetti <michael.zanetti@guh.io> Wed, 30 Oct 2019 00:32:48 +0100
nymea (0.16.0) xenial; urgency=medium
[ Michael Zanetti ]
* Add account interface

View File

@ -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 &paramType, 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 &paramType, 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
{

View File

@ -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 &paramType, 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();

View File

@ -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);

View File

@ -0,0 +1,100 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* 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 <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "experiencemanager.h"
#include "experiences/experienceplugin.h"
#include "jsonrpc/jsonrpcserverimplementation.h"
#include "loggingcategories.h"
#include <QCoreApplication>
#include <QDir>
#include <QDebug>
#include <QPluginLoader>
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<ExperiencePlugin*>(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);
}
}

View File

@ -0,0 +1,59 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* 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 <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef EXPERIENCEMANAGER_H
#define EXPERIENCEMANAGER_H
#include <QObject>
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<ExperiencePlugin*> m_plugins;
};
}
#endif // EXPERIENCEMANAGER_H

View File

@ -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<Types::InputType>();
registerEnum<Types::Unit>();
// Objects
registerObject<ParamType, ParamTypes>();
registerObject<Param, ParamList>();
registerObject<ActionType>();
registerObject<Action>();
// 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<ParamList>());
returns.insert("deviceError", enumRef<Device::DeviceError>());
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<Device::DeviceError>());
returns.insert("o:actionType", objectRef<ActionType>());
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<Device::DeviceError>());
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<ParamList>());
returns.insert("deviceError", enumRef<Device::DeviceError>());
registerMethod("ExecuteBrowserItemAction", description, params, returns, "Please use Devices.ExecuteBrowserItem instead.");
}
@ -96,7 +104,7 @@ JsonReply* ActionHandler::ExecuteAction(const QVariantMap &params)
{
DeviceId deviceId(params.value("deviceId").toString());
ActionTypeId actionTypeId(params.value("actionTypeId").toString());
ParamList actionParams = JsonTypes::unpackParams(params.value("params").toList());
ParamList actionParams = unpack<ParamList>(params.value("params"));
QLocale locale = params.value("locale").toLocale();
Action action(actionTypeId, deviceId);
@ -105,8 +113,9 @@ JsonReply* ActionHandler::ExecuteAction(const QVariantMap &params)
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 &params)
JsonReply *ActionHandler::GetActionType(const QVariantMap &params) 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::DeviceError>(Device::DeviceErrorNoError));
data.insert("actionType", pack(translatedActionType));
return createReply(data);
}
}
}
return createReply(statusToReply(Device::DeviceErrorActionTypeNotFound));
QVariantMap data;
data.insert("deviceError", enumValueName<Device::DeviceError>(Device::DeviceErrorActionTypeNotFound));
return createReply(data);
}
JsonReply *ActionHandler::ExecuteBrowserItem(const QVariantMap &params)
@ -142,8 +158,10 @@ JsonReply *ActionHandler::ExecuteBrowserItem(const QVariantMap &params)
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<Device::DeviceError>(info->status()));
jsonReply->setData(data);
jsonReply->finished();
});
@ -155,14 +173,16 @@ JsonReply *ActionHandler::ExecuteBrowserItemAction(const QVariantMap &params)
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<ParamList>(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<Device::DeviceError>(info->status()));
jsonReply->setData(data);
jsonReply->finished();
});

View File

@ -22,7 +22,7 @@
#ifndef ACTIONHANDLER_H
#define ACTIONHANDLER_H
#include "jsonhandler.h"
#include "jsonrpc/jsonhandler.h"
#include "devices/devicemanager.h"
namespace nymeaserver {

View File

@ -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<NymeaConfiguration::ConfigurationError>();
// Objects
registerObject<ServerConfiguration>();
registerObject<WebServerConfiguration>();
registerObject<MqttPolicy>();
// 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<ServerConfiguration>());
returns.insert("tcpServerConfigurations", tcpServerConfigurations);
QVariantList webServerConfigurations;
webServerConfigurations.append(JsonTypes::webServerConfigurationRef());
webServerConfigurations.append(objectRef<WebServerConfiguration>());
returns.insert("webServerConfigurations", webServerConfigurations);
QVariantList webSocketServerConfigurations;
webSocketServerConfigurations.append(JsonTypes::serverConfigurationRef());
webSocketServerConfigurations.append(objectRef<ServerConfiguration>());
returns.insert("webSocketServerConfigurations", webSocketServerConfigurations);
QVariantList mqttServerConfigurations;
mqttServerConfigurations.append(JsonTypes::serverConfigurationRef());
mqttServerConfigurations.append(objectRef<ServerConfiguration>());
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<NymeaConfiguration::ConfigurationError>());
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<NymeaConfiguration::ConfigurationError>());
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<NymeaConfiguration::ConfigurationError>());
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<NymeaConfiguration::ConfigurationError>());
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<ServerConfiguration>());
returns.insert("configurationError", enumRef<NymeaConfiguration::ConfigurationError>());
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<NymeaConfiguration::ConfigurationError>());
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<ServerConfiguration>());
returns.insert("configurationError", enumRef<NymeaConfiguration::ConfigurationError>());
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<NymeaConfiguration::ConfigurationError>());
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<WebServerConfiguration>());
returns.insert("configurationError", enumRef<NymeaConfiguration::ConfigurationError>());
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<NymeaConfiguration::ConfigurationError>());
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<NymeaConfiguration::ConfigurationError>());
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<ServerConfiguration>());
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<ServerConfiguration>());
returns.insert("configurationError", enumRef<NymeaConfiguration::ConfigurationError>());
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<NymeaConfiguration::ConfigurationError>());
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<MqttPolicy>());
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<MqttPolicy>());
returns.insert("configurationError", enumRef<NymeaConfiguration::ConfigurationError>());
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<NymeaConfiguration::ConfigurationError>());
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<ServerConfiguration>());
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<ServerConfiguration>());
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<ServerConfiguration>());
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<WebServerConfiguration>());
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<MqttPolicy>());
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 &params) 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 &params) const
JsonReply *ConfigurationHandler::SetTcpServerConfiguration(const QVariantMap &params) const
{
ServerConfiguration config = JsonTypes::unpackServerConfiguration(params.value("configuration").toMap());
ServerConfiguration config = unpack<ServerConfiguration>(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 &params) const
{
WebServerConfiguration config = JsonTypes::unpackWebServerConfiguration(params.value("configuration").toMap());
WebServerConfiguration config = unpack<WebServerConfiguration>(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 &params) const
{
ServerConfiguration config = JsonTypes::unpackServerConfiguration(params.value("configuration").toMap());
ServerConfiguration config = unpack<ServerConfiguration>(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 &params) const
{
ServerConfiguration config = JsonTypes::unpackServerConfiguration(params.value("configuration").toMap());
ServerConfiguration config = unpack<ServerConfiguration>(params.value("configuration").toMap());
if (config.id.isEmpty()) {
return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidId));
}
@ -540,7 +529,7 @@ JsonReply *ConfigurationHandler::GetMqttPolicies(const QVariantMap &params) 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 &params) cons
JsonReply *ConfigurationHandler::SetMqttPolicy(const QVariantMap &params) const
{
MqttPolicy policy = JsonTypes::unpackMqttPolicy(params.value("policy").toMap());
MqttPolicy policy = unpack<MqttPolicy>(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<NymeaConfiguration::ConfigurationError>(status));
return returns;
}
void ConfigurationHandler::onCloudConfigurationChanged(bool enabled)
{
qCDebug(dcJsonRpc()) << "Notification: cloud configuration changed";

View File

@ -23,7 +23,8 @@
#include <QObject>
#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;
};
}

File diff suppressed because it is too large Load Diff

View File

@ -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 &params) const;
Q_INVOKABLE JsonReply *GetBrowserItem(const QVariantMap &params) const;
Q_INVOKABLE JsonReply *ExecuteAction(const QVariantMap &params);
Q_INVOKABLE JsonReply *ExecuteBrowserItem(const QVariantMap &params);
Q_INVOKABLE JsonReply *ExecuteBrowserItemAction(const QVariantMap &params);
static QVariantMap packBrowserItem(const BrowserItem &item);
signals:
void PluginConfigurationChanged(const QVariantMap &params);
void StateChanged(const QVariantMap &params);
@ -67,6 +73,7 @@ signals:
void DeviceAdded(const QVariantMap &params);
void DeviceChanged(const QVariantMap &params);
void DeviceSettingChanged(const QVariantMap &params);
void EventTriggered(const QVariantMap &params);
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 &paramTypeId, const QVariant &value);
private:
QVariantMap statusToReply(Device::DeviceError status) const;
};
}

View File

@ -47,23 +47,27 @@ namespace nymeaserver {
EventHandler::EventHandler(QObject *parent) :
JsonHandler(parent)
{
QVariantMap params;
QVariantMap returns;
registerEnum<Types::InputType>();
registerEnum<Types::Unit>();
// Objects
registerObject<Param, ParamList>();
registerObject<Event>();
registerObject<ParamType, ParamTypes>();
registerObject<EventType>();
// Methods
QString description; QVariantMap params; QVariantMap returns;
description = "Get the EventType for the given eventTypeId.";
params.insert("eventTypeId", enumValueName(Uuid));
returns.insert("deviceError", enumRef<Device::DeviceError>());
returns.insert("o:eventType", objectRef<EventType>());
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<Event>());
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 &params) 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::DeviceError>(Device::DeviceErrorNoError));
data.insert("eventType", pack(translatedEventType));
return createReply(data);
}
}
}
return createReply(statusToReply(Device::DeviceErrorEventTypeNotFound));
QVariantMap data;
data.insert("deviceError", enumValueName<Device::DeviceError>(Device::DeviceErrorEventTypeNotFound));
return createReply(data);
}
}

View File

@ -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 &params) const;

View File

@ -1,354 +0,0 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stürz <simon.stuerz@guh.io> *
* Copyright (C) 2014 Michael Zanetti <michael_zanetti@gmx.net> *
* *
* 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 <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*!
\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 &params);
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 <QMetaMethod>
#include <QDebug>
#include <QRegExp>
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<bool, QString> JsonHandler::validateParams(const QString &methodName, const QVariantMap &params)
{
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<bool, QString> 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 &params)
{
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<JsonHandler*>(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<JsonHandler*>(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;
}
}

View File

@ -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<BasicType>();
registerEnum<UserManager::UserError>();
registerEnum<CloudManager::CloudConnectionState>();
// Objects
registerObject<TokenInfo>();
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<UserManager::UserError>());
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<UserManager::UserError>());
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<CloudManager::CloudConnectionState>());
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<CloudManager::CloudConnectionState>());
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 &params)
JsonReply *JsonRPCServerImplementation::Hello(const QVariantMap &params)
{
Q_UNUSED(params);
TransportInterface *interface = reinterpret_cast<TransportInterface*>(property("transportInterface").toLongLong());
qCDebug(dcJsonRpc()) << params;
@ -266,38 +265,13 @@ JsonReply *JsonRPCServer::Hello(const QVariantMap &params)
return createReply(createWelcomeMessage(interface, clientId));
}
JsonReply* JsonRPCServer::Introspect(const QVariantMap &params) const
JsonReply* JsonRPCServerImplementation::Introspect(const QVariantMap &params) 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 &params) const
JsonReply* JsonRPCServerImplementation::Version(const QVariantMap &params) const
{
Q_UNUSED(params)
@ -307,7 +281,7 @@ JsonReply* JsonRPCServer::Version(const QVariantMap &params) const
return createReply(data);
}
JsonReply* JsonRPCServer::SetNotificationStatus(const QVariantMap &params)
JsonReply* JsonRPCServerImplementation::SetNotificationStatus(const QVariantMap &params)
{
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 &params)
return createReply(returns);
}
JsonReply *JsonRPCServer::CreateUser(const QVariantMap &params)
JsonReply *JsonRPCServerImplementation::CreateUser(const QVariantMap &params)
{
QString username = params.value("username").toString();
QString password = params.value("password").toString();
@ -342,11 +316,11 @@ JsonReply *JsonRPCServer::CreateUser(const QVariantMap &params)
UserManager::UserError status = NymeaCore::instance()->userManager()->createUser(username, password);
QVariantMap returns;
returns.insert("error", JsonTypes::userErrorToString(status));
returns.insert("error", enumValueName<UserManager::UserError>(status));
return createReply(returns);
}
JsonReply *JsonRPCServer::Authenticate(const QVariantMap &params)
JsonReply *JsonRPCServerImplementation::Authenticate(const QVariantMap &params)
{
QString username = params.value("username").toString();
QString password = params.value("password").toString();
@ -361,7 +335,7 @@ JsonReply *JsonRPCServer::Authenticate(const QVariantMap &params)
return createReply(ret);
}
JsonReply *JsonRPCServer::RequestPushButtonAuth(const QVariantMap &params)
JsonReply *JsonRPCServerImplementation::RequestPushButtonAuth(const QVariantMap &params)
{
QString deviceName = params.value("deviceName").toString();
QUuid clientId = this->property("clientId").toUuid();
@ -376,36 +350,32 @@ JsonReply *JsonRPCServer::RequestPushButtonAuth(const QVariantMap &params)
return createReply(data);
}
JsonReply *JsonRPCServer::Tokens(const QVariantMap &params) const
JsonReply *JsonRPCServerImplementation::Tokens(const QVariantMap &params) 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<TokenInfo> 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 &params)
JsonReply *JsonRPCServerImplementation::RemoveToken(const QVariantMap &params)
{
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<UserManager::UserError>(error));
return createReply(ret);
}
JsonReply *JsonRPCServer::SetupCloudConnection(const QVariantMap &params)
JsonReply *JsonRPCServerImplementation::SetupCloudConnection(const QVariantMap &params)
{
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 &params)
return createReply(ret);
}
JsonReply *JsonRPCServer::SetupRemoteAccess(const QVariantMap &params)
JsonReply *JsonRPCServerImplementation::SetupRemoteAccess(const QVariantMap &params)
{
QString idToken = params.value("idToken").toString();
QString userId = params.value("userId").toString();
@ -437,18 +407,18 @@ JsonReply *JsonRPCServer::SetupRemoteAccess(const QVariantMap &params)
return reply;
}
JsonReply *JsonRPCServer::IsCloudConnected(const QVariantMap &params)
JsonReply *JsonRPCServerImplementation::IsCloudConnected(const QVariantMap &params)
{
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<CloudManager::CloudConnectionState>(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 &params)
JsonReply *JsonRPCServerImplementation::KeepAlive(const QVariantMap &params)
{
QString sessionId = params.value("sessionId").toString();
qCDebug(dcJsonRpc()) << "KeepAlive received" << sessionId;
@ -459,42 +429,55 @@ JsonReply *JsonRPCServer::KeepAlive(const QVariantMap &params)
}
/*! Returns the list of registered \l{JsonHandler}{JsonHandlers} and their name.*/
QHash<QString, JsonHandler *> JsonRPCServer::handlers() const
QHash<QString, JsonHandler *> 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 &params)
void JsonRPCServerImplementation::sendResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QVariantMap &params, 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<bool, QString> 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 &params)
void JsonRPCServerImplementation::sendNotification(const QVariantMap &params)
{
JsonHandler *handler = qobject_cast<JsonHandler *>(sender());
QMetaMethod method = handler->metaObject()->method(senderSignalIndex());
QList<QUuid> 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<JsonReply *>(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<CloudManager::CloudConnectionState>(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 &notificationName, 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<TransportInterface *>(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);

View File

@ -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<QString, JsonHandler *> handlers() const;
void sendResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QVariantMap &params = QVariantMap());
void sendResponse(TransportInterface *interface, const QUuid &clientId, int commandId, const QVariantMap &params = 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<JsonHandler*, QString> m_experiences;
QMap<TransportInterface*, bool> m_interfaces; // Interface, authenticationRequired
QHash<QString, JsonHandler *> m_handlers;
QHash<JsonReply *, TransportInterface *> 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

File diff suppressed because it is too large Load Diff

View File

@ -1,292 +0,0 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stürz <simon.stuerz@guh.io> *
* Copyright (C) 2014 Michael Zanetti <michael_zanetti@gmx.net> *
* Copyright (C) 2017 Michael Zanetti <michael.zanetti@guh.io> *
* *
* 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 <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#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 <QObject>
#include <QVariantMap>
#include <QString>
#include <QMetaEnum>
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<className::enumName>(); \
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 &param);
static QVariantMap packBrowserItem(const BrowserItem &item);
static QVariantMap packParamType(const ParamType &paramType, const PluginId &pluginId, const QLocale &locale);
static QVariantMap packParamDescriptor(const ParamDescriptor &paramDescriptor);
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 &paramList);
static QVariantList packBrowserItems(const BrowserItems &items);
static QVariantList packRules(const QList<Rule> 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<DeviceDescriptor> 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<Rule> &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 &paramMap);
static ParamList unpackParams(const QVariantList &paramList);
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 &paramDescriptorMap);
static QList<ParamDescriptor> unpackParamDescriptors(const QVariantList &paramDescriptorList);
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<bool, QString> validateMap(const QVariantMap &templateMap, const QVariantMap &map);
static QPair<bool, QString> validateProperty(const QVariant &templateValue, const QVariant &value);
static QPair<bool, QString> validateList(const QVariantList &templateList, const QVariantList &list);
static QPair<bool, QString> validateVariant(const QVariant &templateVariant, const QVariant &variant);
static QPair<bool, QString> validateEnum(const QVariantList &enumList, const QVariant &value);
static QPair<bool, QString> validateBasicType(const QVariant &variant);
private:
static bool s_initialized;
static void init();
static QPair<bool, QString> report(bool status, const QString &message);
static QVariantList enumToStrings(const QMetaObject &metaObject, const QString &enumName);
static QString s_lastError;
};
}
#endif // JSONTYPES_H

View File

@ -0,0 +1,278 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* 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 <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "jsonvalidator.h"
#include "jsonrpc/jsonhandler.h"
#include "loggingcategories.h"
#include <QJsonDocument>
#include <QColor>
#include <QDateTime>
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 &params, 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 &params, const QString &notification, 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<JsonHandler::BasicType>(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<QColor>();
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);
}
}

View File

@ -0,0 +1,70 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* 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 <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef JSONVALIDATOR_H
#define JSONVALIDATOR_H
#include <QPair>
#include <QVariant>
#include <QIODevice>
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 &params, const QString &method, const QVariantMap &api);
Result validateReturns(const QVariantMap &returns, const QString &method, const QVariantMap &api);
Result validateNotificationParams(const QVariantMap &params, const QString &notification, 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

View File

@ -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<Logging::LoggingSource>();
registerEnum<Logging::LoggingLevel>();
registerEnum<Logging::LoggingEventType>();
registerEnum<Logging::LoggingError>();
QVariantMap timeFilter;
params.clear(); returns.clear();
setDescription("GetLogEntries", "Get the LogEntries matching the given filter. "
// Objects
registerObject<LogEntry, LogEntries>();
// 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<Logging::LoggingSource>());
params.insert("o:loggingLevels", QVariantList() << enumRef<Logging::LoggingLevel>());
params.insert("o:eventTypes", QVariantList() << enumRef<Logging::LoggingEventType>());
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<Logging::LoggingError>());
returns.insert("o:logEntries", objectRef<LogEntries>());
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<LogEntry>());
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 &params) 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::LoggingError>(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<Logging::LoggingLevel>(logEntry.level()));
logEntryMap.insert("source", enumValueName<Logging::LoggingSource>(logEntry.source()));
logEntryMap.insert("eventType", enumValueName<Logging::LoggingEventType>(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<RuleEngine::RuleError>(static_cast<RuleEngine::RuleError>(logEntry.errorCode())));
break;
case Logging::LoggingSourceActions:
case Logging::LoggingSourceEvents:
case Logging::LoggingSourceStates:
case Logging::LoggingSourceBrowserActions:
logEntryMap.insert("errorCode", enumValueName<Device::DeviceError>(static_cast<Device::DeviceError>(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<Logging::LoggingSource>(source.toString()));
}
}
if (logFilterMap.contains("loggingLevels")) {
QVariantList loggingLevels = logFilterMap.value("loggingLevels").toList();
foreach (const QVariant &level, loggingLevels) {
filter.addLoggingLevel(enumNameToValue<Logging::LoggingLevel>(level.toString()));
}
}
if (logFilterMap.contains("eventTypes")) {
QVariantList eventTypes = logFilterMap.value("eventTypes").toList();
foreach (const QVariant &eventType, eventTypes) {
filter.addLoggingEventType(enumNameToValue<Logging::LoggingEventType>(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;
}
}

View File

@ -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 &params);
void LogDatabaseUpdated(const QVariantMap &params);
private:
static QVariantMap packLogEntry(const LogEntry &logEntry);
static LogFilter unpackLogFilter(const QVariantMap &logFilterMap);
private slots:
void logEntryAdded(const LogEntry &entry);
void logDatabaseUpdated();

View File

@ -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<NetworkManager::NetworkManagerError>();
registerEnum<NetworkManager::NetworkManagerState>();
registerEnum<NetworkDevice::NetworkDeviceState>();
params.clear(); returns.clear();
setDescription("GetNetworkStatus", "Get the current network manager status.");
setParams("GetNetworkStatus", params);
// Objects
registerUncreatableObject<WirelessAccessPoint>();
registerUncreatableObject<WiredNetworkDevice>();
QVariantMap wirelessNetworkDevice;
wirelessNetworkDevice.insert("interface", enumValueName(String));
wirelessNetworkDevice.insert("macAddress", enumValueName(String));
wirelessNetworkDevice.insert("state", enumRef<NetworkDevice::NetworkDeviceState>());
wirelessNetworkDevice.insert("bitRate", enumValueName(String));
wirelessNetworkDevice.insert("o:currentAccessPoint", objectRef<WirelessAccessPoint>());
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<NetworkManager::NetworkManagerState>());
returns.insert("o:status", status);
returns.insert("networkManagerError", JsonTypes::networkManagerErrorRef());
setReturns("GetNetworkStatus", returns);
returns.insert("networkManagerError", enumRef<NetworkManager::NetworkManagerError>());
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<NetworkManager::NetworkManagerError>());
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<NetworkManager::NetworkManagerError>());
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<NetworkManager::NetworkManagerError>());
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<NetworkManager::NetworkManagerError>());
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<NetworkManager::NetworkManagerError>());
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<NetworkManager::NetworkManagerError>());
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<NetworkManager::NetworkManagerError>());
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 &params)
{
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 &params)
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 &params)
{
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<NetworkManager::NetworkManagerError>(status));
return returns;
}
}

View File

@ -23,7 +23,8 @@
#include <QObject>
#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;
};
}

View File

@ -58,6 +58,7 @@
#include "loggingcategories.h"
#include <QDebug>
#include <QJsonDocument>
namespace nymeaserver {
@ -65,26 +66,49 @@ namespace nymeaserver {
RulesHandler::RulesHandler(QObject *parent) :
JsonHandler(parent)
{
QVariantMap params;
QVariantMap returns;
// Enums
registerEnum<RuleEngine::RuleError>();
registerEnum<Types::ValueOperator>();
registerEnum<Types::StateOperator>();
registerEnum<RepeatingOption::RepeatingMode>();
// 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<ParamDescriptor, ParamDescriptors>();
registerObject<EventDescriptor, EventDescriptors>();
registerObject<StateDescriptor>();
registerObject<StateEvaluator, StateEvaluators>();
registerObject<RepeatingOption>();
registerObject<CalendarItem, CalendarItems>();
registerObject<TimeEventItem, TimeEventItems>();
registerObject<TimeDescriptor>();
registerObject<RuleActionParam, RuleActionParams>();
registerObject<RuleAction, RuleActions>();
registerObject<Rule, Rules>();
// 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<RuleEngine::RuleError>());
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<RuleEngine::RuleError>());
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<RuleEngine::RuleError>());
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<RuleEngine::RuleError>());
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<RuleEngine::RuleError>());
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<RuleEngine::RuleError>());
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<RuleEngine::RuleError>());
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<RuleEngine::RuleError>());
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 &params)
{
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 &params)
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::RuleError>(RuleEngine::RuleErrorRuleNotFound));
return createReply(data);
}
QVariantMap returns = statusToReply(RuleEngine::RuleErrorNoError);
returns.insert("rule", JsonTypes::packRule(rule));
QVariantMap returns;
returns.insert("ruleError", enumValueName<RuleEngine::RuleError>(RuleEngine::RuleErrorNoError));
returns.insert("rule", pack(rule));
return createReply(returns);
}
JsonReply* RulesHandler::AddRule(const QVariantMap &params)
{
Rule rule = JsonTypes::unpackRule(params);
Rule rule = unpack<Rule>(params);
rule.setId(RuleId::createRuleId());
RuleEngine::RuleError status = NymeaCore::instance()->ruleEngine()->addRule(rule);
@ -237,19 +260,23 @@ JsonReply* RulesHandler::AddRule(const QVariantMap &params)
if (status == RuleEngine::RuleErrorNoError) {
returns.insert("ruleId", rule.id().toString());
}
returns.insert("ruleError", JsonTypes::ruleErrorToString(status));
returns.insert("ruleError", enumValueName<RuleEngine::RuleError>(status));
return createReply(returns);
}
JsonReply *RulesHandler::EditRule(const QVariantMap &params)
{
Rule rule = JsonTypes::unpackRule(params);
Rule rule = unpack<Rule>(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<RuleEngine::RuleError>(status));
return createReply(returns);
}
@ -258,7 +285,7 @@ JsonReply* RulesHandler::RemoveRule(const QVariantMap &params)
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<RuleEngine::RuleError>(status));
return createReply(returns);
}
@ -279,12 +306,18 @@ JsonReply *RulesHandler::FindRules(const QVariantMap &params)
JsonReply *RulesHandler::EnableRule(const QVariantMap &params)
{
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<RuleEngine::RuleError>(status));
return createReply(ret);
}
JsonReply *RulesHandler::DisableRule(const QVariantMap &params)
{
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<RuleEngine::RuleError>(status));
return createReply(ret);
}
JsonReply *RulesHandler::ExecuteActions(const QVariantMap &params)
@ -292,7 +325,7 @@ JsonReply *RulesHandler::ExecuteActions(const QVariantMap &params)
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<RuleEngine::RuleError>(status));
return createReply(returns);
}
@ -301,7 +334,7 @@ JsonReply *RulesHandler::ExecuteExitActions(const QVariantMap &params)
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<RuleEngine::RuleError>(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;
}
}

View File

@ -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);
};
}

View File

@ -42,16 +42,17 @@ namespace nymeaserver {
StateHandler::StateHandler(QObject *parent) :
JsonHandler(parent)
{
QVariantMap params;
QVariantMap returns;
registerEnum<Types::Unit>();
registerObject<State>();
registerObject<StateType>();
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<Device::DeviceError>());
returns.insert("o:stateType", objectRef<StateType>());
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 &params) 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::DeviceError>(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::DeviceError>(Device::DeviceErrorStateTypeNotFound));
return createReply(data);
}
}

View File

@ -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 &params) const;

View File

@ -32,146 +32,133 @@ SystemHandler::SystemHandler(Platform *platform, QObject *parent):
JsonHandler(parent),
m_platform(platform)
{
// Objects
registerObject<Package, Packages>();
registerObject<Repository, Repositories>();
// 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 &params)
JsonReply *SystemHandler::Reboot(const QVariantMap &params) 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 &params) const
JsonReply *SystemHandler::Shutdown(const QVariantMap &params) 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 &params) 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 &params) const
JsonReply *SystemHandler::GetRepositories(const QVariantMap &params) 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);

View File

@ -23,9 +23,11 @@
#include <QObject>
#include "jsonhandler.h"
#include "jsonrpc/jsonhandler.h"
#include "platform/platform.h"
#include "platform/package.h"
#include "platform/repository.h"
namespace nymeaserver {

View File

@ -27,51 +27,52 @@ namespace nymeaserver {
TagsHandler::TagsHandler(QObject *parent) : JsonHandler(parent)
{
QVariantMap params;
QVariantMap returns;
// Enums
registerEnum<TagsStorage::TagError>();
// Objects
registerObject<Tag, Tags>();
// 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<TagsStorage::TagError>());
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<TagsStorage::TagError>());
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<TagsStorage::TagError>());
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 &params) 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 &params) const
JsonReply *TagsHandler::AddTag(const QVariantMap &params) const
{
Tag tag = JsonTypes::unpackTag(params.value("tag").toMap());
Tag tag = unpack<Tag>(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 &params) const
JsonReply *TagsHandler::RemoveTag(const QVariantMap &params) const
{
Tag tag = JsonTypes::unpackTag(params.value("tag").toMap());
Tag tag = unpack<Tag>(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<TagsStorage::TagError>(status));
return returns;
}
}

View File

@ -23,7 +23,8 @@
#include <QObject>
#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;
};
}

View File

@ -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 \

View File

@ -38,12 +38,17 @@
#include "logentry.h"
#include "nymeacore.h"
#include "jsonrpc/jsontypes.h"
#include <QDebug>
#include <QMetaEnum>
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<Logging::LoggingSource>();
dbg.nospace() << " source: " << metaEnum.valueToKey(entry.source()) << endl;
metaEnum = QMetaEnum::fromType<Logging::LoggingLevel>();
dbg.nospace() << " level: " << metaEnum.valueToKey(entry.level()) << endl;
metaEnum = QMetaEnum::fromType<Logging::LoggingEventType>();
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<LogEntry> &other): QList<LogEntry>(other)
{
}
QVariant LogEntries::get(int index) const
{
return QVariant::fromValue(at(index));
}
void LogEntries::put(const QVariant &variant)
{
append(variant.value<LogEntry>());
}
}

View File

@ -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<LogEntry>
{
Q_GADGET
Q_PROPERTY(int count READ count)
public:
LogEntries();
LogEntries(const QList<LogEntry> &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

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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();
}

View File

@ -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<RuleId> m_executingRules;

View File

@ -49,7 +49,7 @@ Rule::Rule():
m_eventDescriptors(QList<EventDescriptor>()),
m_actions(QList<RuleAction>()),
m_exitActions(QList<RuleAction>()),
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<EventDescriptor> Rule::eventDescriptors() const
EventDescriptors Rule::eventDescriptors() const
{
return m_eventDescriptors;
}
/*! Sets the \a eventDescriptors of this \l{Rule}. */
void Rule::setEventDescriptors(const QList<EventDescriptor> &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<RuleAction> Rule::actions() const
RuleActions Rule::actions() const
{
return m_actions;
}
/*! Sets the \a actions of this \l{Rule}. */
void Rule::setActions(const QList<RuleAction> 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<RuleAction> Rule::exitActions() const
RuleActions Rule::exitActions() const
{
return m_exitActions;
}
/*! Sets the \a exitActions of this \l{Rule}. */
void Rule::setExitActions(const QList<RuleAction> 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<Rule> &other): QList<Rule>(other)
{
}
QVariant Rules::get(int index) const
{
return QVariant::fromValue(at(index));
}
void Rules::put(const QVariant &variant)
{
append(variant.value<Rule>());
}
}

View File

@ -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<EventDescriptor> eventDescriptors() const;
void setEventDescriptors(const QList<EventDescriptor> &eventDescriptors);
EventDescriptors eventDescriptors() const;
void setEventDescriptors(const EventDescriptors &eventDescriptors);
QList<RuleAction> actions() const;
void setActions(const QList<RuleAction> actions);
RuleActions actions() const;
void setActions(const RuleActions actions);
QList<RuleAction> exitActions() const;
void setExitActions(const QList<RuleAction> 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<EventDescriptor> m_eventDescriptors;
QList<RuleAction> m_actions;
QList<RuleAction> 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<Rule>
{
Q_GADGET
Q_PROPERTY(int count READ count)
public:
Rules();
Rules(const QList<Rule> &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

View File

@ -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 &params):
RuleAction::RuleAction(const ActionTypeId &actionTypeId, const DeviceId &deviceId, const RuleActionParams &params):
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 &params) :
RuleAction::RuleAction(const QString &interface, const QString &interfaceAction, const RuleActionParams &params) :
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<RuleAction> &ruleActionList)
}
return dbg;
}
RuleActions::RuleActions()
{
}
RuleActions::RuleActions(const QList<RuleAction> &other): QList<RuleAction>(other)
{
}
QVariant RuleActions::get(int index) const
{
return QVariant::fromValue(at(index));
}
void RuleActions::put(const QVariant &variant)
{
append(variant.value<RuleAction>());
}

View File

@ -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 &params = RuleActionParamList());
explicit RuleAction(const QString &interface, const QString &interfaceAction, const RuleActionParamList &params = RuleActionParamList());
explicit RuleAction(const ActionTypeId &actionTypeId = ActionTypeId(), const DeviceId &deviceId = DeviceId(), const RuleActionParams &params = RuleActionParams());
explicit RuleAction(const QString &interface, const QString &interfaceAction, const RuleActionParams &params = 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<RuleAction>
{
Q_GADGET
Q_PROPERTY(int count READ count)
public:
RuleActions();
RuleActions(const QList<RuleAction> &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<RuleAction> &ruleActionList);

View File

@ -124,12 +124,22 @@ ParamTypeId RuleActionParam::paramTypeId() const
return m_paramTypeId;
}
void RuleActionParam::setParamTypeId(const ParamTypeId &paramTypeId)
{
m_paramTypeId = paramTypeId;
}
/*! Returns the name of this RuleActionParam. */
QString RuleActionParam::paramName() const
{
return m_paramName;
}
void RuleActionParam::setParamName(const QString &paramName)
{
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 &param, *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 &param, *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<RuleActionParam>());
}

View File

@ -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 &param = Param());
RuleActionParam(const ParamTypeId &paramTypeId, const QVariant &value = QVariant());
@ -44,7 +53,10 @@ public:
RuleActionParam(const QString &paramName, const DeviceId &stateDeviceId, const StateTypeId &stateTypeId);
ParamTypeId paramTypeId() const;
void setParamTypeId(const ParamTypeId &paramTypeId);
QString paramName() const;
void setParamName(const QString &paramName);
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<RuleActionParam>
class LIBNYMEA_EXPORT RuleActionParams: public QList<RuleActionParam>
{
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<ParamTypeId> m_ids;
};
QDebug operator<<(QDebug dbg, const RuleActionParamList &ruleActionParams);
QDebug operator<<(QDebug dbg, const RuleActionParams &ruleActionParams);
#endif // RULEACTIONPARAM_H

View File

@ -1264,7 +1264,7 @@ QList<RuleAction> 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<int> weekDays;

View File

@ -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> 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<StateEvaluator> &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<StateEvaluator> &other): QList<StateEvaluator>(other)
{
}
QVariant StateEvaluators::get(int index) const
{
return QVariant::fromValue(at(index));
}
void StateEvaluators::put(const QVariant &variant)
{
append(variant.value<StateEvaluator>());
}
}

View File

@ -30,17 +30,34 @@
class NymeaSettings;
namespace nymeaserver {
class StateEvaluator;
class StateEvaluators: public QList<StateEvaluator>
{
Q_GADGET
Q_PROPERTY(int count READ count)
public:
StateEvaluators();
StateEvaluators(const QList<StateEvaluator> &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<StateEvaluator> childEvaluators = QList<StateEvaluator>(), Types::StateOperator stateOperator = Types::StateOperatorAnd);
StateDescriptor stateDescriptor() const;
void setStateDescriptor(const StateDescriptor &stateDescriptor);
QList<StateEvaluator> childEvaluators() const;
void setChildEvaluators(const QList<StateEvaluator> &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

View File

@ -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;
}

View File

@ -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<QString, TcpServer*> m_tcpServers;

View File

@ -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<Tag> &other): QList<Tag>(other)
{
}
QVariant Tags::get(int index) const
{
return QVariant::fromValue(at(index));
}
void Tags::put(const QVariant &variant)
{
append(variant.value<Tag>());
}
}

View File

@ -24,19 +24,34 @@
#include "typeutils.h"
#include <QString>
#include <QVariant>
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<Tag>
{
Q_GADGET
Q_PROPERTY(int count READ count)
public:
Tags();
Tags(const QList<Tag> &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

View File

@ -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),

View File

@ -23,12 +23,20 @@
#include <QUuid>
#include <QDateTime>
#include <QMetaType>
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

View File

@ -271,7 +271,7 @@ void Device::setSettingValue(const ParamTypeId &paramTypeId, const QVariant &val
}
/*! Returns the states of this Device. It must match the \l{StateType} description in the associated \l{DeviceClass}. */
QList<State> Device::states() const
States Device::states() const
{
return m_states;
}
@ -283,7 +283,7 @@ bool Device::hasParam(const ParamTypeId &paramTypeId) const
}
/*! Set the \l{State}{States} of this \l{Device} to the given \a states.*/
void Device::setStates(const QList<State> &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<Device*>());
}

View File

@ -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 &paramTypeId) const;
void setSettingValue(const ParamTypeId &paramTypeId, const QVariant &value);
QList<State> states() const;
States states() const;
bool hasState(const StateTypeId &stateTypeId) const;
void setStates(const QList<State> &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<State> 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<Device*>
{
Q_GADGET
Q_PROPERTY(int count READ count)
public:
Devices() = default;
Devices(const QList<Device *> &other);
@ -154,6 +163,9 @@ public:
Devices filterByParam(const ParamTypeId &paramTypeId, 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)

View File

@ -143,3 +143,13 @@ void DeviceDescriptor::setParams(const ParamList &params)
{
m_params = params;
}
QVariant DeviceDescriptors::get(int index) const
{
return QVariant::fromValue(at(index));
}
void DeviceDescriptors::put(const QVariant &variant)
{
append(variant.value<DeviceDescriptor>());
}

View File

@ -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<DeviceDescriptor>
{
Q_GADGET
Q_PROPERTY(int count READ count)
public:
DeviceDescriptors() {}
inline DeviceDescriptors(std::initializer_list<DeviceDescriptor> args): QList(args) {}
DeviceDescriptors(const QList<DeviceDescriptor> &other): QList<DeviceDescriptor>(other) {}
Q_INVOKABLE QVariant get(int index) const;
Q_INVOKABLE void put(const QVariant &variant);
};
Q_DECLARE_METATYPE(DeviceDescriptor)

View File

@ -37,5 +37,8 @@
DeviceManager::DeviceManager(QObject *parent) : QObject(parent)
{
qRegisterMetaType<Param>();
qRegisterMetaType<ParamList>();
qRegisterMetaType<ParamType>();
qRegisterMetaType<ParamTypes>();
}

View File

@ -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 &paramType, 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);

View File

@ -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<DevicePlugin*>());
}

View File

@ -55,6 +55,7 @@
#include <QTranslator>
#include <QPair>
#include <QSettings>
#include <QMetaType>
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<DevicePlugin*>
{
Q_GADGET
Q_PROPERTY(int count READ count)
public:
DevicePlugins();
DevicePlugins(const QList<DevicePlugin*> &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

View File

@ -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<bool, ParamTypes> 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;

View File

@ -0,0 +1,54 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* 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 <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#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();
}

View File

@ -0,0 +1,56 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* 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 <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef EXPERIENCEPLUGIN_H
#define EXPERIENCEPLUGIN_H
#include <QObject>
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

View File

@ -0,0 +1,464 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* 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 <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "jsonhandler.h"
#include "loggingcategories.h"
#include <QDebug>
#include <QDateTime>
JsonHandler::JsonHandler(QObject *parent) : QObject(parent)
{
qRegisterMetaType<QVariant::Type>();
registerEnum<BasicType>();
}
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 &params, 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 &params, 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<JsonHandler*>(this), data);
}
JsonReply *JsonHandler::createAsyncReply(const QString &method) const
{
return JsonReply::createAsyncReply(const_cast<JsonHandler*>(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<void*>(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<BasicType>();
ret.insert(metaProperty.name(), metaEnum.key(variantTypeToBasicType(propertyValue.template value<QVariant::Type>())));
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<BasicType>... Only QVariantList is known to the meta system
if (propertyTypeName.startsWith("QList<")) {
QVariantList list;
if (propertyTypeName == "QList<int>") {
foreach (int entry, propertyValue.value<QList<int>>()) {
list << entry;
}
} else if (propertyTypeName == "QList<QUuid>") {
foreach (const QUuid &entry, propertyValue.value<QList<QUuid>>()) {
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<int>")) {
QList<int> intList;
foreach (const QVariant &val, variant.toList()) {
intList.append(val.toInt());
}
metaProperty.writeOnGadget(ptr, QVariant::fromValue(intList));
} else if (metaProperty.typeName() == QStringLiteral("QList<QUuid>")) {
QList<QUuid> 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();
}

View File

@ -0,0 +1,242 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* 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 <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef JSONHANDLER_H
#define JSONHANDLER_H
#include <QObject>
#include <QVariantMap>
#include <QMetaMethod>
#include <QDebug>
#include <QVariant>
#include <QDateTime>
#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<typename T> static QString enumRef();
template<typename T> static QString objectRef();
static QString objectRef(const QString &objectName);
template<typename T> static QString enumValueName(T value);
template<typename T> static T enumNameToValue(const QString &name);
static BasicType variantTypeToBasicType(QVariant::Type variantType);
static QVariant::Type basicTypeToVariantType(BasicType basicType);
template<typename T> QVariant pack(const T &value) const;
template<typename T> QVariant pack(T *value) const;
template <typename T> T unpack(const QVariant &value) const;
protected:
template <typename Enum> void registerEnum();
template <typename Enum, typename Flags> void registerEnum();
template <typename ObjectType> void registerObject();
template <typename ObjectType, typename ListType> void registerObject();
template <typename ObjectType> void registerUncreatableObject();
template <typename ObjectType, typename ListType> void registerUncreatableObject();
template<typename ListType, typename BasicTypeName> 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 &params, const QVariantMap &returns, const QString &deprecationInfo = QString());
void registerNotification(const QString &name, const QString &description, const QVariantMap &params, 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<QString, QMetaEnum> m_metaEnums;
QVariantMap m_flags;
QHash<QString, QMetaEnum> m_metaFlags;
QHash<QString, QString> m_flagsEnums;
QVariantMap m_objects;
QHash<QString, QMetaObject> m_metaObjects;
QHash<QString, QMetaObject> m_listMetaObjects;
QHash<QString, QString> m_listEntryTypes;
QVariantMap m_methods;
QVariantMap m_notifications;
};
Q_DECLARE_METATYPE(QVariant::Type)
template<typename T>
void JsonHandler::registerEnum()
{
QMetaEnum metaEnum = QMetaEnum::fromType<T>();
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<typename Enum, typename Flags>
void JsonHandler::registerEnum()
{
registerEnum<Enum>();
QMetaEnum metaEnum = QMetaEnum::fromType<Enum>();
QMetaEnum metaFlags = QMetaEnum::fromType<Flags>();
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<typename ObjectType>
void JsonHandler::registerObject()
{
qRegisterMetaType<ObjectType>();
QMetaObject metaObject = ObjectType::staticMetaObject;
registerObject(metaObject);
}
template<typename ObjectType, typename ListType>
void JsonHandler::registerObject()
{
qRegisterMetaType<ObjectType>();
qRegisterMetaType<ListType>();
QMetaObject metaObject = ObjectType::staticMetaObject;
QMetaObject listMetaObject = ListType::staticMetaObject;
registerObject(metaObject, listMetaObject);
}
template<typename ObjectType>
void JsonHandler::registerUncreatableObject()
{
QMetaObject metaObject = ObjectType::staticMetaObject;
registerObject(metaObject);
}
template<typename ObjectType, typename ListType >
void JsonHandler::registerUncreatableObject()
{
QMetaObject metaObject = ObjectType::staticMetaObject;
QMetaObject listMetaObject = ListType::staticMetaObject;
registerObject(metaObject, listMetaObject);
}
template<typename ListType, typename BasicTypeName>
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<typename T>
QString JsonHandler::enumRef()
{
QMetaEnum metaEnum = QMetaEnum::fromType<T>();
return QString("$ref:%1").arg(metaEnum.name());
}
template<typename T>
QString JsonHandler::objectRef()
{
QMetaObject metaObject = T::staticMetaObject;
return QString("$ref:%1").arg(QString(metaObject.className()).split("::").last());
}
template<typename T>
QString JsonHandler::enumValueName(T value)
{
QMetaEnum metaEnum = QMetaEnum::fromType<T>();
return metaEnum.valueToKey(value);
}
template<typename T>
T JsonHandler::enumNameToValue(const QString &name)
{
QMetaEnum metaEnum = QMetaEnum::fromType<T>();
return static_cast<T>(metaEnum.keyToValue(name.toUtf8()));
}
template<typename T>
QVariant JsonHandler::pack(const T &value) const
{
QMetaObject metaObject = T::staticMetaObject;
return pack(metaObject, static_cast<const void*>(&value));
}
template<typename T>
QVariant JsonHandler::pack(T *value) const
{
QMetaObject metaObject = T::staticMetaObject;
return pack(metaObject, static_cast<const void*>(value));
}
template<typename T>
T JsonHandler::unpack(const QVariant &value) const
{
QMetaObject metaObject = T::staticMetaObject;
QVariant ret = unpack(metaObject, value);
return ret.value<T>();
}
#endif // JSONHANDLER_H

View File

@ -0,0 +1,143 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* 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 <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#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;
}

View File

@ -1,7 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stürz <simon.stuerz@guh.io> *
* Copyright (C) 2014 Michael Zanetti <michael_zanetti@gmx.net> *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* 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 <QObject>
#include <QVariantMap>
#include <QMetaMethod>
#include <QUuid>
#include <QTimer>
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<bool, QString> validateParams(const QString &methodName, const QVariantMap &params);
QPair<bool, QString> validateReturns(const QString &methodName, const QVariantMap &returns);
signals:
void asyncReply(int id, const QVariantMap &params);
protected:
void setDescription(const QString &methodName, const QString &description);
void setParams(const QString &methodName, const QVariantMap &params);
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<QString, QString> m_descriptions;
QHash<QString, QVariantMap> m_params;
QHash<QString, QVariantMap> m_returns;
};
}
#endif // JSONHANDLER_H
#endif // JSONREPLY_H

View File

@ -0,0 +1,25 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* 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 <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "jsonrpcserver.h"
/*! \fn void JsonRPCServer::registerExperienceHandler(JsonHandler *handler, int majorVersion, int minorVersion)
Register an experience JSON RPC handler on the JSON RPC server.
*/

View File

@ -0,0 +1,36 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2019 Michael Zanetti <michael.zanetti@nymea.io> *
* *
* 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 <http://www.gnu.org/licenses/>. *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#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

View File

@ -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 += \

View File

@ -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")

View File

@ -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)

View File

@ -129,3 +129,23 @@ bool Package::operator!=(const Package &other) const
{
return !operator==(other);
}
Packages::Packages()
{
}
Packages::Packages(const QList<Package> &other): QList<Package>(other)
{
}
QVariant Packages::get(int index) const
{
return QVariant::fromValue(at(index));
}
void Packages::put(const QVariant &variant)
{
append(variant.value<Package>());
}

View File

@ -24,9 +24,23 @@
#define PACKAGE_H
#include <QString>
#include <QMetaObject>
#include <QList>
#include <QVariant>
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<Package>
{
Q_GADGET
Q_PROPERTY(int count READ count)
public:
Packages();
Packages(const QList<Package> &other);
Q_INVOKABLE QVariant get(int index) const;
Q_INVOKABLE void put(const QVariant &variant);
};
Q_DECLARE_METATYPE(Packages)
#endif // PACKAGE_H

View File

@ -54,3 +54,23 @@ void Repository::setEnabled(bool enabled)
{
m_enabled = enabled;
}
Repositories::Repositories()
{
}
Repositories::Repositories(const QList<Repository> &other): QList<Repository>(other)
{
}
QVariant Repositories::get(int index) const
{
return QVariant::fromValue(at(index));
}
void Repositories::put(const QVariant &variant)
{
append(variant.value<Repository>());
}

View File

@ -24,9 +24,14 @@
#define REPOSITORY_H
#include <QString>
#include <QVariant>
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<Repository>
{
Q_GADGET
Q_PROPERTY(int count READ count)
public:
Repositories();
Repositories(const QList<Repository> &other);
Q_INVOKABLE QVariant get(int index) const;
Q_INVOKABLE void put(const QVariant &variant);
};
#endif // REPOSITORY_H

View File

@ -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 <QDebug>
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<CalendarItem> &other): QList<CalendarItem>(other)
{
}
QVariant CalendarItems::get(int index) const
{
return QVariant::fromValue(at(index));
}
void CalendarItems::put(const QVariant &variant)
{
append(variant.value<CalendarItem>());
}

View File

@ -24,11 +24,15 @@
#include <QTime>
#include "repeatingoption.h"
namespace nymeaserver {
#include <QVariant>
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<CalendarItem>
{
Q_GADGET
Q_PROPERTY(int count READ count)
public:
CalendarItems();
CalendarItems(const QList<CalendarItem> &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

View File

@ -83,8 +83,6 @@
#include <QDateTime>
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<int> RepeatingOption::weekDays() const
{
return m_weekDays;
}
void RepeatingOption::setWeekDays(const QList<int> &weekDays)
{
m_weekDays = weekDays;
}
/*! Returns the list of month days on which this \l{RepeatingOption} should be valid. */
QList<int> RepeatingOption::monthDays() const
{
return m_monthDays;
}
void RepeatingOption::setMonthDays(const QList<int> &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;
}
}

View File

@ -23,15 +23,16 @@
#include <QList>
#include <QMetaType>
#include <QVariant>
class QDateTime;
namespace nymeaserver {
class RepeatingOption
{
Q_GADGET
Q_PROPERTY(RepeatingMode mode READ mode WRITE setMode)
Q_PROPERTY(QList<int> weekDays READ weekDays WRITE setWeekDays USER true)
Q_PROPERTY(QList<int> monthDays READ monthDays WRITE setMonthDays USER true)
public:
enum RepeatingMode {
RepeatingModeNone,
@ -47,9 +48,13 @@ public:
RepeatingOption(const RepeatingMode &mode, const QList<int> &weekDays = QList<int>(), const QList<int> &monthDays = QList<int>());
RepeatingMode mode() const;
void setMode(RepeatingMode mode);
QList<int> weekDays() const;
void setWeekDays(const QList<int> &weekDays);
QList<int> monthDays() const;
void setMonthDays(const QList<int> &monthDays);
bool isEmtpy() const;
bool isValid() const;
@ -66,6 +71,5 @@ private:
};
QDebug operator<<(QDebug dbg, const RepeatingOption &RepeatingOption);
}
#endif // REPEATINGOPTION_H

View File

@ -36,8 +36,6 @@
#include <QDebug>
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<TimeEventItem> 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<TimeEventItem> &timeEventItems)
void TimeDescriptor::setTimeEventItems(const TimeEventItems &timeEventItems)
{
m_timeEventItems = timeEventItems;
}
/*! Returns the list of \l{CalendarItem}{CalendarItems} of this \l{TimeDescriptor}.*/
QList<CalendarItem> 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<CalendarItem> &calendarItems)
void TimeDescriptor::setCalendarItems(const CalendarItems &calendarItems)
{
m_calendarItems = calendarItems;
}
@ -119,5 +117,3 @@ QDebug operator<<(QDebug dbg, const TimeDescriptor &timeDescriptor)
}
return dbg;
}
}

View File

@ -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<TimeEventItem> timeEventItems() const;
void setTimeEventItems(const QList<TimeEventItem> &timeEventItems);
TimeEventItems timeEventItems() const;
void setTimeEventItems(const TimeEventItems &timeEventItems);
QList<CalendarItem> calendarItems() const;
void setCalendarItems(const QList<CalendarItem> &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<TimeEventItem> m_timeEventItems;
QList<CalendarItem> m_calendarItems;
TimeEventItems m_timeEventItems;
CalendarItems m_calendarItems;
};
QDebug operator<<(QDebug dbg, const TimeDescriptor &timeDescriptor);
}
#endif // TIMEDESCRIPTOR_H

View File

@ -33,8 +33,6 @@
#include <QDebug>
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<TimeEventItem> &other): QList<TimeEventItem>(other)
{
}
QVariant TimeEventItems::get(int index) const
{
return QVariant::fromValue(at(index));
}
void TimeEventItems::put(const QVariant &variant)
{
append(variant.value<TimeEventItem>());
}

View File

@ -22,18 +22,21 @@
#define TIMEEVENTITEM_H
#include <QDateTime>
#include <QVariant>
#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<TimeEventItem>
{
Q_GADGET
Q_PROPERTY(int count READ count)
public:
TimeEventItems();
TimeEventItems(const QList<TimeEventItem> &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

View File

@ -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
{

View File

@ -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 &params);

View File

@ -123,6 +123,16 @@ ActionTypes::ActionTypes(const QList<ActionType> &other)
}
}
QVariant ActionTypes::get(int index) const
{
return QVariant::fromValue(at(index));
}
void ActionTypes::put(const QVariant &variant)
{
append(variant.value<ActionType>());
}
ActionType ActionTypes::findByName(const QString &name)
{
foreach (const ActionType &actionType, *this) {

View File

@ -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<ActionType>
{
Q_GADGET
Q_PROPERTY(int count READ count)
public:
ActionTypes() = default;
ActionTypes(const QList<ActionType> &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

View File

@ -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<ActionTypeId> actionTypeIds READ actionTypeIds)
public:
enum BrowserIcon {
BrowserIconNone,

View File

@ -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<DeviceClass>());
}

View File

@ -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<DeviceClass>
{
Q_GADGET
Q_PROPERTY(int count READ count)
public:
DeviceClasses();
DeviceClasses(const QList<DeviceClass> &other);
DeviceClass findById(const DeviceClassId &id) const;
Q_INVOKABLE QVariant get(int index) const;
Q_INVOKABLE void put(const QVariant &variant);
};
#endif

View File

@ -108,7 +108,7 @@ Param Event::param(const ParamTypeId &paramTypeId) const
return param;
}
}
return Param(QString());
return Param(paramTypeId);
}
/*! Returns true if this event is autogenerated by a state change. */

View File

@ -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 &params = ParamList(), bool isStateChangeEvent = false);

View File

@ -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<ParamDescriptor> EventDescriptor::paramDescriptors() const
{
@ -169,3 +189,23 @@ QDebug operator<<(QDebug dbg, const QList<EventDescriptor> &eventDescriptors)
return dbg;
}
EventDescriptors::EventDescriptors()
{
}
EventDescriptors::EventDescriptors(const QList<EventDescriptor> &other): QList<EventDescriptor>(other)
{
}
QVariant EventDescriptors::get(int index) const
{
return QVariant::fromValue(at(index));
}
void EventDescriptors::put(const QVariant &variant)
{
append(variant.value<EventDescriptor>());
}

Some files were not shown because too many files have changed in this diff Show More