File indexing completed on 2024-05-12 03:47:43

0001 /*
0002     File        : MQTTSubscription.cpp
0003     Project     : LabPlot
0004     Description : Represents a subscription made in MQTTClient
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2018 Kovacs Ferencz <kferike98@gmail.com>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 #include "backend/datasources/MQTTSubscription.h"
0011 #include "backend/datasources/MQTTClient.h"
0012 #include "backend/datasources/MQTTTopic.h"
0013 #include "backend/lib/XmlStreamReader.h"
0014 
0015 #include <KLocalizedString>
0016 #include <QIcon>
0017 
0018 /*!
0019   \class MQTTSubscription
0020   \brief Represents a subscription made in a MQTTClient object. It plays a role in managing MQTTTopic objects
0021   and makes possible representing the subscriptions and topics in a tree like structure
0022 
0023   \ingroup datasources
0024 */
0025 MQTTSubscription::MQTTSubscription(const QString& name)
0026     : Folder(name, AspectType::MQTTSubscription)
0027     , m_subscriptionName(name) {
0028     qDebug() << "New MQTTSubscription: " << name;
0029 }
0030 
0031 MQTTSubscription::~MQTTSubscription() {
0032     qDebug() << "Delete MQTTSubscription: " << m_subscriptionName;
0033 }
0034 
0035 /*!
0036  *\brief Returns the object's MQTTTopic children
0037  *
0038  * \return a vector of pointers to the children of the MQTTSubscription
0039  */
0040 const QVector<MQTTTopic*> MQTTSubscription::topics() const {
0041     return children<MQTTTopic>();
0042 }
0043 
0044 /*!
0045  *\brief Returns the object's parent
0046  *
0047  * \return a pointer to the parent MQTTTopic of the object
0048  */
0049 MQTTClient* MQTTSubscription::mqttClient() const {
0050     return m_MQTTClient;
0051 }
0052 
0053 /*!
0054  *\brief Called when a message arrived to a topic contained by the MQTTSubscription
0055  * If the topic can't be found among the children, a new MQTTTopic is instantiated
0056  * Passes the messages to the appropriate MQTTTopic
0057  *
0058  * \param message the message to pass
0059  * \param topicName the name of the topic the message was sent to
0060  */
0061 void MQTTSubscription::messageArrived(const QString& message, const QString& topicName) {
0062     bool found = false;
0063     QVector<MQTTTopic*> topics = children<MQTTTopic>();
0064     // search for the topic among the MQTTTopic children
0065     for (auto* topic : topics) {
0066         if (topicName == topic->topicName()) {
0067             // pass the message to the topic
0068             topic->newMessage(message);
0069 
0070             // read the message if needed
0071             if ((m_MQTTClient->updateType() == MQTTClient::UpdateType::NewData) && !m_MQTTClient->isPaused())
0072                 topic->read();
0073 
0074             found = true;
0075             break;
0076         }
0077     }
0078 
0079     // if the topic can't be found, we add it as a new MQTTTopic, and read from it if needed
0080     if (!found) {
0081         auto* newTopic = new MQTTTopic(topicName, this, false);
0082         addChildFast(newTopic); // no need for undo/redo here
0083         newTopic->newMessage(message);
0084         if ((m_MQTTClient->updateType() == MQTTClient::UpdateType::NewData) && !m_MQTTClient->isPaused())
0085             newTopic->read();
0086     }
0087 }
0088 
0089 /*!
0090  *\brief Returns the subscription's name
0091  *
0092  * \return m_subscriptionName
0093  */
0094 QString MQTTSubscription::subscriptionName() const {
0095     return m_subscriptionName;
0096 }
0097 
0098 /*!
0099  *\brief Sets the MQTTClient the subscription belongs to
0100  *
0101  * \param client
0102  */
0103 void MQTTSubscription::setMQTTClient(MQTTClient* client) {
0104     m_MQTTClient = client;
0105 }
0106 
0107 /*!
0108  *\brief Returns the icon of MQTTSubscription
0109  */
0110 QIcon MQTTSubscription::icon() const {
0111     return QIcon::fromTheme(QStringLiteral("mail-signed-full"));
0112 }
0113 
0114 // ##############################################################################
0115 // ##################  Serialization/Deserialization  ###########################
0116 // ##############################################################################
0117 /*!
0118   Saves as XML.
0119  */
0120 void MQTTSubscription::save(QXmlStreamWriter* writer) const {
0121     writer->writeStartElement(QStringLiteral("MQTTSubscription"));
0122     writeBasicAttributes(writer);
0123     writeCommentElement(writer);
0124 
0125     // general
0126     writer->writeStartElement(QStringLiteral("general"));
0127     writer->writeAttribute(QStringLiteral("subscriptionName"), m_subscriptionName);
0128     writer->writeEndElement();
0129 
0130     // MQTTTopics
0131     for (auto* topic : children<MQTTTopic>(AbstractAspect::ChildIndexFlag::IncludeHidden))
0132         topic->save(writer);
0133 
0134     writer->writeEndElement(); // "MQTTSubscription"
0135 }
0136 
0137 /*!
0138   Loads from XML.
0139 */
0140 bool MQTTSubscription::load(XmlStreamReader* reader, bool preview) {
0141     if (!readBasicAttributes(reader))
0142         return false;
0143 
0144     QXmlStreamAttributes attribs;
0145 
0146     while (!reader->atEnd()) {
0147         reader->readNext();
0148         if (reader->isEndElement() && reader->name() == QLatin1String("MQTTSubscription"))
0149             break;
0150 
0151         if (!reader->isStartElement())
0152             continue;
0153 
0154         if (reader->name() == QLatin1String("comment")) {
0155             if (!readCommentElement(reader))
0156                 return false;
0157         } else if (reader->name() == QLatin1String("general")) {
0158             attribs = reader->attributes();
0159             m_subscriptionName = attribs.value(QStringLiteral("subscriptionName")).toString();
0160         } else if (reader->name() == QLatin1String("MQTTTopic")) {
0161             auto* topic = new MQTTTopic(QString(), this, false);
0162             if (!topic->load(reader, preview)) {
0163                 delete topic;
0164                 return false;
0165             }
0166             addChildFast(topic);
0167         } else { // unknown element
0168             reader->raiseWarning(i18n("unknown element '%1'", reader->name().toString()));
0169             if (!reader->skipToEndElement())
0170                 return false;
0171         }
0172     }
0173 
0174     Q_EMIT loaded(this->subscriptionName());
0175     return !reader->hasError();
0176 }