diff --git a/libguh-core/awsconnector.cpp b/libguh-core/awsconnector.cpp index 998bae1e..8546aafe 100644 --- a/libguh-core/awsconnector.cpp +++ b/libguh-core/awsconnector.cpp @@ -159,6 +159,7 @@ void AWSConnector::setupSubscriptions() subscriptions.append(QString("%1/device/name/response").arg(m_clientId)); subscriptions.append(QString("%1/device/users/response").arg(m_clientId)); subscriptions.append(QString("%1/pair/response").arg(m_clientId)); + subscriptions.append(QString("%1/notify/response").arg(m_clientId)); subscribe(subscriptions); // fetch previous pairings @@ -174,17 +175,36 @@ void AWSConnector::fetchPairings() publish(QString("%1/device/users").arg(m_clientId), params); } -void AWSConnector::onPairingsRetrieved(const QVariantList &pairings) +void AWSConnector::onPairingsRetrieved(const QVariantMap &pairings) { - qCDebug(dcAWS) << pairings.count() << "devices paired in cloud."; - if (pairings.count() > 0) { + qCDebug(dcAWS) << pairings.value("users").toList().count() << "devices paired in cloud."; + if (pairings.value("users").toList().count() > 0) { QStringList topics; - foreach (const QVariant &pairing, pairings) { + foreach (const QVariant &pairing, pairings.value("users").toList()) { topics << QString("%1/%2/#").arg(m_clientId).arg(pairing.toString()); } subscribe(topics); } + qCDebug(dcAWS) << pairings.value("pushNotificationsEndpoints").toList().count() << "push notification enabled users paired in cloud."; + QList pushNotificationEndpoints; + if (pairings.value("pushNotificationsEndpoints").toList().count() > 0) { + foreach (const QVariant &pairing, pairings.value("pushNotificationsEndpoints").toList()) { + foreach (const QString &cognitoUserId, pairing.toMap().keys()) { + qCDebug(dcAWS()) << "User:" << cognitoUserId << "has" << pairing.toMap().value(cognitoUserId).toList().count() << "push notifications enabled devices."; + foreach (const QVariant &endpoint, pairing.toMap().value(cognitoUserId).toList()) { + PushNotificationsEndpoint ep; + ep.userId = cognitoUserId; + ep.endpointId = endpoint.toMap().value("endpointId").toString(); + ep.displayName = endpoint.toMap().value("displayName").toString(); + pushNotificationEndpoints.append(ep); + qCDebug(dcAWS) << "Device:" << ep.displayName << "endpoint:" << ep.endpointId << "user:" << ep.userId; + } + } + } + } + emit pushNotificationEndpointsUpdated(pushNotificationEndpoints); + if (readSyncedNameCache() != m_clientName) { setName(); } @@ -237,6 +257,18 @@ void AWSConnector::sendWebRtcHandshakeMessage(const QString &sessionId, const QV publish(sessionId + "/reply", map); } +int AWSConnector::sendPushNotification(const QString &userId, const QString &endpointId, const QString &title, const QString &text) +{ + QVariantMap params; + params.insert("id", ++m_transactionId); + params.insert("command", "sendPushNotification"); + params.insert("title", title); + params.insert("body", text); + params.insert("timestamp", QDateTime::currentMSecsSinceEpoch()); + publish(QString("%1/notify/user/%2/%3").arg(m_clientId, userId, endpointId), params); + return m_transactionId; +} + quint16 AWSConnector::publish(const QString &topic, const QVariantMap &message) { if (!m_setupInProgress && !isConnected()) { @@ -418,7 +450,7 @@ ResponseCode AWSConnector::onSubscriptionReceivedCallback(util::String topic_nam qCWarning(dcAWS()) << "Received a pairing response for a transaction we didn't start"; } } else if (topic == QString("%1/device/users/response").arg(connector->m_clientId)) { - connector->staticMetaObject.invokeMethod(connector, "onPairingsRetrieved", Qt::QueuedConnection, Q_ARG(QVariantList, jsonDoc.toVariant().toMap().value("users").toList())); + connector->staticMetaObject.invokeMethod(connector, "onPairingsRetrieved", Qt::QueuedConnection, Q_ARG(QVariantMap, jsonDoc.toVariant().toMap())); } else if (topic == QString("%1/device/name/response").arg(connector->m_clientId)) { qCDebug(dcAWS) << "Set device name in cloud with status:" << jsonDoc.toVariant().toMap().value("status").toInt(); if (jsonDoc.toVariant().toMap().value("status").toInt() == 200) { @@ -438,6 +470,11 @@ ResponseCode AWSConnector::onSubscriptionReceivedCallback(util::String topic_nam connector->webRtcHandshakeMessageReceived(topic, jsonDoc.toVariant().toMap()); } else if (topic.startsWith(QString("%1/eu-west-1:").arg(connector->m_clientId)) && topic.contains("reply")) { // silently drop our own things (should not be subscribed to that in the first place) + } else if (topic == QString("%1/notify/response").arg(connector->m_clientId)) { + int transactionId = jsonDoc.toVariant().toMap().value("id").toInt(); + int status = jsonDoc.toVariant().toMap().value("status").toInt(); + qCDebug(dcAWS()) << "Push notification reply for transaction" << transactionId << " Status:" << status << jsonDoc.toVariant().toMap().value("message").toString(); + emit connector->pushNotificationSent(transactionId, status); } else { qCWarning(dcAWS) << "Unhandled subscription received!" << topic << QString::fromStdString(payload); } diff --git a/libguh-core/awsconnector.h b/libguh-core/awsconnector.h index ac5dd31f..810868ae 100644 --- a/libguh-core/awsconnector.h +++ b/libguh-core/awsconnector.h @@ -39,6 +39,13 @@ public: explicit AWSConnector(QObject *parent = 0); ~AWSConnector(); + class PushNotificationsEndpoint { + public: + QString userId; + QString endpointId; + QString displayName; + }; + void connect2AWS(const QString &endpoint, const QString &clientId, const QString &clientName, const QString &caFile, const QString &clientCertFile, const QString &clientPrivKeyFile); void disconnectAWS(); bool isConnected() const; @@ -48,11 +55,16 @@ public: void sendWebRtcHandshakeMessage(const QString &sessionId, const QVariantMap &map); +public slots: + int sendPushNotification(const QString &userId, const QString &endpointId, const QString &title, const QString &text); + signals: void connected(); void disconnected(); void devicePaired(const QString &cognritoUserId, int errorCode, const QString &message); void webRtcHandshakeMessageReceived(const QString &transactionId, const QVariantMap &data); + void pushNotificationEndpointsUpdated(const QList pushNotificationEndpoints); + void pushNotificationSent(int id, int status); private slots: void doConnect(); @@ -61,7 +73,7 @@ private slots: void onDeviceRegistered(bool needsReconnect); void setupSubscriptions(); void fetchPairings(); - void onPairingsRetrieved(const QVariantList &pairings); + void onPairingsRetrieved(const QVariantMap &pairings); void setName(); void onDisconnected(); diff --git a/libguh-core/cloudmanager.cpp b/libguh-core/cloudmanager.cpp index 28bcc3fe..32b7a82e 100644 --- a/libguh-core/cloudmanager.cpp +++ b/libguh-core/cloudmanager.cpp @@ -22,6 +22,8 @@ #include "awsconnector.h" #include "janusconnector.h" #include "loggingcategories.h" +#include "cloudnotifications.h" + CloudManager::CloudManager(NetworkManager *networkManager, QObject *parent) : QObject(parent), m_networkManager(networkManager) @@ -130,6 +132,12 @@ bool CloudManager::keepAlive(const QString &sessionId) return m_janusConnector->sendKeepAliveMessage(sessionId); } +CloudNotifications *CloudManager::createNotificationsPlugin() const +{ + CloudNotifications* notifications = new CloudNotifications(m_awsConnector); + return notifications; +} + void CloudManager::connect2aws() { m_awsConnector->connect2AWS(m_serverUrl, diff --git a/libguh-core/cloudmanager.h b/libguh-core/cloudmanager.h index 04d64484..3a0f384c 100644 --- a/libguh-core/cloudmanager.h +++ b/libguh-core/cloudmanager.h @@ -30,6 +30,7 @@ class JanusConnector; class AWSConnector; +class CloudNotifications; class CloudManager : public QObject { @@ -51,6 +52,8 @@ public: bool keepAlive(const QString &sessionId); + CloudNotifications* createNotificationsPlugin() const; + signals: void connectedChanged(bool connected); @@ -80,6 +83,8 @@ private: QString m_caCertificate; QString m_clientCertificate; QString m_clientCertificateKey; + + CloudNotifications *m_notifications; }; #endif // CLOUDMANAGER_H diff --git a/libguh-core/cloudnotifications.cpp b/libguh-core/cloudnotifications.cpp new file mode 100644 index 00000000..69025177 --- /dev/null +++ b/libguh-core/cloudnotifications.cpp @@ -0,0 +1,209 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2017 Michael Zanetti * + * * + * This file is part of guh. * + * * + * Guh is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * Guh is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with guh. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "cloudnotifications.h" +#include "loggingcategories.h" + +#include + +DeviceClassId cloudNotificationsDeviceClassId = DeviceClassId("81c1bbcc-543a-48fd-bd18-ab6a76f9c38d"); +ParamTypeId cloudNotificationsDeviceClassUserParamId = ParamTypeId("5bdeaf08-91a9-42bc-a9f9-ef6b02ecaa3c"); +ParamTypeId cloudNotificationsDeviceClassEndpointParamId = ParamTypeId("e7c41785-dd3b-4f46-b5b4-1f8a7d060ddd"); + +ActionTypeId notifyActionTypeId = ActionTypeId("211d1f25-28e7-4eba-8938-b29de0e41571"); +ParamTypeId notifyActionParamTitleId = ParamTypeId("096503fc-b343-4d7f-8387-96162faf0f8e"); +ParamTypeId notifyActionParamBodyId = ParamTypeId("4bd0fa87-c663-4621-8040-99b6d535387c"); + +StateTypeId connectedStateTypeId = StateTypeId("518e27b6-c3bf-49d7-be24-05ae978c00f7"); + +CloudNotifications::CloudNotifications(AWSConnector* awsConnector, QObject *parent): + DevicePlugin(parent), + m_awsConnector(awsConnector) +{ + connect(m_awsConnector, &AWSConnector::pushNotificationEndpointsUpdated, this, &CloudNotifications::pushNotificationEndpointsUpdated); + connect(m_awsConnector, &AWSConnector::pushNotificationSent, this, &CloudNotifications::pushNotificationSent); +} + +QJsonObject CloudNotifications::metaData() const +{ + QVariantMap pluginMetaData; + pluginMetaData.insert("id", "ccc6dbc8-e352-48a1-8e87-3c89a4669fc2"); + pluginMetaData.insert("name", "cloudNotifications"); + pluginMetaData.insert("displayName", "Cloud Notifications"); + + QVariantList interfaces; + interfaces.append("notifications"); + interfaces.append("connectable"); + + QVariantList createMethods; + createMethods.append("auto"); + + QVariantMap userIdParam; + userIdParam.insert("id", cloudNotificationsDeviceClassUserParamId); + userIdParam.insert("name", "userId"); + userIdParam.insert("displayName", "User ID"); + userIdParam.insert("type", "QString"); + + QVariantMap endpointIdParam; + endpointIdParam.insert("id", cloudNotificationsDeviceClassEndpointParamId); + endpointIdParam.insert("name", "endpoint"); + endpointIdParam.insert("displayName", "Device"); + endpointIdParam.insert("type", "QString"); + + QVariantList cloudNotificationDeviceClassParamTypes; + cloudNotificationDeviceClassParamTypes.append(userIdParam); + cloudNotificationDeviceClassParamTypes.append(endpointIdParam); + + QVariantMap notifyActionParamTitle; + notifyActionParamTitle.insert("id", notifyActionParamTitleId); + notifyActionParamTitle.insert("name", "title"); + notifyActionParamTitle.insert("displayName", "Title"); + notifyActionParamTitle.insert("type", "QString"); + + QVariantMap notifyActionParamBody; + notifyActionParamBody.insert("id", notifyActionParamBodyId); + notifyActionParamBody.insert("name", "body"); + notifyActionParamBody.insert("displayName", "Message text"); + notifyActionParamBody.insert("type", "QString"); + + QVariantList notifyActionParamTypes; + notifyActionParamTypes.append(notifyActionParamTitle); + notifyActionParamTypes.append(notifyActionParamBody); + + QVariantMap notifyAction; + notifyAction.insert("id", notifyActionTypeId); + notifyAction.insert("name", "notify"); + notifyAction.insert("displayName", "Send notification"); + notifyAction.insert("paramTypes", notifyActionParamTypes); + + QVariantList actionTypes; + actionTypes.append(notifyAction); + + QVariantMap connectedState; + connectedState.insert("id", connectedStateTypeId); + connectedState.insert("name", "connected"); + connectedState.insert("displayName", "connected"); + connectedState.insert("type", "bool"); + connectedState.insert("displayNameEvent", "Connected changed"); + connectedState.insert("defaultValue", false); + + QVariantList stateTypes; + stateTypes.append(connectedState); + + + QVariantMap cloudNotificationsDeviceClass; + cloudNotificationsDeviceClass.insert("id", cloudNotificationsDeviceClassId); + cloudNotificationsDeviceClass.insert("name", "cloudNotifications"); + cloudNotificationsDeviceClass.insert("displayName", "Cloud Notifications"); + cloudNotificationsDeviceClass.insert("createMethods", createMethods); + cloudNotificationsDeviceClass.insert("paramTypes", cloudNotificationDeviceClassParamTypes); + cloudNotificationsDeviceClass.insert("interfaces", interfaces); + cloudNotificationsDeviceClass.insert("actionTypes", actionTypes); + cloudNotificationsDeviceClass.insert("stateTypes", stateTypes); + + QVariantList deviceClasses; + deviceClasses.append(cloudNotificationsDeviceClass); + + QVariantMap guhVendor; + guhVendor.insert("id", "2062d64d-3232-433c-88bc-0d33c0ba2ba6"); // guh's id + guhVendor.insert("name", "guh"); + guhVendor.insert("displayName", "guh"); + guhVendor.insert("deviceClasses", deviceClasses); + + QVariantList vendors; + vendors.append(guhVendor); + pluginMetaData.insert("vendors", vendors); + return QJsonObject::fromVariantMap(pluginMetaData); +} + +DeviceManager::DeviceSetupStatus CloudNotifications::setupDevice(Device *device) +{ + qWarning() << "--------------------------------------------------------------------- setupDevice" << device->id() << device->name(); + Q_UNUSED(device) + return DeviceManager::DeviceSetupStatusSuccess; +} + +void CloudNotifications::startMonitoringAutoDevices() +{ +} + +DeviceManager::DeviceError CloudNotifications::executeAction(Device *device, const Action &action) +{ + qCDebug(dcCloud()) << "executeAction" << device << action.id() << action.params(); + QString userId = device->paramValue(cloudNotificationsDeviceClassUserParamId).toString(); + QString endpointId = device->paramValue(cloudNotificationsDeviceClassEndpointParamId).toString(); + int id = m_awsConnector->sendPushNotification(userId, endpointId, action.param(notifyActionParamTitleId).value().toString(), action.param(notifyActionParamBodyId).value().toString()); + m_pendingPushNotifications.insert(id, action.id()); + return DeviceManager::DeviceErrorAsync; +} + +void CloudNotifications::pushNotificationEndpointsUpdated(const QList &endpoints) +{ + qCDebug(dcCloud()) << "Push Notification endpoint update"; + QList devicesToRemove; + foreach (Device *configuredDevice, myDevices()) { + bool found = false; + foreach (const AWSConnector::PushNotificationsEndpoint &ep, endpoints) { + if (configuredDevice->paramValue(cloudNotificationsDeviceClassUserParamId).toString() == ep.userId + && configuredDevice->paramValue(cloudNotificationsDeviceClassEndpointParamId).toString() == ep.endpointId) { + found = true; + break; + } + } + if (!found) { + devicesToRemove.append(configuredDevice); + } + } + foreach (Device *d, devicesToRemove) { + emit autoDeviceDisappeared(d->id()); + } + + QList devicesToAdd; + foreach (const AWSConnector::PushNotificationsEndpoint &ep, endpoints) { + bool found = false; + foreach (Device *d, myDevices()) { + if (d->paramValue(cloudNotificationsDeviceClassUserParamId).toString() == ep.userId + && d->paramValue(cloudNotificationsDeviceClassEndpointParamId).toString() == ep.endpointId) { + found = true; + break; + } + } + if (!found) { + qCDebug(dcCloud) << "Adding new notification device" << ep.displayName; + DeviceDescriptor descriptor(cloudNotificationsDeviceClassId, ep.displayName, QString("Send notifications to %1").arg(ep.displayName)); + ParamList params; + Param userIdParam(cloudNotificationsDeviceClassUserParamId, ep.userId); + params.append(userIdParam); + Param endpointIdParam(cloudNotificationsDeviceClassEndpointParamId, ep.endpointId); + params.append(endpointIdParam); + descriptor.setParams(params); + devicesToAdd.append(descriptor); + } + } + emit autoDevicesAppeared(cloudNotificationsDeviceClassId, devicesToAdd); + +} + +void CloudNotifications::pushNotificationSent(int id, int status) +{ + qCDebug(dcCloud()) << "Push notification sent" << id << status; + ActionId actionId = m_pendingPushNotifications.value(id); + emit actionExecutionFinished(actionId, status == 200 ? DeviceManager::DeviceErrorNoError : DeviceManager::DeviceErrorHardwareNotAvailable); +} diff --git a/libguh-core/cloudnotifications.h b/libguh-core/cloudnotifications.h new file mode 100644 index 00000000..f21855cb --- /dev/null +++ b/libguh-core/cloudnotifications.h @@ -0,0 +1,52 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2017 Michael Zanetti * + * * + * This file is part of guh. * + * * + * Guh is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * Guh is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with guh. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef CLOUDNOTIFICATIONS_H +#define CLOUDNOTIFICATIONS_H + +#include "plugin/deviceplugin.h" +#include "awsconnector.h" + +class CloudNotifications : public DevicePlugin +{ + Q_OBJECT + +// Q_PLUGIN_METADATA(IID "guru.guh.DevicePlugin" FILE "deviceplugincloudnotifications.json") + Q_INTERFACES(DevicePlugin) + +public: + CloudNotifications(AWSConnector *awsConnector, QObject* parent = nullptr); + + QJsonObject metaData() const; + + DeviceManager::DeviceSetupStatus setupDevice(Device *device) override; + void startMonitoringAutoDevices() override; + DeviceManager::DeviceError executeAction(Device *device, const Action &action) override; + +private slots: + void pushNotificationEndpointsUpdated(const QList &endpoints); + void pushNotificationSent(int id, int status); + +private: + AWSConnector *m_awsConnector = nullptr; + QHash m_pendingPushNotifications; +}; + +#endif // CLOUDNOTIFICATIONS_H diff --git a/libguh-core/guhcore.cpp b/libguh-core/guhcore.cpp index 8cc95d58..a4a733a0 100644 --- a/libguh-core/guhcore.cpp +++ b/libguh-core/guhcore.cpp @@ -103,6 +103,7 @@ #include "devicemanager.h" #include "plugin/device.h" +#include "cloudnotifications.h" namespace guhserver { @@ -506,6 +507,9 @@ void GuhCore::init() { m_cloudManager->setClientCertificates(m_configuration->cloudCertificateCA(), m_configuration->cloudCertificate(), m_configuration->cloudCertificateKey()); m_cloudManager->setEnabled(m_configuration->cloudEnabled()); + CloudNotifications *cloudNotifications = m_cloudManager->createNotificationsPlugin(); + m_deviceManager->registerStaticPlugin(cloudNotifications, cloudNotifications->metaData()); + connect(m_configuration, &GuhConfiguration::localeChanged, this, &GuhCore::onLocaleChanged); connect(m_configuration, &GuhConfiguration::cloudEnabledChanged, m_cloudManager, &CloudManager::setEnabled); connect(m_configuration, &GuhConfiguration::serverNameChanged, m_cloudManager, &CloudManager::setDeviceName); diff --git a/libguh-core/libguh-core.pro b/libguh-core/libguh-core.pro index 2d79e7ec..4c0ba6e8 100644 --- a/libguh-core/libguh-core.pro +++ b/libguh-core/libguh-core.pro @@ -73,6 +73,7 @@ HEADERS += guhcore.h \ certificategenerator.h \ awsconnector.h \ cloudmanager.h \ + cloudnotifications.h \ MbedTLS/MbedTLSConnection.hpp \ janusconnector.h \ pushbuttondbusservice.h \ @@ -96,7 +97,6 @@ HEADERS += guhcore.h \ hardware/network/avahi/qtavahiservicebrowserimplementation.h \ hardware/network/avahi/qtavahiservicebrowserimplementation_p.h \ - SOURCES += guhcore.cpp \ tcpserver.cpp \ mocktcpserver.cpp \ @@ -151,6 +151,7 @@ SOURCES += guhcore.cpp \ certificategenerator.cpp \ awsconnector.cpp \ cloudmanager.cpp \ + cloudnotifications.cpp \ MbedTLS/MbedTLSConnection.cpp \ janusconnector.cpp \ pushbuttondbusservice.cpp \ diff --git a/libguh/devicemanager.cpp b/libguh/devicemanager.cpp index 9f513151..87b10ca9 100644 --- a/libguh/devicemanager.cpp +++ b/libguh/devicemanager.cpp @@ -208,7 +208,12 @@ DeviceManager::~DeviceManager() } foreach (DevicePlugin *plugin, m_devicePlugins) { - delete plugin; + if (plugin->parent() == this) { + qCDebug(dcDeviceManager()) << "Deleting plugin" << plugin->pluginName(); + delete plugin; + } else { + qCDebug(dcDeviceManager()) << "Not deleting plugin" << plugin->pluginName(); + } } } @@ -254,6 +259,19 @@ QList DeviceManager::pluginsMetadata() return pluginList; } +/*! Register a DevicePlugin class. This can be used to create devices internally from the guh system without having to create a full plugin. + The DeviceManager takes ownership of the object and will clean it up when exiting. Do not delete the object yourself. */ +void DeviceManager::registerStaticPlugin(DevicePlugin *plugin, const QJsonObject &metaData) +{ + if (!verifyPluginMetadata(metaData)) { + qCWarning(dcDeviceManager()) << "Failed to verify plugin metadata. Not loading static plugin:" << plugin->pluginName(); + return; + } + plugin->setParent(this); + plugin->setMetaData(metaData); + loadPlugin(plugin); +} + /*! Set the \a locale of all plugins and reload the translated strings. */ void DeviceManager::setLocale(const QLocale &locale) { @@ -1014,75 +1032,81 @@ void DeviceManager::loadPlugins() qCWarning(dcDeviceManager) << "Could not get plugin instance of" << entry; continue; } + pluginIface->setParent(this); if (!verifyPluginMetadata(loader.metaData().value("MetaData").toObject())) continue; pluginIface->setMetaData(loader.metaData().value("MetaData").toObject()); - pluginIface->setLocale(m_locale); - qApp->installTranslator(pluginIface->translator()); - - pluginIface->initPlugin(this); - - qCDebug(dcDeviceManager) << "**** Loaded plugin" << pluginIface->pluginName(); - foreach (const Vendor &vendor, pluginIface->supportedVendors()) { - qCDebug(dcDeviceManager) << "* Loaded vendor:" << vendor.name(); - if (m_supportedVendors.contains(vendor.id())) - continue; - - m_supportedVendors.insert(vendor.id(), vendor); - } - - foreach (const DeviceClass &deviceClass, pluginIface->supportedDevices()) { - if (!m_supportedVendors.contains(deviceClass.vendorId())) { - qCWarning(dcDeviceManager) << "Vendor not found. Ignoring device. VendorId:" << deviceClass.vendorId() << "DeviceClass:" << deviceClass.name() << deviceClass.id(); - continue; - } - m_vendorDeviceMap[deviceClass.vendorId()].append(deviceClass.id()); - m_supportedDevices.insert(deviceClass.id(), deviceClass); - qCDebug(dcDeviceManager) << "* Loaded device class:" << deviceClass.name(); - } - - GuhSettings settings(GuhSettings::SettingsRolePlugins); - settings.beginGroup("PluginConfig"); - ParamList params; - if (settings.childGroups().contains(pluginIface->pluginId().toString())) { - settings.beginGroup(pluginIface->pluginId().toString()); - foreach (const QString ¶mTypeIdString, settings.allKeys()) { - Param param(ParamTypeId(paramTypeIdString), settings.value(paramTypeIdString)); - params.append(param); - } - settings.endGroup(); - } else if (!pluginIface->configurationDescription().isEmpty()){ - // plugin requires config but none stored. Init with defaults - foreach (const ParamType ¶mType, pluginIface->configurationDescription()) { - Param param(paramType.id(), paramType.defaultValue()); - params.append(param); - } - } - settings.endGroup(); - - if (params.count() > 0) { - DeviceError status = pluginIface->setConfiguration(params); - if (status != DeviceErrorNoError) { - qCWarning(dcDeviceManager) << "Error setting params to plugin. Broken configuration?"; - } - } - - m_devicePlugins.insert(pluginIface->pluginId(), pluginIface); - - connect(pluginIface, &DevicePlugin::emitEvent, this, &DeviceManager::eventTriggered); - connect(pluginIface, &DevicePlugin::devicesDiscovered, this, &DeviceManager::slotDevicesDiscovered, Qt::QueuedConnection); - connect(pluginIface, &DevicePlugin::deviceSetupFinished, this, &DeviceManager::slotDeviceSetupFinished); - connect(pluginIface, &DevicePlugin::actionExecutionFinished, this, &DeviceManager::actionExecutionFinished); - connect(pluginIface, &DevicePlugin::pairingFinished, this, &DeviceManager::slotPairingFinished); - connect(pluginIface, &DevicePlugin::autoDevicesAppeared, this, &DeviceManager::onAutoDevicesAppeared); - connect(pluginIface, &DevicePlugin::autoDeviceDisappeared, this, &DeviceManager::onAutoDeviceDisappeared); + loadPlugin(pluginIface); } } } +void DeviceManager::loadPlugin(DevicePlugin *pluginIface) +{ + pluginIface->setLocale(m_locale); + qApp->installTranslator(pluginIface->translator()); + + pluginIface->initPlugin(this); + + qCDebug(dcDeviceManager) << "**** Loaded plugin" << pluginIface->pluginName(); + foreach (const Vendor &vendor, pluginIface->supportedVendors()) { + qCDebug(dcDeviceManager) << "* Loaded vendor:" << vendor.name(); + if (m_supportedVendors.contains(vendor.id())) + continue; + + m_supportedVendors.insert(vendor.id(), vendor); + } + + foreach (const DeviceClass &deviceClass, pluginIface->supportedDevices()) { + if (!m_supportedVendors.contains(deviceClass.vendorId())) { + qCWarning(dcDeviceManager) << "Vendor not found. Ignoring device. VendorId:" << deviceClass.vendorId() << "DeviceClass:" << deviceClass.name() << deviceClass.id(); + continue; + } + m_vendorDeviceMap[deviceClass.vendorId()].append(deviceClass.id()); + m_supportedDevices.insert(deviceClass.id(), deviceClass); + qCDebug(dcDeviceManager) << "* Loaded device class:" << deviceClass.name(); + } + + GuhSettings settings(GuhSettings::SettingsRolePlugins); + settings.beginGroup("PluginConfig"); + ParamList params; + if (settings.childGroups().contains(pluginIface->pluginId().toString())) { + settings.beginGroup(pluginIface->pluginId().toString()); + foreach (const QString ¶mTypeIdString, settings.allKeys()) { + Param param(ParamTypeId(paramTypeIdString), settings.value(paramTypeIdString)); + params.append(param); + } + settings.endGroup(); + } else if (!pluginIface->configurationDescription().isEmpty()){ + // plugin requires config but none stored. Init with defaults + foreach (const ParamType ¶mType, pluginIface->configurationDescription()) { + Param param(paramType.id(), paramType.defaultValue()); + params.append(param); + } + } + settings.endGroup(); + + if (params.count() > 0) { + DeviceError status = pluginIface->setConfiguration(params); + if (status != DeviceErrorNoError) { + qCWarning(dcDeviceManager) << "Error setting params to plugin. Broken configuration?"; + } + } + + m_devicePlugins.insert(pluginIface->pluginId(), pluginIface); + + connect(pluginIface, &DevicePlugin::emitEvent, this, &DeviceManager::eventTriggered); + connect(pluginIface, &DevicePlugin::devicesDiscovered, this, &DeviceManager::slotDevicesDiscovered, Qt::QueuedConnection); + connect(pluginIface, &DevicePlugin::deviceSetupFinished, this, &DeviceManager::slotDeviceSetupFinished); + connect(pluginIface, &DevicePlugin::actionExecutionFinished, this, &DeviceManager::actionExecutionFinished); + connect(pluginIface, &DevicePlugin::pairingFinished, this, &DeviceManager::slotPairingFinished); + connect(pluginIface, &DevicePlugin::autoDevicesAppeared, this, &DeviceManager::onAutoDevicesAppeared); + connect(pluginIface, &DevicePlugin::autoDeviceDisappeared, this, &DeviceManager::onAutoDeviceDisappeared); +} + void DeviceManager::loadConfiguredDevices() { GuhSettings settings(GuhSettings::SettingsRoleDevices); @@ -1324,7 +1348,7 @@ void DeviceManager::onAutoDevicesAppeared(const DeviceClassId &deviceClassId, co foreach (const DeviceDescriptor &deviceDescriptor, deviceDescriptors) { Device *device = new Device(plugin->pluginId(), deviceClassId, this); device->m_autoCreated = true; - device->setName(deviceClass.name()); + device->setName(deviceDescriptor.title()); device->setParams(deviceDescriptor.params()); DeviceSetupStatus setupStatus = setupDevice(device); diff --git a/libguh/devicemanager.h b/libguh/devicemanager.h index e9ae28f9..439fbfa9 100644 --- a/libguh/devicemanager.h +++ b/libguh/devicemanager.h @@ -95,6 +95,7 @@ public: static QStringList pluginSearchDirs(); static QList pluginsMetadata(); + void registerStaticPlugin(DevicePlugin* plugin, const QJsonObject &metaData); void setLocale(const QLocale &locale); @@ -158,6 +159,7 @@ public slots: private slots: void loadPlugins(); + void loadPlugin(DevicePlugin *pluginIface); void loadConfiguredDevices(); void storeConfiguredDevices(); void startMonitoringAutoDevices();