diff --git a/libnymea-core/jsonrpc/configurationhandler.cpp b/libnymea-core/jsonrpc/configurationhandler.cpp index 1b5e48a3..2d8e077f 100644 --- a/libnymea-core/jsonrpc/configurationhandler.cpp +++ b/libnymea-core/jsonrpc/configurationhandler.cpp @@ -100,6 +100,8 @@ ConfigurationHandler::ConfigurationHandler(QObject *parent): QVariantList webSocketServerConfigurations; webSocketServerConfigurations.append(JsonTypes::serverConfigurationRef()); returns.insert("webSocketServerConfigurations", webSocketServerConfigurations); + QVariantList mqttServerConfigurations; + mqttServerConfigurations.append(JsonTypes::serverConfigurationRef()); QVariantMap cloudConfiguration; cloudConfiguration.insert("enabled", JsonTypes::basicTypeToString(JsonTypes::Bool)); returns.insert("cloud", cloudConfiguration); @@ -182,53 +184,129 @@ ConfigurationHandler::ConfigurationHandler(QObject *parent): returns.insert("configurationError", JsonTypes::configurationErrorRef()); setReturns("SetCloudEnabled", 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); + + 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); + + 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); + + params.clear(); returns.clear(); + setDescription("GetMqttPolicies", "Get all MQTT broker policies."); + setParams("GetMqttPolicies", params); + returns.insert("mqttPolicies", QVariantList() << JsonTypes::mqttPolicyRef()); + setReturns("GetMqttPolicies", 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); + + 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); + // Notifications params.clear(); returns.clear(); setDescription("BasicConfigurationChanged", "Emitted whenever the basic configuration of this server changes."); - params.insert("serverName", JsonTypes::basicTypeToString(JsonTypes::String)); - params.insert("serverUuid", JsonTypes::basicTypeToString(JsonTypes::Uuid)); - params.insert("serverTime", JsonTypes::basicTypeToString(JsonTypes::Uint)); - params.insert("timeZone", JsonTypes::basicTypeToString(JsonTypes::String)); - params.insert("debugServerEnabled", JsonTypes::basicTypeToString(JsonTypes::Bool)); + params.insert("basicConfiguration", basicConfiguration); setParams("BasicConfigurationChanged", params); - params.clear(); returns.clear(); - setDescription("TcpServerConfigurationChanged", "Emitted whenever the TCP server configuration changes."); - params.insert("host", JsonTypes::basicTypeToString(JsonTypes::String)); - params.insert("port", JsonTypes::basicTypeToString(JsonTypes::Uint)); - setParams("TcpServerConfigurationChanged", params); - - params.clear(); returns.clear(); - setDescription("WebServerConfigurationChanged", "Emitted whenever the web server configuration changes."); - params.insert("host", JsonTypes::basicTypeToString(JsonTypes::String)); - params.insert("port", JsonTypes::basicTypeToString(JsonTypes::Uint)); - setParams("WebServerConfigurationChanged", params); - - params.clear(); returns.clear(); - setDescription("WebSocketServerConfigurationChanged", "Emitted whenever the web socket server configuration changes."); - params.insert("host", JsonTypes::basicTypeToString(JsonTypes::String)); - params.insert("port", JsonTypes::basicTypeToString(JsonTypes::Uint)); - setParams("WebSocketServerConfigurationChanged", 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); + params.clear(); returns.clear(); + setDescription("TcpServerConfigurationChanged", "Emitted whenever the TCP server configuration changes."); + params.insert("tcpServerConfiguration", JsonTypes::serverConfigurationRef()); + setParams("TcpServerConfigurationChanged", 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); + + params.clear(); returns.clear(); + setDescription("WebSocketServerConfigurationChanged", "Emitted whenever the web socket server configuration changes."); + params.insert("webSocketServerConfiguration", JsonTypes::serverConfigurationRef()); + setParams("WebSocketServerConfigurationChanged", 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); + + params.clear(); returns.clear(); + setDescription("MqttServerConfigurationChanged", "Emitted whenever the MQTT broker configuration is changed."); + params.insert("mqttServerConfiguration", JsonTypes::serverConfigurationRef()); + setParams("MqttServerConfigurationChanged", 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); + + params.clear(); returns.clear(); + setDescription("WebServerConfigurationChanged", "Emitted whenever the web server configuration changes."); + params.insert("webServerConfiguration", JsonTypes::webServerConfigurationRef()); + setParams("WebServerConfigurationChanged", 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); + params.clear(); returns.clear(); setDescription("CloudConfigurationChanged", "Emitted whenever the cloud configuration is changed."); - params.insert("enabled", JsonTypes::basicTypeToString(JsonTypes::Bool)); + params.insert("cloudConfiguration", cloudConfiguration); setParams("CloudConfigurationChanged", params); + params.clear(); returns.clear(); + setDescription("MqttPolicyChanged", "Emitted whenever a MQTT broker policy is changed."); + params.insert("policy", JsonTypes::mqttPolicyRef()); + setParams("MqttPolicyChanged", 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); + connect(NymeaCore::instance()->configuration(), &NymeaConfiguration::serverNameChanged, this, &ConfigurationHandler::onBasicConfigurationChanged); connect(NymeaCore::instance()->configuration(), &NymeaConfiguration::timeZoneChanged, this, &ConfigurationHandler::onBasicConfigurationChanged); connect(NymeaCore::instance()->configuration(), &NymeaConfiguration::localeChanged, this, &ConfigurationHandler::onBasicConfigurationChanged); connect(NymeaCore::instance()->configuration(), &NymeaConfiguration::debugServerEnabledChanged, this, &ConfigurationHandler::onBasicConfigurationChanged); - connect(NymeaCore::instance()->configuration(), &NymeaConfiguration::tcpServerConfigurationChanged, this, &ConfigurationHandler::onTcpServerConfigurationChanged); - connect(NymeaCore::instance()->configuration(), &NymeaConfiguration::webServerConfigurationChanged, this, &ConfigurationHandler::onWebServerConfigurationChanged); - connect(NymeaCore::instance()->configuration(), &NymeaConfiguration::webSocketServerConfigurationChanged, this, &ConfigurationHandler::onWebSocketServerConfigurationChanged); - connect(NymeaCore::instance()->configuration(), &NymeaConfiguration::cloudEnabledChanged, this, &ConfigurationHandler::onCloudConfigurationChanged); connect(NymeaCore::instance()->deviceManager(), &DeviceManager::languageUpdated, this, &ConfigurationHandler::onLanguageChanged); + connect(NymeaCore::instance()->configuration(), &NymeaConfiguration::tcpServerConfigurationChanged, this, &ConfigurationHandler::onTcpServerConfigurationChanged); + connect(NymeaCore::instance()->configuration(), &NymeaConfiguration::tcpServerConfigurationRemoved, this, &ConfigurationHandler::onTcpServerConfigurationRemoved); + connect(NymeaCore::instance()->configuration(), &NymeaConfiguration::webServerConfigurationChanged, this, &ConfigurationHandler::onWebServerConfigurationChanged); + connect(NymeaCore::instance()->configuration(), &NymeaConfiguration::webServerConfigurationRemoved, this, &ConfigurationHandler::onWebServerConfigurationRemoved); + connect(NymeaCore::instance()->configuration(), &NymeaConfiguration::webSocketServerConfigurationChanged, this, &ConfigurationHandler::onWebSocketServerConfigurationChanged); + connect(NymeaCore::instance()->configuration(), &NymeaConfiguration::webSocketServerConfigurationRemoved, this, &ConfigurationHandler::onWebSocketServerConfigurationRemoved); + connect(NymeaCore::instance()->configuration(), &NymeaConfiguration::mqttServerConfigurationChanged, this, &ConfigurationHandler::onMqttServerConfigurationChanged); + connect(NymeaCore::instance()->configuration(), &NymeaConfiguration::mqttServerConfigurationRemoved, this, &ConfigurationHandler::onMqttServerConfigurationRemoved); + connect(NymeaCore::instance()->configuration(), &NymeaConfiguration::mqttPolicyChanged, this, &ConfigurationHandler::onMqttPolicyChanged); + connect(NymeaCore::instance()->configuration(), &NymeaConfiguration::mqttPolicyRemoved, this, &ConfigurationHandler::onMqttPolicyRemoved); + connect(NymeaCore::instance()->configuration(), &NymeaConfiguration::cloudEnabledChanged, this, &ConfigurationHandler::onCloudConfigurationChanged); } /*! Returns the name of the \l{ConfigurationHandler}. In this case \b Configuration.*/ @@ -397,7 +475,7 @@ JsonReply *ConfigurationHandler::SetWebSocketServerConfiguration(const QVariantM return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidPort)); } - qCDebug(dcJsonRpc()) << QString("Configure web socket server %1:%2").arg(config.address.toString()).arg(config.port); + qCDebug(dcJsonRpc()) << QString("Configuring web socket server %1:%2").arg(config.address.toString()).arg(config.port); NymeaCore::instance()->configuration()->setWebSocketServerConfiguration(config); @@ -414,6 +492,75 @@ JsonReply *ConfigurationHandler::DeleteWebSocketServerConfiguration(const QVaria return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorNoError)); } +JsonReply *ConfigurationHandler::GetMqttServerConfigurations(const QVariantMap ¶ms) const +{ + Q_UNUSED(params) + QVariantMap ret; + QVariantList mqttServerConfigs; + foreach (const ServerConfiguration &config, NymeaCore::instance()->configuration()->mqttServerConfigurations()) { + mqttServerConfigs << JsonTypes::packServerConfiguration(config); + } + ret.insert("mqttServerConfigurations", mqttServerConfigs); + return createReply(ret); +} + +JsonReply *ConfigurationHandler::SetMqttServerConfiguration(const QVariantMap ¶ms) const +{ + ServerConfiguration config = JsonTypes::unpackServerConfiguration(params.value("configuration").toMap()); + if (config.id.isEmpty()) { + return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidId)); + } + if (config.address.isNull()) + return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidHostAddress)); + + if (config.port <= 0 || config.port > 65535) { + qCWarning(dcJsonRpc()) << "Port out of range"; + return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidPort)); + } + + qCDebug(dcJsonRpc()) << QString("Configure MQTT server %1:%2").arg(config.address.toString()).arg(config.port); + + NymeaCore::instance()->configuration()->setMqttServerConfiguration(config); + + return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorNoError)); +} + +JsonReply *ConfigurationHandler::DeleteMqttServerConfiguration(const QVariantMap ¶ms) const +{ + QString id = params.value("id").toString(); + if (id.isEmpty() || !NymeaCore::instance()->configuration()->mqttServerConfigurations().contains(id)) { + return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorInvalidId)); + } + NymeaCore::instance()->configuration()->removeMqttServerConfiguration(id); + return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorNoError)); +} + +JsonReply *ConfigurationHandler::GetMqttPolicies(const QVariantMap ¶ms) const +{ + Q_UNUSED(params) + QVariantList mqttPolicies; + foreach (const MqttPolicy &policy, NymeaCore::instance()->configuration()->mqttPolicies()) { + mqttPolicies << JsonTypes::packMqttPolicy(policy); + } + QVariantMap ret; + ret.insert("mqttPolicies", mqttPolicies); + return createReply(ret); +} + +JsonReply *ConfigurationHandler::SetMqttPolicy(const QVariantMap ¶ms) const +{ + MqttPolicy policy = JsonTypes::unpackMqttPolicy(params.value("policy").toMap()); + NymeaCore::instance()->configuration()->updateMqttPolicy(policy); + return createReply(statusToReply(NymeaConfiguration::ConfigurationErrorNoError)); +} + +JsonReply *ConfigurationHandler::DeleteMqttPolicy(const QVariantMap ¶ms) const +{ + QString clientId = params.value("clientId").toString(); + bool success = NymeaCore::instance()->configuration()->removeMqttPolicy(clientId); + return createReply(statusToReply(success ? NymeaConfiguration::ConfigurationErrorNoError : NymeaConfiguration::ConfigurationErrorInvalidId)); +} + JsonReply *ConfigurationHandler::SetCloudEnabled(const QVariantMap ¶ms) const { bool enabled = params.value("enabled").toBool(); @@ -430,40 +577,96 @@ JsonReply *ConfigurationHandler::SetDebugServerEnabled(const QVariantMap ¶ms void ConfigurationHandler::onBasicConfigurationChanged() { - QVariantMap params; qCDebug(dcJsonRpc()) << "Notification: Basic configuration changed"; + QVariantMap params; params.insert("basicConfiguration", JsonTypes::packBasicConfiguration()); emit BasicConfigurationChanged(params); } void ConfigurationHandler::onTcpServerConfigurationChanged(const QString &id) { - QVariantMap params; qCDebug(dcJsonRpc()) << "Notification: TCP server configuration changed"; + QVariantMap params; params.insert("tcpServerConfiguration", JsonTypes::packServerConfiguration(NymeaCore::instance()->configuration()->tcpServerConfigurations().value(id))); emit TcpServerConfigurationChanged(params); } +void ConfigurationHandler::onTcpServerConfigurationRemoved(const QString &id) +{ + qCDebug(dcJsonRpc) << "Notification: TCP server configuration removed"; + QVariantMap params; + params.insert("id", id); + emit TcpServerConfigurationRemoved(params); +} + void ConfigurationHandler::onWebServerConfigurationChanged(const QString &id) { - QVariantMap params; qCDebug(dcJsonRpc()) << "Notification: web server configuration changed"; + QVariantMap params; params.insert("webServerConfiguration", JsonTypes::packWebServerConfiguration(NymeaCore::instance()->configuration()->webServerConfigurations().value(id))); emit WebServerConfigurationChanged(params); } +void ConfigurationHandler::onWebServerConfigurationRemoved(const QString &id) +{ + qCDebug(dcJsonRpc()) << "Notification: Web server configuration removed"; + QVariantMap params; + params.insert("id", id); + emit WebServerConfigurationChanged(params); +} + void ConfigurationHandler::onWebSocketServerConfigurationChanged(const QString &id) { - QVariantMap params; qCDebug(dcJsonRpc()) << "Notification: web socket server configuration changed"; + QVariantMap params; params.insert("webSocketServerConfiguration", JsonTypes::packServerConfiguration(NymeaCore::instance()->configuration()->webSocketServerConfigurations().value(id))); emit WebSocketServerConfigurationChanged(params); } +void ConfigurationHandler::onWebSocketServerConfigurationRemoved(const QString &id) +{ + qCDebug(dcJsonRpc()) << "Notification: WebSocket server configuration removed"; + QVariantMap params; + params.insert("id", id); + emit WebSocketServerConfigurationRemoved(params); +} + +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))); + emit MqttServerConfigurationChanged(params); +} + +void ConfigurationHandler::onMqttServerConfigurationRemoved(const QString &id) +{ + qCDebug(dcJsonRpc()) << "Notification: MQTT server configuration removed"; + QVariantMap params; + params.insert("id", id); + emit MqttServerConfigurationRemoved(params); +} + +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))); + emit MqttPolicyChanged(params); +} + +void ConfigurationHandler::onMqttPolicyRemoved(const QString &clientId) +{ + qCDebug(dcJsonRpc()) << "Notification: MQTT policy removed"; + QVariantMap params; + params.insert("clientId", clientId); + emit MqttPolicyRemoved(params); +} + void ConfigurationHandler::onCloudConfigurationChanged(bool enabled) { + qCDebug(dcJsonRpc()) << "Notification: cloud configuration changed"; QVariantMap params; - qCDebug(dcJanus()) << "Notification: cloud configuration changed"; QVariantMap cloudConfiguration; cloudConfiguration.insert("enabled", enabled); params.insert("cloudConfiguration", cloudConfiguration); @@ -472,8 +675,8 @@ void ConfigurationHandler::onCloudConfigurationChanged(bool enabled) void ConfigurationHandler::onLanguageChanged() { - QVariantMap params; qCDebug(dcJsonRpc()) << "Notification: language configuration changed"; + QVariantMap params; params.insert("language", NymeaCore::instance()->configuration()->locale().name()); emit LanguageChanged(params); } diff --git a/libnymea-core/jsonrpc/configurationhandler.h b/libnymea-core/jsonrpc/configurationhandler.h index 78cf53d8..e5ef0e07 100644 --- a/libnymea-core/jsonrpc/configurationhandler.h +++ b/libnymea-core/jsonrpc/configurationhandler.h @@ -32,7 +32,7 @@ class ConfigurationHandler : public JsonHandler Q_OBJECT public: - ConfigurationHandler(QObject *parent = 0); + ConfigurationHandler(QObject *parent = nullptr); QString name() const; Q_INVOKABLE JsonReply *GetConfigurations(const QVariantMap ¶ms) const; @@ -41,31 +41,53 @@ public: Q_INVOKABLE JsonReply *SetServerName(const QVariantMap ¶ms) const; Q_INVOKABLE JsonReply *SetTimeZone(const QVariantMap ¶ms) const; Q_INVOKABLE JsonReply *SetLanguage(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *SetDebugServerEnabled(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *SetCloudEnabled(const QVariantMap ¶ms) const; Q_INVOKABLE JsonReply *SetTcpServerConfiguration(const QVariantMap ¶ms) const; Q_INVOKABLE JsonReply *DeleteTcpServerConfiguration(const QVariantMap ¶ms) const; Q_INVOKABLE JsonReply *SetWebServerConfiguration(const QVariantMap ¶ms) const; Q_INVOKABLE JsonReply *DeleteWebServerConfiguration(const QVariantMap ¶ms) const; Q_INVOKABLE JsonReply *SetWebSocketServerConfiguration(const QVariantMap ¶ms) const; Q_INVOKABLE JsonReply *DeleteWebSocketServerConfiguration(const QVariantMap ¶ms) const; - Q_INVOKABLE JsonReply *SetCloudEnabled(const QVariantMap ¶ms) const; - Q_INVOKABLE JsonReply *SetDebugServerEnabled(const QVariantMap ¶ms) const; + + Q_INVOKABLE JsonReply *GetMqttServerConfigurations(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *SetMqttServerConfiguration(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *DeleteMqttServerConfiguration(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *GetMqttPolicies(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *SetMqttPolicy(const QVariantMap ¶ms) const; + Q_INVOKABLE JsonReply *DeleteMqttPolicy(const QVariantMap ¶ms) const; signals: void BasicConfigurationChanged(const QVariantMap ¶ms); - void TcpServerConfigurationChanged(const QVariantMap ¶ms); - void WebServerConfigurationChanged(const QVariantMap ¶ms); - void WebSocketServerConfigurationChanged(const QVariantMap ¶ms); - void CloudConfigurationChanged(const QVariantMap ¶ms); + // TODO: remove, should be part of BasicConfigurationChanged void LanguageChanged(const QVariantMap ¶ms); + void CloudConfigurationChanged(const QVariantMap ¶ms); + void TcpServerConfigurationChanged(const QVariantMap ¶ms); + void TcpServerConfigurationRemoved(const QVariantMap ¶ms); + void WebServerConfigurationChanged(const QVariantMap ¶ms); + void WebServerConfigurationRemoved(const QVariantMap ¶ms); + void WebSocketServerConfigurationChanged(const QVariantMap ¶ms); + void WebSocketServerConfigurationRemoved(const QVariantMap ¶ms); + + void MqttServerConfigurationChanged(const QVariantMap ¶ms); + void MqttServerConfigurationRemoved(const QVariantMap ¶ms); + void MqttPolicyChanged(const QVariantMap ¶ms); + void MqttPolicyRemoved(const QVariantMap ¶ms); private slots: void onBasicConfigurationChanged(); - void onTcpServerConfigurationChanged(const QString &id); - void onWebServerConfigurationChanged(const QString &id); - void onWebSocketServerConfigurationChanged(const QString &id); - void onCloudConfigurationChanged(bool enabled); void onLanguageChanged(); - + void onCloudConfigurationChanged(bool enabled); + void onTcpServerConfigurationChanged(const QString &id); + void onTcpServerConfigurationRemoved(const QString &id); + void onWebServerConfigurationChanged(const QString &id); + void onWebServerConfigurationRemoved(const QString &id); + void onWebSocketServerConfigurationChanged(const QString &id); + void onWebSocketServerConfigurationRemoved(const QString &id); + void onMqttServerConfigurationChanged(const QString &id); + void onMqttServerConfigurationRemoved(const QString &id); + void onMqttPolicyChanged(const QString &clientId); + void onMqttPolicyRemoved(const QString &clientId); }; } diff --git a/libnymea-core/jsonrpc/jsonhandler.h b/libnymea-core/jsonrpc/jsonhandler.h index fdb6c9bb..1111e452 100644 --- a/libnymea-core/jsonrpc/jsonhandler.h +++ b/libnymea-core/jsonrpc/jsonhandler.h @@ -88,7 +88,7 @@ class JsonHandler : public QObject { Q_OBJECT public: - explicit JsonHandler(QObject *parent = 0); + explicit JsonHandler(QObject *parent = nullptr); virtual QString name() const = 0; diff --git a/libnymea-core/jsonrpc/jsonrpcserver.cpp b/libnymea-core/jsonrpc/jsonrpcserver.cpp index 8422c3c2..76451abc 100644 --- a/libnymea-core/jsonrpc/jsonrpcserver.cpp +++ b/libnymea-core/jsonrpc/jsonrpcserver.cpp @@ -203,6 +203,7 @@ JsonRPCServer::JsonRPCServer(const QSslConfiguration &sslConfiguration, QObject 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); params.clear(); @@ -607,15 +608,15 @@ void JsonRPCServer::processJsonPacket(TransportInterface *interface, const QUuid reply->startWait(); } else { Q_ASSERT_X((targetNamespace == "JSONRPC" && method == "Introspect") || handler->validateReturns(method, reply->data()).first - ,"validating return value", formatAssertion(targetNamespace, method, handler, reply->data()).toLatin1().data()); + ,"validating return value", formatAssertion(targetNamespace, method, QMetaMethod::Method, handler, reply->data()).toLatin1().data()); sendResponse(interface, clientId, commandId, reply->data()); reply->deleteLater(); } } -QString JsonRPCServer::formatAssertion(const QString &targetNamespace, const QString &method, JsonHandler *handler, const QVariantMap &data) const +QString JsonRPCServer::formatAssertion(const QString &targetNamespace, const QString &method, QMetaMethod::MethodType methodType, JsonHandler *handler, const QVariantMap &data) const { - QJsonDocument doc = QJsonDocument::fromVariant(handler->introspect(QMetaMethod::Method).value(targetNamespace + "." + method)); + 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) @@ -633,6 +634,7 @@ void JsonRPCServer::sendNotification(const QVariantMap ¶ms) 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()); QByteArray data = QJsonDocument::fromVariant(notification).toJson(QJsonDocument::Compact); qCDebug(dcJsonRpcTraffic()) << "Sending notification:" << data; @@ -652,7 +654,7 @@ void JsonRPCServer::asyncReplyFinished() } if (!reply->timedOut()) { Q_ASSERT_X(reply->handler()->validateReturns(reply->method(), reply->data()).first - ,"validating return value", formatAssertion(reply->handler()->name(), reply->method(), reply->handler(), reply->data()).toLatin1().data()); + ,"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()); } else { sendErrorResponse(interface, reply->clientId(), reply->commandId(), "Command timed out"); diff --git a/libnymea-core/jsonrpc/jsonrpcserver.h b/libnymea-core/jsonrpc/jsonrpcserver.h index 3bdfbcf2..984712e4 100644 --- a/libnymea-core/jsonrpc/jsonrpcserver.h +++ b/libnymea-core/jsonrpc/jsonrpcserver.h @@ -112,7 +112,7 @@ private: int m_notificationId; void registerHandler(JsonHandler *handler); - QString formatAssertion(const QString &targetNamespace, const QString &method, JsonHandler *handler, const QVariantMap &data) const; + QString formatAssertion(const QString &targetNamespace, const QString &method, QMetaMethod::MethodType methodType, JsonHandler *handler, const QVariantMap &data) const; }; } diff --git a/libnymea-core/jsonrpc/jsontypes.cpp b/libnymea-core/jsonrpc/jsontypes.cpp index c8895873..eb287714 100644 --- a/libnymea-core/jsonrpc/jsontypes.cpp +++ b/libnymea-core/jsonrpc/jsontypes.cpp @@ -125,6 +125,7 @@ QVariantMap JsonTypes::s_tokenInfo; QVariantMap JsonTypes::s_serverConfiguration; QVariantMap JsonTypes::s_webServerConfiguration; QVariantMap JsonTypes::s_tag; +QVariantMap JsonTypes::s_mqttPolicy; void JsonTypes::init() { @@ -392,6 +393,13 @@ void JsonTypes::init() s_webServerConfiguration = s_serverConfiguration; s_webServerConfiguration.insert("publicFolder", basicTypeToString(QVariant::String)); + // MQTT + s_mqttPolicy.insert("clientId", basicTypeToString(QVariant::String)); + s_mqttPolicy.insert("username", basicTypeToString(QVariant::String)); + s_mqttPolicy.insert("password", basicTypeToString(QVariant::String)); + s_mqttPolicy.insert("allowedPublishTopicFilters", basicTypeToString(QVariant::StringList)); + s_mqttPolicy.insert("allowedSubscribeTopicFilters", basicTypeToString(QVariant::StringList)); + // Tag s_tag.insert("o:deviceId", basicTypeToString(QVariant::Uuid)); s_tag.insert("o:ruleId", basicTypeToString(QVariant::Uuid)); @@ -1197,6 +1205,16 @@ QVariantMap JsonTypes::packWebServerConfiguration(const WebServerConfiguration & return webServerConfiguration; } +QVariantMap JsonTypes::packMqttPolicy(const MqttPolicy &policy) +{ + QVariantMap policyMap; + policyMap.insert("clientId", policy.clientId); + policyMap.insert("username", policy.username); + policyMap.insert("password", policy.password); + policyMap.insert("allowedPublishTopicFilters", policy.allowedPublishTopicFilters); + policyMap.insert("allowedSubscribeTopicFilters", policy.allowedSubscribeTopicFilters); + return policyMap; +} /*! Returns a variant list containing all rule descriptions. */ QVariantList JsonTypes::packRuleDescriptions() @@ -1277,6 +1295,8 @@ QString JsonTypes::basicTypeToString(const QVariant::Type &type) return "Uuid"; case QVariant::String: return "String"; + case QVariant::StringList: + return "StringList"; case QVariant::Int: return "Int"; case QVariant::UInt: @@ -1674,6 +1694,17 @@ WebServerConfiguration JsonTypes::unpackWebServerConfiguration(const QVariantMap return webServerConfiguration; } +MqttPolicy JsonTypes::unpackMqttPolicy(const QVariantMap &mqttPolicyMap) +{ + MqttPolicy policy; + policy.clientId = mqttPolicyMap.value("clientId").toString(); + policy.username = mqttPolicyMap.value("username").toString(); + policy.password = mqttPolicyMap.value("password").toString(); + policy.allowedPublishTopicFilters = mqttPolicyMap.value("allowedPublishTopicFilters").toStringList(); + policy.allowedSubscribeTopicFilters = mqttPolicyMap.value("allowedSubscribeTopicFilters").toStringList(); + return policy; +} + /*! Compairs the given \a map with the given \a templateMap. Returns the error string and false if the params are not valid. */ QPair JsonTypes::validateMap(const QVariantMap &templateMap, const QVariantMap &map) @@ -1733,6 +1764,10 @@ QPair JsonTypes::validateProperty(const QVariant &templateValue, QString errorString = QString("Param %1 is not a string.").arg(value.toString()); return report(value.canConvert(QVariant::String), errorString); } + if (strippedTemplateValue == JsonTypes::basicTypeToString(QVariant::StringList)) { + QString errorString = QString("Param %1 is not a string list.").arg(value.toString()); + return report(value.canConvert(QVariant::StringList), errorString); + } if (strippedTemplateValue == JsonTypes::basicTypeToString(QVariant::Bool)) { QString errorString = QString("Param %1 is not a bool.").arg(value.toString()); return report(value.canConvert(QVariant::Bool), errorString); @@ -1980,6 +2015,12 @@ QPair JsonTypes::validateVariant(const QVariant &templateVariant, qCWarning(dcJsonRpc) << "WebServerConfiguration not matching"; return result; } + } else if (refName == mqttPolicyRef()) { + QPair result = validateMap(s_mqttPolicy, variant.toMap()); + if (!result.first) { + qCWarning(dcJsonRpc) << "MqttPolicy not matching"; + return result; + } } else if (refName == tagRef()) { QPair result = validateMap(tagDescription(), variant.toMap()); if (!result.first) { diff --git a/libnymea-core/jsonrpc/jsontypes.h b/libnymea-core/jsonrpc/jsontypes.h index b9896306..7cfa785a 100644 --- a/libnymea-core/jsonrpc/jsontypes.h +++ b/libnymea-core/jsonrpc/jsontypes.h @@ -106,6 +106,7 @@ public: enum BasicType { Uuid, String, + StringList, Int, Uint, Double, @@ -176,6 +177,7 @@ public: DECLARE_OBJECT(serverConfiguration, "ServerConfiguration") DECLARE_OBJECT(webServerConfiguration, "WebServerConfiguration") DECLARE_OBJECT(tag, "Tag") + DECLARE_OBJECT(mqttPolicy, "MqttPolicy") // pack types static QVariantMap packEventType(const EventType &eventType); @@ -220,6 +222,7 @@ public: static QVariantMap packBasicConfiguration(); static QVariantMap packServerConfiguration(const ServerConfiguration &config); static QVariantMap packWebServerConfiguration(const WebServerConfiguration &config); + static QVariantMap packMqttPolicy(const MqttPolicy &policy); static QVariantList packRuleDescriptions(); static QVariantList packRuleDescriptions(const QList &rules); @@ -254,6 +257,7 @@ public: static ServerConfiguration unpackServerConfiguration(const QVariantMap &serverConfigurationMap); static WebServerConfiguration unpackWebServerConfiguration(const QVariantMap &webServerConfigurationMap); + static MqttPolicy unpackMqttPolicy(const QVariantMap &mqttPolicyMap); // validate static QPair validateMap(const QVariantMap &templateMap, const QVariantMap &map); diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index 6a78c2b0..48f41859 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -5,7 +5,7 @@ include(../nymea.pri) QT += sql qmqtt INCLUDEPATH += $$top_srcdir/libnymea -LIBS += -L$$top_builddir/libnymea/ -lnymea -lssl -lcrypto -lavahi-common -lavahi-client +LIBS += -L$$top_builddir/libnymea/ -lnymea -lssl -lcrypto -lavahi-common -lavahi-client -lnymea-mqtt target.path = /usr/lib/$$system('dpkg-architecture -q DEB_HOST_MULTIARCH') INSTALLS += target @@ -37,6 +37,7 @@ HEADERS += nymeacore.h \ servers/rest/pluginsresource.h \ servers/rest/rulesresource.h \ servers/websocketserver.h \ + servers/mqttbroker.h \ jsonrpc/jsonrpcserver.h \ jsonrpc/jsonhandler.h \ jsonrpc/devicehandler.h \ @@ -121,6 +122,7 @@ SOURCES += nymeacore.cpp \ servers/rest/logsresource.cpp \ servers/rest/pluginsresource.cpp \ servers/rest/rulesresource.cpp \ + servers/mqttbroker.cpp \ jsonrpc/jsonrpcserver.cpp \ jsonrpc/jsonhandler.cpp \ jsonrpc/devicehandler.cpp \ diff --git a/libnymea-core/nymeaconfiguration.cpp b/libnymea-core/nymeaconfiguration.cpp index 4d17f04a..799baa31 100644 --- a/libnymea-core/nymeaconfiguration.cpp +++ b/libnymea-core/nymeaconfiguration.cpp @@ -66,7 +66,7 @@ NymeaConfiguration::NymeaConfiguration(QObject *parent) : if (settings.childGroups().contains("TcpServer")) { settings.beginGroup("TcpServer"); if (settings.value("disabled").toBool()) { - qCDebug(dcApplication) << "TCP Server disabled by configuration"; + qCDebug(dcApplication) << "TCP server disabled by configuration"; } else if (!settings.childGroups().isEmpty()) { foreach (const QString &key, settings.childGroups()) { ServerConfiguration config = readServerConfig("TcpServer", key); @@ -78,7 +78,7 @@ NymeaConfiguration::NymeaConfiguration(QObject *parent) : settings.endGroup(); } if (createDefaults) { - qCWarning(dcApplication) << "No TCP Server configuration found. Generating default of 0.0.0.0:2222"; + qCWarning(dcApplication) << "No TCP server configuration found. Generating default of 0.0.0.0:2222"; ServerConfiguration config; config.id = "default"; config.address = QHostAddress("0.0.0.0"); @@ -95,7 +95,7 @@ NymeaConfiguration::NymeaConfiguration(QObject *parent) : if (settings.childGroups().contains("WebServer")) { settings.beginGroup("WebServer"); if (settings.value("disabled").toBool()) { - qCDebug(dcApplication) << "WebServer disabled by configuration"; + qCDebug(dcApplication) << "Web server disabled by configuration"; } else if (!settings.childGroups().isEmpty()) { foreach (const QString &key, settings.childGroups()) { WebServerConfiguration config = readWebServerConfig(key); @@ -107,7 +107,7 @@ NymeaConfiguration::NymeaConfiguration(QObject *parent) : settings.endGroup(); } if (createDefaults) { - qCWarning(dcApplication) << "No WebServer configuration found. Generating default of 0.0.0.0:3333"; + qCWarning(dcApplication) << "No Web server configuration found. Generating default of 0.0.0.0:3333"; WebServerConfiguration insecureConfig; insecureConfig.id = "insecure"; insecureConfig.address = QHostAddress("0.0.0.0"); @@ -136,7 +136,7 @@ NymeaConfiguration::NymeaConfiguration(QObject *parent) : if (settings.childGroups().contains("WebSocketServer")) { settings.beginGroup("WebSocketServer"); if (settings.value("disabled").toBool()) { - qCDebug(dcApplication) << "WebSocket Server disabled by configuration."; + qCDebug(dcApplication) << "WebSocket server disabled by configuration."; } else if (!settings.childGroups().isEmpty()) { foreach (const QString &key, settings.childGroups()) { ServerConfiguration config = readServerConfig("WebSocketServer", key); @@ -148,7 +148,7 @@ NymeaConfiguration::NymeaConfiguration(QObject *parent) : settings.endGroup(); } if (createDefaults) { - qCWarning(dcApplication) << "No WebSocketServer configuration found. Generating default of 0.0.0.0:4444"; + qCWarning(dcApplication) << "No WebSocket server configuration found. Generating default of 0.0.0.0:4444"; ServerConfiguration config; config.id = "default"; config.address = QHostAddress("0.0.0.0"); @@ -160,6 +160,34 @@ NymeaConfiguration::NymeaConfiguration(QObject *parent) : storeServerConfig("WebSocketServer", config); } + // MQTT Server + createDefaults = !settings.childGroups().contains("MqttServer"); + if (settings.childGroups().contains("MqttServer")) { + settings.beginGroup("MqttServer"); + if (settings.value("disabled").toBool()) { + qCDebug(dcApplication) << "MQTT server disabled by configuration."; + } else if (!settings.childGroups().isEmpty()) { + foreach (const QString &key, settings.childGroups()) { + ServerConfiguration config = readServerConfig("MqttServer", key); + m_mqttServerConfigs[config.id] = config; + } + } else { + createDefaults = true; + } + settings.endGroup(); + } + if (createDefaults) { + qCWarning(dcApplication) << "No MQTT server configuration found. Generating default of 0.0.0.0:1883"; + ServerConfiguration config; + config.id = "default"; + config.address = QHostAddress("0.0.0.0"); + config.port = 1883; + config.sslEnabled = false; + config.authenticationEnabled = true; + m_mqttServerConfigs[config.id] = config; + storeServerConfig("MqttServer", config); + } + // Write defaults for log settings settings.beginGroup("Logs"); settings.setValue("logDBDriver", logDBDriver()); @@ -315,6 +343,48 @@ void NymeaConfiguration::removeWebSocketServerConfiguration(const QString &id) emit webSocketServerConfigurationRemoved(id); } +QHash NymeaConfiguration::mqttServerConfigurations() const +{ + return m_mqttServerConfigs; +} + +void NymeaConfiguration::setMqttServerConfiguration(const ServerConfiguration &config) +{ + m_mqttServerConfigs[config.id] = config; + storeServerConfig("MqttServer", config); + emit mqttServerConfigurationChanged(config.id); +} + +void NymeaConfiguration::removeMqttServerConfiguration(const QString &id) +{ + m_mqttServerConfigs.take(id); + deleteServerConfig("MqttServer", id); + emit mqttServerConfigurationRemoved(id); +} + +QHash NymeaConfiguration::mqttPolicies() const +{ + return m_mqttPolicies; +} + +void NymeaConfiguration::updateMqttPolicy(const MqttPolicy &policy) +{ + m_mqttPolicies[policy.clientId] = policy; + storeMqttPolicy(policy); + emit mqttPolicyChanged(policy.clientId); +} + +bool NymeaConfiguration::removeMqttPolicy(const QString &clientId) +{ + if (!m_mqttPolicies.contains(clientId)) { + return false; + } + m_mqttPolicies.take(clientId); + deleteMqttPolicy(clientId); + emit mqttPolicyRemoved(clientId); + return true; +} + bool NymeaConfiguration::bluetoothServerEnabled() const { NymeaSettings settings(NymeaSettings::SettingsRoleGlobal); @@ -322,7 +392,7 @@ bool NymeaConfiguration::bluetoothServerEnabled() const return settings.value("enabled", false).toBool(); } -void NymeaConfiguration::setBluetoothServerEnabled(const bool &enabled) +void NymeaConfiguration::setBluetoothServerEnabled(bool enabled) { qCDebug(dcApplication()) << "Configuration: Bluetooth server" << (enabled ? "enabled" : "disabled"); @@ -330,7 +400,7 @@ void NymeaConfiguration::setBluetoothServerEnabled(const bool &enabled) settings.beginGroup("BluetoothServer"); settings.setValue("enabled", enabled); settings.endGroup(); - emit bluetoothServerEnabled(); + emit bluetoothServerEnabledChanged(); } bool NymeaConfiguration::cloudEnabled() const @@ -599,6 +669,23 @@ WebServerConfiguration NymeaConfiguration::readWebServerConfig(const QString &id return config; } +void NymeaConfiguration::storeMqttPolicy(const MqttPolicy &policy) +{ + NymeaSettings settings(NymeaSettings::SettingsRoleMqttPolicies); + settings.beginGroup(policy.clientId); + settings.setValue("username", policy.username); + settings.setValue("password", policy.password); + settings.setValue("allowedPublishTopicFilters", policy.allowedPublishTopicFilters); + settings.setValue("allowedSubscribeTopicFilters", policy.allowedSubscribeTopicFilters); + settings.endGroup(); +} + +void NymeaConfiguration::deleteMqttPolicy(const QString &clientId) +{ + NymeaSettings settings(NymeaSettings::SettingsRoleMqttPolicies); + settings.remove(clientId); +} + QDebug operator <<(QDebug debug, const ServerConfiguration &configuration) { debug.nospace() << "ServerConfiguration(" << configuration.address; diff --git a/libnymea-core/nymeaconfiguration.h b/libnymea-core/nymeaconfiguration.h index 1fc44322..37e7195f 100644 --- a/libnymea-core/nymeaconfiguration.h +++ b/libnymea-core/nymeaconfiguration.h @@ -37,7 +37,7 @@ public: bool sslEnabled = true; bool authenticationEnabled = true; - bool operator==(const ServerConfiguration &other) { + bool operator==(const ServerConfiguration &other) const { return id == other.id && address == other.address && port == other.port @@ -48,7 +48,6 @@ public: QDebug operator <<(QDebug debug, const ServerConfiguration &configuration); - class WebServerConfiguration: public ServerConfiguration { public: @@ -56,6 +55,17 @@ public: bool restServerEnabled = false; }; +class MqttPolicy +{ +public: + QString clientId; + QString username; + QString password; + QStringList allowedSubscribeTopicFilters; + QStringList allowedPublishTopicFilters; +}; +typedef QList MqttPolicies; + class NymeaConfiguration : public QObject { Q_OBJECT @@ -73,7 +83,7 @@ public: ConfigurationErrorInvalidCertificate }; - explicit NymeaConfiguration(QObject *parent = 0); + explicit NymeaConfiguration(QObject *parent = nullptr); // Global settings QUuid serverUuid() const; @@ -110,9 +120,18 @@ public: void setWebSocketServerConfiguration(const ServerConfiguration &config); void removeWebSocketServerConfiguration(const QString &id); + // MQTT + QHash mqttServerConfigurations() const; + void setMqttServerConfiguration(const ServerConfiguration &config); + void removeMqttServerConfiguration(const QString &id); + + QHash mqttPolicies() const; + void updateMqttPolicy(const MqttPolicy &policy); + bool removeMqttPolicy(const QString &clientId); + // Bluetooth bool bluetoothServerEnabled() const; - void setBluetoothServerEnabled(const bool &enabled); + void setBluetoothServerEnabled(bool enabled); // Cloud bool cloudEnabled() const; @@ -139,6 +158,8 @@ private: QHash m_tcpServerConfigs; QHash m_webServerConfigs; QHash m_webSocketServerConfigs; + QHash m_mqttServerConfigs; + QHash m_mqttPolicies; void setServerUuid(const QUuid &uuid); void setWebServerPublicFolder(const QString & path); @@ -151,6 +172,10 @@ private: void storeWebServerConfig(const WebServerConfiguration &config); WebServerConfiguration readWebServerConfig(const QString &id); + void storeMqttPolicy(const MqttPolicy &policy); + MqttPolicy readMqttPolicy(const QString &clientId); + void deleteMqttPolicy(const QString &clientId); + signals: void serverNameChanged(const QString &serverName); void timeZoneChanged(); @@ -162,12 +187,21 @@ signals: void webServerConfigurationRemoved(const QString &configId); void webSocketServerConfigurationChanged(const QString &configId); void webSocketServerConfigurationRemoved(const QString &configId); + void mqttServerConfigurationChanged(const QString &configId); + void mqttServerConfigurationRemoved(const QString &configId); + + void mqttPolicyChanged(const QString &clientId); + void mqttPolicyRemoved(const QString &clientId); void bluetoothServerEnabledChanged(); + void mqttBrokerEnabledChanged(); + void mqttPortChanged(); void cloudEnabledChanged(bool enabled); void debugServerEnabledChanged(bool enabled); }; } +Q_DECLARE_METATYPE(nymeaserver::ServerConfiguration) +Q_DECLARE_METATYPE(nymeaserver::MqttPolicy) #endif // NYMEACONFIGURATION_H diff --git a/libnymea-core/servermanager.cpp b/libnymea-core/servermanager.cpp index 56a8712a..e12c8546 100644 --- a/libnymea-core/servermanager.cpp +++ b/libnymea-core/servermanager.cpp @@ -37,7 +37,6 @@ #include "nymeacore.h" #include "certificategenerator.h" #include "nymeasettings.h" -#include "nymeaconfiguration.h" #include "jsonrpc/jsonrpcserver.h" #include "servers/mocktcpserver.h" @@ -46,6 +45,7 @@ #include "servers/websocketserver.h" #include "servers/webserver.h" #include "servers/bluetoothserver.h" +#include "servers/mqttbroker.h" #include #include @@ -130,7 +130,10 @@ ServerManager::ServerManager(NymeaConfiguration *configuration, QObject *parent) m_webServers.insert(config.id, webServer); } - + m_mqttBroker = new MqttBroker(this); + foreach (const ServerConfiguration &config, configuration->mqttServerConfigurations()) { + m_mqttBroker->startServer(config); + } connect(configuration, &NymeaConfiguration::tcpServerConfigurationChanged, this, &ServerManager::tcpServerConfigurationChanged); connect(configuration, &NymeaConfiguration::tcpServerConfigurationRemoved, this, &ServerManager::tcpServerConfigurationRemoved); @@ -138,6 +141,10 @@ ServerManager::ServerManager(NymeaConfiguration *configuration, QObject *parent) connect(configuration, &NymeaConfiguration::webSocketServerConfigurationRemoved, this, &ServerManager::webSocketServerConfigurationRemoved); connect(configuration, &NymeaConfiguration::webServerConfigurationChanged, this, &ServerManager::webServerConfigurationChanged); connect(configuration, &NymeaConfiguration::webServerConfigurationRemoved, this, &ServerManager::webServerConfigurationRemoved); + connect(configuration, &NymeaConfiguration::mqttServerConfigurationChanged, this, &ServerManager::mqttServerConfigurationChanged); + connect(configuration, &NymeaConfiguration::mqttServerConfigurationRemoved, this, &ServerManager::mqttServerConfigurationRemoved); + connect(configuration, &NymeaConfiguration::mqttPolicyChanged, this, &ServerManager::mqttPolicyChanged); + connect(configuration, &NymeaConfiguration::mqttPolicyRemoved, this, &ServerManager::mqttPolicyRemoved); } /*! Returns the pointer to the created \l{JsonRPCServer} in this \l{ServerManager}. */ @@ -164,6 +171,11 @@ MockTcpServer *ServerManager::mockTcpServer() const return m_mockTcpServer; } +MqttBroker *ServerManager::mqttBroker() const +{ + return m_mqttBroker; +} + void ServerManager::tcpServerConfigurationChanged(const QString &id) { ServerConfiguration config = NymeaCore::instance()->configuration()->tcpServerConfigurations().value(id); @@ -249,6 +261,30 @@ void ServerManager::webServerConfigurationRemoved(const QString &id) server->deleteLater(); } +void ServerManager::mqttServerConfigurationChanged(const QString &id) +{ + ServerConfiguration config = NymeaCore::instance()->configuration()->mqttServerConfigurations().value(id); + if (m_mqttBroker->isRunning(id)) { + m_mqttBroker->stopServer(id); + } + m_mqttBroker->startServer(config, m_sslConfiguration); +} + +void ServerManager::mqttServerConfigurationRemoved(const QString &id) +{ + m_mqttBroker->stopServer(id); +} + +void ServerManager::mqttPolicyChanged(const QString &clientId) +{ + m_mqttBroker->updatePolicy(NymeaCore::instance()->configuration()->mqttPolicies().value(clientId)); +} + +void ServerManager::mqttPolicyRemoved(const QString &clientId) +{ + m_mqttBroker->removePolicy(clientId); +} + bool ServerManager::loadCertificate(const QString &certificateKeyFileName, const QString &certificateFileName) { QFile certificateKeyFile(certificateKeyFileName); diff --git a/libnymea-core/servermanager.h b/libnymea-core/servermanager.h index 085cb2ad..10f3df35 100644 --- a/libnymea-core/servermanager.h +++ b/libnymea-core/servermanager.h @@ -24,6 +24,7 @@ #include #include "loggingcategories.h" +#include "nymeaconfiguration.h" #include #include @@ -55,6 +56,8 @@ public: MockTcpServer *mockTcpServer() const; + MqttBroker *mqttBroker() const; + private slots: void tcpServerConfigurationChanged(const QString &id); void tcpServerConfigurationRemoved(const QString &id); @@ -62,6 +65,10 @@ private slots: void webSocketServerConfigurationRemoved(const QString &id); void webServerConfigurationChanged(const QString &id); void webServerConfigurationRemoved(const QString &id); + void mqttServerConfigurationChanged(const QString &id); + void mqttServerConfigurationRemoved(const QString &id); + void mqttPolicyChanged(const QString &clientId); + void mqttPolicyRemoved(const QString &clientId); private: // Interfaces @@ -74,6 +81,8 @@ private: QHash m_webServers; MockTcpServer *m_mockTcpServer; + MqttBroker *m_mqttBroker; + // Encrytption and stuff QSslConfiguration m_sslConfiguration; QSslKey m_certificateKey; diff --git a/libnymea/loggingcategories.cpp b/libnymea/loggingcategories.cpp index 2afac8ef..562aff45 100644 --- a/libnymea/loggingcategories.cpp +++ b/libnymea/loggingcategories.cpp @@ -53,3 +53,4 @@ Q_LOGGING_CATEGORY(dcJanus, "Janus") Q_LOGGING_CATEGORY(dcJanusTraffic, "JanusTraffic") Q_LOGGING_CATEGORY(dcBluetoothServer, "BluetoothServer") Q_LOGGING_CATEGORY(dcBluetoothServerTraffic, "BluetoothServerTraffic") +Q_LOGGING_CATEGORY(dcMqtt, "Mqtt") diff --git a/libnymea/loggingcategories.h b/libnymea/loggingcategories.h index c39ead63..72bb9bd1 100644 --- a/libnymea/loggingcategories.h +++ b/libnymea/loggingcategories.h @@ -61,5 +61,6 @@ Q_DECLARE_LOGGING_CATEGORY(dcJanus) Q_DECLARE_LOGGING_CATEGORY(dcJanusTraffic) Q_DECLARE_LOGGING_CATEGORY(dcBluetoothServer) Q_DECLARE_LOGGING_CATEGORY(dcBluetoothServerTraffic) +Q_DECLARE_LOGGING_CATEGORY(dcMqtt) #endif // LOGGINGCATEGORYS_H diff --git a/libnymea/nymeasettings.cpp b/libnymea/nymeasettings.cpp index 3d3fd1fe..7c2532fb 100644 --- a/libnymea/nymeasettings.cpp +++ b/libnymea/nymeasettings.cpp @@ -104,6 +104,9 @@ NymeaSettings::NymeaSettings(const SettingsRole &role, QObject *parent): case SettingsRoleTags: fileName = "tags.conf"; break; + case SettingsRoleMqttPolicies: + fileName = "mqttpolicies.conf"; + break; } m_settings = new QSettings(basePath + settingsPrefix + fileName, QSettings::IniFormat, this); } diff --git a/libnymea/nymeasettings.h b/libnymea/nymeasettings.h index 9faaf83e..86210d81 100644 --- a/libnymea/nymeasettings.h +++ b/libnymea/nymeasettings.h @@ -41,7 +41,8 @@ public: SettingsRolePlugins, SettingsRoleGlobal, SettingsRoleDeviceStates, - SettingsRoleTags + SettingsRoleTags, + SettingsRoleMqttPolicies, }; explicit NymeaSettings(const SettingsRole &role = SettingsRoleNone, QObject *parent = nullptr); diff --git a/nymea.pri b/nymea.pri index 88ee6ced..25c3cfd1 100644 --- a/nymea.pri +++ b/nymea.pri @@ -6,7 +6,7 @@ NYMEA_PLUGINS_PATH=/usr/lib/$$system('dpkg-architecture -q DEB_HOST_MULTIARCH')/ # define protocol versions JSON_PROTOCOL_VERSION_MAJOR=1 -JSON_PROTOCOL_VERSION_MINOR=10 +JSON_PROTOCOL_VERSION_MINOR=11 REST_API_VERSION=1 DEFINES += NYMEA_VERSION_STRING=\\\"$${NYMEA_VERSION_STRING}\\\" \ diff --git a/server/main.cpp b/server/main.cpp index 9655a7d9..4e52fe10 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -131,7 +131,8 @@ int main(int argc, char *argv[]) "Janus", "JanusTraffic", "BluetoothServer", - "BluetoothServerTraffic" + "BluetoothServerTraffic", + "Mqtt" }; QStringList loggingFiltersPlugins; diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index 12d8f36b..e4bd38e8 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -23,4 +23,5 @@ SUBDIRS = versioning \ timemanager \ userloading \ usermanager \ + mqttbroker \ tags \ diff --git a/tests/auto/nymeatestbase.cpp b/tests/auto/nymeatestbase.cpp index 5d63051a..d91e01dd 100644 --- a/tests/auto/nymeatestbase.cpp +++ b/tests/auto/nymeatestbase.cpp @@ -230,7 +230,7 @@ QVariant NymeaTestBase::checkNotification(const QSignalSpy &spy, const QString & QVariantList NymeaTestBase::checkNotifications(const QSignalSpy &spy, const QString ¬ification) { - //qDebug() << "Got" << spy.count() << "notifications while waiting for" << notification; +// qWarning() << "Got" << spy.count() << "notifications while waiting for" << notification; QVariantList notificationList; for (int i = 0; i < spy.count(); i++) { // Make sure the response it a valid JSON string