summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorMaurice Kalinowski <maurice.kalinowski@qt.io>2017-06-14 13:42:33 +0200
committerMaurice Kalinowski <maurice.kalinowski@qt.io>2017-06-20 07:36:14 +0000
commitbbe6eea7db67dda88cd47211e96c5ace8984a426 (patch)
treea4c810a8c817e3190760fdaf809941cedf746127 /examples
parent73cfe25e9a5d62fc95b65aec58f9faad38b9818e (diff)
Add websocket example
Beside QtWebSockets not officially supporting subprotocols, one can circumvent this using QNetworkRequest. Works nicely with hivemq, yet need to find a websocket server supporting MQTT 3.1.1. Change-Id: I889eca86b5b7e4a9752aa0b4cef525d3b8462ab0 Reviewed-by: Alex Blasche <alexander.blasche@qt.io> Reviewed-by: Karsten Heimrich <karsten.heimrich@qt.io>
Diffstat (limited to 'examples')
-rw-r--r--examples/mqtt/mqtt.pro3
-rw-r--r--examples/mqtt/websocketsubscription/clientsubscription.cpp121
-rw-r--r--examples/mqtt/websocketsubscription/clientsubscription.h86
-rw-r--r--examples/mqtt/websocketsubscription/main.cpp108
-rw-r--r--examples/mqtt/websocketsubscription/websocketiodevice.cpp115
-rw-r--r--examples/mqtt/websocketsubscription/websocketiodevice.h85
-rw-r--r--examples/mqtt/websocketsubscription/websocketsubscription.pro32
7 files changed, 549 insertions, 1 deletions
diff --git a/examples/mqtt/mqtt.pro b/examples/mqtt/mqtt.pro
index 5c4c4d2..f719fff 100644
--- a/examples/mqtt/mqtt.pro
+++ b/examples/mqtt/mqtt.pro
@@ -2,4 +2,5 @@ TEMPLATE = subdirs
SUBDIRS += \
simpleclient \
subscriptions \
- quicksubscription
+ quicksubscription \
+ websocketsubscription
diff --git a/examples/mqtt/websocketsubscription/clientsubscription.cpp b/examples/mqtt/websocketsubscription/clientsubscription.cpp
new file mode 100644
index 0000000..c360e27
--- /dev/null
+++ b/examples/mqtt/websocketsubscription/clientsubscription.cpp
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "clientsubscription.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QLoggingCategory>
+
+Q_LOGGING_CATEGORY(lcWebSocketMqtt, "qtdemo.websocket.mqtt")
+
+ClientSubscription::ClientSubscription(QObject *parent) : QObject(parent)
+{
+ connect(this, &ClientSubscription::errorOccured, qApp, &QCoreApplication::quit);
+}
+
+void ClientSubscription::setUrl(const QUrl &url)
+{
+ m_url = url;
+}
+
+void ClientSubscription::setTopic(const QString &topic)
+{
+ m_topic = topic;
+}
+
+void ClientSubscription::setVersion(int v)
+{
+ m_version = v;
+}
+
+void ClientSubscription::connectAndSubscribe()
+{
+ qCDebug(lcWebSocketMqtt) << "Connecting to broker at " << m_url;
+
+ m_device.setUrl(m_url);
+ m_device.setProtocol(m_version == 3 ? "mqttv3.1" : "mqtt");
+
+ connect(&m_device, &WebSocketIODevice::socketConnected, this, [this]() {
+ qCDebug(lcWebSocketMqtt) << "WebSocket connected, initializing MQTT connection.";
+
+ m_client.setProtocolVersion(m_version == 3 ? QMqttClient::MQTT_3_1 : QMqttClient::MQTT_3_1_1);
+ m_client.setTransport(&m_device, QMqttClient::IODevice);
+
+ connect(&m_client, &QMqttClient::connected, this, [this]() {
+ qCDebug(lcWebSocketMqtt) << "MQTT connection established";
+
+ m_subscription = m_client.subscribe(m_topic);
+ if (!m_subscription) {
+ qDebug() << "Failed to subscribe to " << m_topic;
+ emit errorOccured();
+ }
+
+ connect(m_subscription.data(), &QMqttSubscription::stateChanged,
+ [](QMqttSubscription::SubscriptionState s) {
+ qCDebug(lcWebSocketMqtt) << "Subscription state changed:" << s;
+ });
+
+ connect(m_subscription.data(), &QMqttSubscription::messageReceived,
+ [this](QMqttMessage msg) {
+ handleMessage(msg.payload());
+ });
+ });
+
+ m_client.connectToHost();
+ });
+ if (!m_device.open(QIODevice::ReadWrite))
+ qDebug() << "Could not open socket device";
+}
+
+void ClientSubscription::handleMessage(const QByteArray &msgContent)
+{
+ // Should happen when the internal device has ready read?
+ qInfo() << "New message:" << msgContent;
+}
diff --git a/examples/mqtt/websocketsubscription/clientsubscription.h b/examples/mqtt/websocketsubscription/clientsubscription.h
new file mode 100644
index 0000000..3f02e62
--- /dev/null
+++ b/examples/mqtt/websocketsubscription/clientsubscription.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CLIENTSUBSCRIPTION_H
+#define CLIENTSUBSCRIPTION_H
+
+#include "websocketiodevice.h"
+
+#include <QtCore/QObject>
+#include <QtMqtt/QMqttClient>
+#include <QtWebSockets/QWebSocket>
+
+class ClientSubscription : public QObject
+{
+ Q_OBJECT
+public:
+ ClientSubscription(QObject *parent = nullptr);
+
+ void setUrl(const QUrl &url); // ie ws://broker.hivemq.com:8000/mqtt
+ void setTopic(const QString &topic);
+ void setVersion(int v);
+signals:
+ void messageReceived(QByteArray);
+ void errorOccured();
+
+public slots:
+ void connectAndSubscribe();
+ void handleMessage(const QByteArray &msgContent);
+
+private:
+ QMqttClient m_client;
+ QSharedPointer<QMqttSubscription> m_subscription;
+ QUrl m_url;
+ QString m_topic;
+ WebSocketIODevice m_device;
+ int m_version;
+};
+
+#endif // CLIENTSUBSCRIPTION_H
diff --git a/examples/mqtt/websocketsubscription/main.cpp b/examples/mqtt/websocketsubscription/main.cpp
new file mode 100644
index 0000000..03ca84e
--- /dev/null
+++ b/examples/mqtt/websocketsubscription/main.cpp
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "clientsubscription.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QCommandLineParser>
+#include <QtCore/QLoggingCategory>
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication a(argc, argv);
+ QCoreApplication::setApplicationVersion("1.0");
+
+ QCommandLineParser parser;
+ parser.setApplicationDescription(QLatin1String("Websocket MQTT subscription tool"));
+ auto help = parser.addHelpOption();
+
+ // Use http://www.hivemq.com/demos/websocket-client/ in browser to publish
+ QCommandLineOption urlOption(QStringList() << "host" << "url" << "broker",
+ QStringLiteral("Host to connect to, eg ws://broker.hivemq.com:8000/mqtt"),
+ "host");
+ parser.addOption(urlOption);
+
+ QCommandLineOption subscriptionOption(QStringList() << "t" << "topic",
+ QStringLiteral("Topic to subscribe to"), "topic");
+ parser.addOption(subscriptionOption);
+
+ QCommandLineOption debugOption(QStringList() << "d" << "debug",
+ QStringLiteral("Enable Debug mode"));
+ parser.addOption(debugOption);
+
+ QCommandLineOption versionOption(QStringList() << "v" << "version",
+ QStringLiteral("MQTT protocol version.\n3: MQTT 3.1\n4: MQTT 3.1.1"),
+ "version", "3");
+ parser.addOption(versionOption);
+
+ parser.process(a.arguments());
+
+ const QString debugLog = QString::fromLatin1("qtdemo.websocket.mqtt*=%1").arg(
+ parser.isSet(debugOption) ? "true" : "false");
+ QLoggingCategory::setFilterRules(debugLog);
+
+ ClientSubscription clientsub;
+ clientsub.setUrl(QUrl(parser.value(urlOption)));
+ clientsub.setTopic(parser.value(subscriptionOption));
+
+ const QString versionString = parser.value(versionOption);
+
+ if (versionString == "4") {
+ clientsub.setVersion(4);
+ } else if (versionString == "3") {
+ clientsub.setVersion(3);
+ } else {
+ qWarning() << "Unknown MQTT version";
+ return -2;
+ }
+
+ clientsub.connectAndSubscribe();
+ return a.exec();
+}
diff --git a/examples/mqtt/websocketsubscription/websocketiodevice.cpp b/examples/mqtt/websocketsubscription/websocketiodevice.cpp
new file mode 100644
index 0000000..a953ddd
--- /dev/null
+++ b/examples/mqtt/websocketsubscription/websocketiodevice.cpp
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "websocketiodevice.h"
+
+#include <QtCore/QDebug>
+
+WebSocketIODevice::WebSocketIODevice(QObject *parent)
+ : QIODevice(parent)
+{
+ connect(&m_socket, &QWebSocket::connected, this, &WebSocketIODevice::onSocketConnected);
+ connect(&m_socket, &QWebSocket::binaryMessageReceived, this, &WebSocketIODevice::handleBinaryMessage);
+}
+
+bool WebSocketIODevice::open(QIODevice::OpenMode mode)
+{
+ // Cannot use an URL because of missing sub protocol support
+ // Have to use QNetworkRequest, see QTBUG-38742
+ QNetworkRequest request;
+ request.setUrl(m_url);
+ request.setRawHeader("Sec-WebSocket-Protocol", m_protocol.constData());
+
+ m_socket.open(request);
+
+ return QIODevice::open(mode);
+}
+
+void WebSocketIODevice::close()
+{
+ m_socket.close();
+ QIODevice::close();
+}
+
+qint64 WebSocketIODevice::readData(char *data, qint64 maxlen)
+{
+ qint64 bytesToRead = qMin(maxlen, (qint64)m_buffer.size());
+ memcpy(data, m_buffer.constData(), bytesToRead);
+ m_buffer = m_buffer.right(m_buffer.size() - bytesToRead);
+ return bytesToRead;
+}
+
+qint64 WebSocketIODevice::writeData(const char *data, qint64 len)
+{
+ QByteArray msg(data, len);
+ const int length = m_socket.sendBinaryMessage(msg);
+ return length;
+}
+
+void WebSocketIODevice::setUrl(const QUrl &url)
+{
+ m_url = url;
+}
+
+void WebSocketIODevice::setProtocol(const QByteArray &data)
+{
+ m_protocol = data;
+}
+
+void WebSocketIODevice::handleBinaryMessage(const QByteArray &msg)
+{
+ m_buffer.append(msg);
+ emit readyRead();
+}
+
+void WebSocketIODevice::onSocketConnected()
+{
+ emit socketConnected();
+}
diff --git a/examples/mqtt/websocketsubscription/websocketiodevice.h b/examples/mqtt/websocketsubscription/websocketiodevice.h
new file mode 100644
index 0000000..23cb746
--- /dev/null
+++ b/examples/mqtt/websocketsubscription/websocketiodevice.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef WEBSOCKETIODEVICE_H
+#define WEBSOCKETIODEVICE_H
+
+#include <QtCore/QIODevice>
+#include <QtWebSockets/QWebSocket>
+
+class WebSocketIODevice : public QIODevice
+{
+ Q_OBJECT
+public:
+ WebSocketIODevice(QObject *parent = nullptr);
+
+ bool open(OpenMode mode) override;
+ void close() override;
+
+ qint64 readData(char *data, qint64 maxlen) override;
+ qint64 writeData(const char *data, qint64 len) override;
+
+ void setUrl(const QUrl &url);
+ void setProtocol(const QByteArray &data);
+Q_SIGNALS:
+ void socketConnected();
+
+public slots:
+ void handleBinaryMessage(const QByteArray &msg);
+ void onSocketConnected();
+
+private:
+ QByteArray m_protocol;
+ QByteArray m_buffer;
+ QWebSocket m_socket;
+ QUrl m_url;
+};
+
+#endif // WEBSOCKETIODEVICE_H
diff --git a/examples/mqtt/websocketsubscription/websocketsubscription.pro b/examples/mqtt/websocketsubscription/websocketsubscription.pro
new file mode 100644
index 0000000..0e9af83
--- /dev/null
+++ b/examples/mqtt/websocketsubscription/websocketsubscription.pro
@@ -0,0 +1,32 @@
+QT += core websockets mqtt
+QT -= gui
+
+CONFIG += c++11
+
+TARGET = websocketsubscription
+CONFIG += console
+CONFIG -= app_bundle
+
+TEMPLATE = app
+
+SOURCES += main.cpp \
+ clientsubscription.cpp \
+ websocketiodevice.cpp
+
+# The following define makes your compiler emit warnings if you use
+# any feature of Qt which as been marked 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
+
+target.path = $$[QT_INSTALL_EXAMPLES]/mqtt/websocketsubscription
+INSTALLS += target
+
+HEADERS += \
+ clientsubscription.h \
+ websocketiodevice.h