mirror of
https://github.com/qt/qtmqtt.git
synced 2026-10-25 16:16:26 +00:00
Add initial support for QMqttSubscription
The class handles all subscription related items. Developers can use it to manage the state of the subscription. Having a subscription object simplifies message handling, there is no need to do a topic check for each message received.
This commit is contained in:
parent
622b0fa962
commit
8bda237fa0
@ -1,2 +1,4 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS += simpleclient
|
||||
SUBDIRS += \
|
||||
simpleclient \
|
||||
subscriptions
|
||||
|
||||
11
examples/mqtt/subscriptions/main.cpp
Normal file
11
examples/mqtt/subscriptions/main.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "mainwindow.h"
|
||||
#include <QApplication>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
MainWindow w;
|
||||
w.show();
|
||||
|
||||
return a.exec();
|
||||
}
|
||||
115
examples/mqtt/subscriptions/mainwindow.cpp
Normal file
115
examples/mqtt/subscriptions/mainwindow.cpp
Normal file
@ -0,0 +1,115 @@
|
||||
#include "mainwindow.h"
|
||||
#include "subscriptionwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
|
||||
#include <QtCore/QDateTime>
|
||||
#include <QtMqtt/QMqttClient>
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::MainWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
m_client = new QMqttClient(this);
|
||||
m_client->setHostname(ui->lineEditHost->text());
|
||||
m_client->setPort(ui->spinBoxPort->value());
|
||||
|
||||
connect(m_client, &QMqttClient::stateChanged, this, &MainWindow::updateLogStateChange);
|
||||
connect(m_client, &QMqttClient::disconnected, this, &MainWindow::brokerDisconnected);
|
||||
|
||||
connect(m_client, &QMqttClient::subscribed, this, [this]() {
|
||||
const QString content = QDateTime::currentDateTime().toString()
|
||||
+ QLatin1String("Subscription Succeeded")
|
||||
+ QLatin1Char('\n');
|
||||
ui->editLog->insertPlainText(content);
|
||||
});
|
||||
|
||||
connect(m_client, &QMqttClient::messageReceived, this, [this](const QString &topic, const QString &message) {
|
||||
const QString content = QDateTime::currentDateTime().toString()
|
||||
+ QLatin1String(" Received Topic: ")
|
||||
+ topic
|
||||
+ QLatin1String(" Message: ")
|
||||
+ message
|
||||
+ QLatin1Char('\n');
|
||||
ui->editLog->insertPlainText(content);
|
||||
});
|
||||
|
||||
connect(m_client, &QMqttClient::pingResponse, this, [this]() {
|
||||
ui->buttonPing->setEnabled(true);
|
||||
const QString content = QDateTime::currentDateTime().toString()
|
||||
+ QLatin1String(" PingResponse")
|
||||
+ QLatin1Char('\n');
|
||||
ui->editLog->insertPlainText(content);
|
||||
});
|
||||
|
||||
connect(ui->lineEditHost, &QLineEdit::textChanged, m_client, &QMqttClient::setHostname);
|
||||
connect(ui->spinBoxPort, SIGNAL(valueChanged(int)), this, SLOT(setClientPort(int)));
|
||||
updateLogStateChange();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
qApp->quit();
|
||||
}
|
||||
|
||||
void MainWindow::on_buttonConnect_clicked()
|
||||
{
|
||||
if (m_client->state() == QMqttClient::Disconnected) {
|
||||
ui->lineEditHost->setEnabled(false);
|
||||
ui->spinBoxPort->setEnabled(false);
|
||||
ui->buttonConnect->setText(tr("Disconnect"));
|
||||
m_client->connectToHost();
|
||||
} else {
|
||||
ui->lineEditHost->setEnabled(true);
|
||||
ui->spinBoxPort->setEnabled(true);
|
||||
ui->buttonConnect->setText(tr("Connect"));
|
||||
m_client->disconnectFromHost();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_buttonQuit_clicked()
|
||||
{
|
||||
QApplication::quit();
|
||||
}
|
||||
|
||||
void MainWindow::updateLogStateChange()
|
||||
{
|
||||
const QString content = QDateTime::currentDateTime().toString()
|
||||
+ QLatin1String(": State Change")
|
||||
+ QString::number(m_client->state())
|
||||
+ QLatin1Char('\n');
|
||||
ui->editLog->insertPlainText(content);
|
||||
}
|
||||
|
||||
void MainWindow::brokerDisconnected()
|
||||
{
|
||||
ui->lineEditHost->setEnabled(true);
|
||||
ui->spinBoxPort->setEnabled(true);
|
||||
ui->buttonConnect->setText(tr("Connect"));
|
||||
}
|
||||
|
||||
void MainWindow::setClientPort(int p)
|
||||
{
|
||||
m_client->setPort(p);
|
||||
}
|
||||
|
||||
void MainWindow::on_buttonPublish_clicked()
|
||||
{
|
||||
m_client->publish(ui->lineEditTopic->text(), ui->lineEditMessage->text());
|
||||
}
|
||||
|
||||
void MainWindow::on_buttonSubscribe_clicked()
|
||||
{
|
||||
auto subscription = m_client->subscribe(ui->lineEditTopic->text());
|
||||
auto subWindow = new SubscriptionWindow(subscription);
|
||||
subWindow->setWindowTitle(subscription->topic());
|
||||
subWindow->show();
|
||||
}
|
||||
|
||||
void MainWindow::on_buttonPing_clicked()
|
||||
{
|
||||
ui->buttonPing->setEnabled(false);
|
||||
m_client->requestPing();
|
||||
}
|
||||
39
examples/mqtt/subscriptions/mainwindow.h
Normal file
39
examples/mqtt/subscriptions/mainwindow.h
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QTcpSocket>
|
||||
#include <QtMqtt/QMqttClient>
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = 0);
|
||||
~MainWindow();
|
||||
|
||||
private slots:
|
||||
void on_buttonConnect_clicked();
|
||||
void on_buttonQuit_clicked();
|
||||
void updateLogStateChange();
|
||||
|
||||
void brokerDisconnected();
|
||||
void setClientPort(int p);
|
||||
|
||||
void on_buttonPublish_clicked();
|
||||
|
||||
void on_buttonSubscribe_clicked();
|
||||
|
||||
void on_buttonPing_clicked();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
QMqttClient *m_client;
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
190
examples/mqtt/subscriptions/mainwindow.ui
Normal file
190
examples/mqtt/subscriptions/mainwindow.ui
Normal file
@ -0,0 +1,190 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>629</width>
|
||||
<height>595</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralWidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Host:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="lineEditHost">
|
||||
<property name="text">
|
||||
<string>hostprocess.de</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Port:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="spinBoxPort">
|
||||
<property name="maximum">
|
||||
<number>99999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1883</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonConnect">
|
||||
<property name="text">
|
||||
<string>Connect</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="lineEditTopic">
|
||||
<property name="text">
|
||||
<string>qtmqtt/topic1</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Topic:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Message:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="buttonPublish">
|
||||
<property name="text">
|
||||
<string>Publish</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="buttonSubscribe">
|
||||
<property name="text">
|
||||
<string>Subscribe</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="lineEditMessage">
|
||||
<property name="text">
|
||||
<string>This is a test message</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QPushButton" name="buttonPing">
|
||||
<property name="text">
|
||||
<string>Ping</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Log Messages</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="editLog"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonQuit">
|
||||
<property name="text">
|
||||
<string>Quit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menuBar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>629</width>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<property name="title">
|
||||
<string>File</string>
|
||||
</property>
|
||||
<addaction name="actionQuit"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="mainToolBar">
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusBar"/>
|
||||
<action name="actionQuit">
|
||||
<property name="text">
|
||||
<string>Quit</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
27
examples/mqtt/subscriptions/subscriptions.pro
Normal file
27
examples/mqtt/subscriptions/subscriptions.pro
Normal file
@ -0,0 +1,27 @@
|
||||
QT += core gui network widgets mqtt
|
||||
|
||||
TARGET = mqttsubscriptions
|
||||
|
||||
# The following define makes your compiler emit warnings if you use
|
||||
# any feature of Qt which as been marked as deprecated (the exact warnings
|
||||
# depend on your compiler). Please consult the documentation of the
|
||||
# deprecated API in order to know how to port your code away from it.
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
# You can also make your code fail to compile if you use deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
|
||||
SOURCES += main.cpp\
|
||||
mainwindow.cpp \
|
||||
subscriptionwindow.cpp
|
||||
|
||||
HEADERS += mainwindow.h \
|
||||
subscriptionwindow.h
|
||||
FORMS += mainwindow.ui \
|
||||
subscriptionwindow.ui
|
||||
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/mqtt/subscriptions
|
||||
INSTALLS += target
|
||||
47
examples/mqtt/subscriptions/subscriptionwindow.cpp
Normal file
47
examples/mqtt/subscriptions/subscriptionwindow.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
#include "subscriptionwindow.h"
|
||||
#include "ui_subscriptionwindow.h"
|
||||
|
||||
SubscriptionWindow::SubscriptionWindow(QSharedPointer<QMqttSubscription> &sub, QWidget *parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::SubscriptionWindow)
|
||||
{
|
||||
m_sub = sub;
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->labelSub->setText(m_sub->topic());
|
||||
updateStatus(m_sub->state());
|
||||
connect(m_sub.data(), &QMqttSubscription::messageReceived, this, &SubscriptionWindow::updateMessage);
|
||||
connect(m_sub.data(), &QMqttSubscription::stateChanged, this, &SubscriptionWindow::updateStatus);
|
||||
connect(ui->pushButton, &QAbstractButton::clicked, m_sub.data(), &QMqttSubscription::unsubscribe);
|
||||
}
|
||||
|
||||
SubscriptionWindow::~SubscriptionWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void SubscriptionWindow::updateMessage(const QString &text)
|
||||
{
|
||||
ui->listWidget->addItem(text);
|
||||
}
|
||||
|
||||
void SubscriptionWindow::updateStatus(QMqttSubscription::SubscriptionState state)
|
||||
{
|
||||
switch (state) {
|
||||
case QMqttSubscription::Unsubscribed:
|
||||
ui->labelStatus->setText(QLatin1String("Unsubscribed"));
|
||||
break;
|
||||
case QMqttSubscription::Pending:
|
||||
ui->labelStatus->setText(QLatin1String("Pending"));
|
||||
break;
|
||||
case QMqttSubscription::Subscribed:
|
||||
ui->labelStatus->setText(QLatin1String("Subscribed"));
|
||||
break;
|
||||
case QMqttSubscription::Error:
|
||||
ui->labelStatus->setText(QLatin1String("Error"));
|
||||
break;
|
||||
default:
|
||||
ui->labelStatus->setText(QLatin1String("--Unknown--"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
27
examples/mqtt/subscriptions/subscriptionwindow.h
Normal file
27
examples/mqtt/subscriptions/subscriptionwindow.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef SUBSCRIPTIONWINDOW_H
|
||||
#define SUBSCRIPTIONWINDOW_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QtMqtt/QMqttSubscription>
|
||||
|
||||
namespace Ui {
|
||||
class SubscriptionWindow;
|
||||
}
|
||||
|
||||
class SubscriptionWindow : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SubscriptionWindow(QSharedPointer<QMqttSubscription> &sub, QWidget *parent = 0);
|
||||
~SubscriptionWindow();
|
||||
|
||||
public slots:
|
||||
void updateMessage(const QString &text);
|
||||
void updateStatus(QMqttSubscription::SubscriptionState state);
|
||||
private:
|
||||
QSharedPointer<QMqttSubscription> m_sub;
|
||||
Ui::SubscriptionWindow *ui;
|
||||
};
|
||||
|
||||
#endif // SUBSCRIPTIONWINDOW_H
|
||||
63
examples/mqtt/subscriptions/subscriptionwindow.ui
Normal file
63
examples/mqtt/subscriptions/subscriptionwindow.ui
Normal file
@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SubscriptionWindow</class>
|
||||
<widget class="QWidget" name="SubscriptionWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Subscription:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="labelSub">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Status:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="labelStatus">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listWidget"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="text">
|
||||
<string>Unsubscribe</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@ -18,9 +18,11 @@ PRIVATE_HEADERS += \
|
||||
SOURCES += \
|
||||
qmqttclient.cpp \
|
||||
qmqttconnection.cpp \
|
||||
qmqttcontrolpacket.cpp
|
||||
qmqttcontrolpacket.cpp \
|
||||
qmqttsubscription.cpp
|
||||
|
||||
HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS \
|
||||
qmqttcontrolpacket_p.h
|
||||
qmqttcontrolpacket_p.h \
|
||||
qmqttsubscription.h
|
||||
|
||||
load(qt_module)
|
||||
|
||||
@ -59,7 +59,7 @@ QIODevice *QMqttClient::transport() const
|
||||
return d->m_connection.transport();
|
||||
}
|
||||
|
||||
bool QMqttClient::subscribe(const QString &topic)
|
||||
QSharedPointer<QMqttSubscription> QMqttClient::subscribe(const QString &topic)
|
||||
{
|
||||
Q_D(QMqttClient);
|
||||
return d->m_connection.sendControlSubscribe(topic);
|
||||
|
||||
@ -31,9 +31,11 @@
|
||||
#define QTMQTTCLIENT_H
|
||||
|
||||
#include <QtMqtt/qmqttglobal.h>
|
||||
#include <QtMqtt/QMqttSubscription>
|
||||
|
||||
#include <QObject>
|
||||
#include <QtCore/QIODevice>
|
||||
#include <QtCore/QSharedPointer>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
@ -68,7 +70,7 @@ public:
|
||||
void setTransport(QIODevice *device, TransportType transport);
|
||||
QIODevice *transport() const;
|
||||
|
||||
bool subscribe(const QString& topic);
|
||||
QSharedPointer<QMqttSubscription> subscribe(const QString& topic);
|
||||
void unsubscribe(const QString& topic);
|
||||
|
||||
bool publish(const QString &topic, const QString& message = QString());
|
||||
|
||||
@ -191,8 +191,11 @@ bool QMqttConnection::sendControlPublish(const QString &topic, const QString &me
|
||||
return writePacketToTransport(packet);
|
||||
}
|
||||
|
||||
bool QMqttConnection::sendControlSubscribe(const QString &topic)
|
||||
QSharedPointer<QMqttSubscription> QMqttConnection::sendControlSubscribe(const QString &topic)
|
||||
{
|
||||
if (m_activeSubscriptions.contains(topic))
|
||||
return m_activeSubscriptions[topic];
|
||||
|
||||
// has to have 0010 as bits 3-0, maybe update SUBSCRIBE instead?
|
||||
// MQTT-3.8.1-1
|
||||
const quint8 header = QMqttControlPacket::SUBSCRIBE + 0x02;
|
||||
@ -206,14 +209,22 @@ bool QMqttConnection::sendControlSubscribe(const QString &topic)
|
||||
// ### TODO: Add actual QOS
|
||||
packet.append(char(0)); // QOS
|
||||
|
||||
QSharedPointer<QMqttSubscription> result(new QMqttSubscription);
|
||||
result->m_topic = topic;
|
||||
result->setState(QMqttSubscription::Pending);
|
||||
|
||||
if (!writePacketToTransport(packet))
|
||||
return QSharedPointer<QMqttSubscription>();
|
||||
|
||||
// SUBACK must contain identifier MQTT-3.8.4-2
|
||||
m_pendingSubscriptionAck.insert(identifier);
|
||||
return writePacketToTransport(packet);
|
||||
m_pendingSubscriptionAck.insert(identifier, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool QMqttConnection::sendControlUnsubscribe()
|
||||
{
|
||||
Q_UNIMPLEMENTED();
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -231,6 +242,10 @@ bool QMqttConnection::sendControlDisconnect()
|
||||
{
|
||||
m_pingTimer.stop();
|
||||
|
||||
for (auto sub : m_activeSubscriptions)
|
||||
sub->unsubscribe();
|
||||
m_activeSubscriptions.clear();
|
||||
|
||||
const QMqttControlPacket packet(QMqttControlPacket::DISCONNECT);
|
||||
if (!writePacketToTransport(packet)) {
|
||||
qWarning("Could not write DISCONNECT frame to transport");
|
||||
@ -327,18 +342,21 @@ void QMqttConnection::transportReadReady()
|
||||
}
|
||||
quint8 result;
|
||||
m_transport->read((char*)&result, 1);
|
||||
auto sub = m_pendingSubscriptionAck.take(id);
|
||||
if (result <= 2) {
|
||||
// ### TODO: subscriptionSucceeded/Failed
|
||||
emit m_client->subscribed();
|
||||
// 0 Success with QoS 0
|
||||
// 1 Success with QoS 1
|
||||
// 2 Success with QoS 2
|
||||
m_pendingSubscriptionAck.remove(id);
|
||||
sub->setState(QMqttSubscription::Subscribed);
|
||||
m_activeSubscriptions.insert(sub->topic(), sub);
|
||||
} else if (result == 0x80) {
|
||||
// ### TODO: subscriptionFailed
|
||||
qWarning("Subscription failed");
|
||||
sub->setState(QMqttSubscription::Error);
|
||||
} else {
|
||||
qWarning("Received invalid SUBACK result value");
|
||||
sub->setState(QMqttSubscription::Error);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -356,6 +374,11 @@ void QMqttConnection::transportReadReady()
|
||||
const QString message = QString::fromUtf8(reinterpret_cast<const char *>(m_transport->read(messageLength).constData()));
|
||||
|
||||
emit m_client->messageReceived(topic, message);
|
||||
|
||||
// Find a subscription
|
||||
const QMap<QString, QSharedPointer<QMqttSubscription>>::const_iterator sub = m_activeSubscriptions.find(topic);
|
||||
if (sub != m_activeSubscriptions.constEnd())
|
||||
emit (*sub)->messageReceived(message);
|
||||
break;
|
||||
}
|
||||
case QMqttControlPacket::PINGRESP: {
|
||||
|
||||
@ -43,7 +43,9 @@
|
||||
|
||||
#include "qmqttclient.h"
|
||||
#include "qmqttcontrolpacket_p.h"
|
||||
#include "qmqttsubscription.h"
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QSharedPointer>
|
||||
#include <QtCore/QSet>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QtEndian>
|
||||
@ -79,7 +81,7 @@ public:
|
||||
|
||||
bool sendControlConnect();
|
||||
bool sendControlPublish(const QString &topic, const QString &message);
|
||||
bool sendControlSubscribe(const QString &topic);
|
||||
QSharedPointer<QMqttSubscription> sendControlSubscribe(const QString &topic);
|
||||
bool sendControlUnsubscribe();
|
||||
bool sendControlPingRequest();
|
||||
bool sendControlDisconnect();
|
||||
@ -100,7 +102,8 @@ public:
|
||||
QMqttClient *m_client{nullptr};
|
||||
private:
|
||||
bool writePacketToTransport(const QMqttControlPacket &p);
|
||||
QSet<quint16> m_pendingSubscriptionAck;
|
||||
QMap<quint16, QSharedPointer<QMqttSubscription>> m_pendingSubscriptionAck;
|
||||
QMap<QString, QSharedPointer<QMqttSubscription>> m_activeSubscriptions;
|
||||
InternalConnectionState m_internalState{BrokerDisconnected};
|
||||
QTimer m_pingTimer;
|
||||
};
|
||||
|
||||
67
src/mqtt/qmqttsubscription.cpp
Normal file
67
src/mqtt/qmqttsubscription.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the Qt Mqtt module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 or (at your option) any later version
|
||||
** approved by the KDE Free Qt Foundation. The licenses are as published by
|
||||
** the Free Software Foundation and appearing in the file LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
#include "qmqttsubscription.h"
|
||||
|
||||
QMqttSubscription::QMqttSubscription(QObject *parent) : QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QMqttSubscription::~QMqttSubscription()
|
||||
{
|
||||
if (m_state == Subscribed)
|
||||
unsubscribe();
|
||||
}
|
||||
|
||||
QMqttSubscription::SubscriptionState QMqttSubscription::state() const
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
QString QMqttSubscription::topic() const
|
||||
{
|
||||
return m_topic;
|
||||
}
|
||||
|
||||
void QMqttSubscription::setState(QMqttSubscription::SubscriptionState state)
|
||||
{
|
||||
if (m_state == state)
|
||||
return;
|
||||
|
||||
m_state = state;
|
||||
emit stateChanged(m_state);
|
||||
}
|
||||
|
||||
void QMqttSubscription::unsubscribe()
|
||||
{
|
||||
Q_UNIMPLEMENTED();
|
||||
setState(Unsubscribed);
|
||||
// Do send unsubscribe
|
||||
// Emit state change to notify all instances
|
||||
}
|
||||
71
src/mqtt/qmqttsubscription.h
Normal file
71
src/mqtt/qmqttsubscription.h
Normal file
@ -0,0 +1,71 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the Qt Mqtt module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:GPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 or (at your option) any later version
|
||||
** approved by the KDE Free Qt Foundation. The licenses are as published by
|
||||
** the Free Software Foundation and appearing in the file LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
#ifndef QMQTTSUBSCRIPTION_H
|
||||
#define QMQTTSUBSCRIPTION_H
|
||||
#include <QtCore/QObject>
|
||||
#include <QtMqtt/qmqttglobal.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class Q_MQTT_EXPORT QMqttSubscription : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(SubscriptionState state READ state WRITE setState NOTIFY stateChanged)
|
||||
Q_PROPERTY(QString topic READ topic)
|
||||
public:
|
||||
~QMqttSubscription();
|
||||
enum SubscriptionState {
|
||||
Unsubscribed = 0,
|
||||
Pending,
|
||||
Subscribed,
|
||||
Error
|
||||
};
|
||||
|
||||
SubscriptionState state() const;
|
||||
QString topic() const;
|
||||
|
||||
signals:
|
||||
void stateChanged(SubscriptionState state);
|
||||
void messageReceived(const QString msg);
|
||||
|
||||
public slots:
|
||||
void setState(SubscriptionState state);
|
||||
void unsubscribe();
|
||||
|
||||
private:
|
||||
friend class QMqttConnection;
|
||||
friend class QMqttClient;
|
||||
explicit QMqttSubscription(QObject *parent = nullptr);
|
||||
SubscriptionState m_state;
|
||||
QString m_topic;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QMQTTSUBSCRIPTION_H
|
||||
Loading…
Reference in New Issue
Block a user