summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMilian Wolff <milian.wolff@kdab.com>2014-01-10 14:21:05 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-02-06 16:32:20 +0100
commit54f66cc7a1e17155e90a1d3b5c33f627dbd0d50f (patch)
tree6dd4b35eda74487977bfae5bb0b81a133dfc1bf4 /src
parent05bafd509ca302fc63465fece7cd0c33ec602e31 (diff)
downloadqtwebchannel-54f66cc7a1e17155e90a1d3b5c33f627dbd0d50f.tar.gz
Make the underlying transport mechanism of the webchannel pluggable.
This enables us to optionally use navigator.qt instead of a WebSocket, which is nicer setup-wise and is also slightly faster: navigator.qt: 284.0 msecs per iteration (total: 2,840, iterations: 10) WebSocket: 295.8 msecs per iteration (total: 2,959, iterations: 10) The baseline is ca. 203 msecs, which would mean a performance boost of ca. 12.7%. Furthermore, this sets the fundation to eventually add a WebEngine transport mechanism. The WebViewTransport should also be removed and instead the WebView itself should directly implement the WebChannelTransportInterface. Change-Id: I368bb27e38ffa2f17ffeb7f5ae695690f6f5ad21 Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Diffstat (limited to 'src')
-rw-r--r--src/imports/webchannel/plugin.cpp10
-rw-r--r--src/imports/webchannel/qmlwebchannel.cpp66
-rw-r--r--src/imports/webchannel/qmlwebchannel.h18
-rw-r--r--src/imports/webchannel/qmlwebviewtransport.cpp103
-rw-r--r--src/imports/webchannel/qmlwebviewtransport.h79
-rw-r--r--src/imports/webchannel/webchannel.pro6
-rw-r--r--src/webchannel/qmetaobjectpublisher.cpp2
-rw-r--r--src/webchannel/qmetaobjectpublisher_p.h17
-rw-r--r--src/webchannel/qwebchannel.cpp75
-rw-r--r--src/webchannel/qwebchannel.h21
-rw-r--r--src/webchannel/qwebchannel.js63
-rw-r--r--src/webchannel/qwebchannel_p.h7
-rw-r--r--src/webchannel/qwebchannelsocket.cpp10
-rw-r--r--src/webchannel/qwebchannelsocket_p.h5
-rw-r--r--src/webchannel/qwebchanneltransportinterface.h93
-rw-r--r--src/webchannel/qwebsocketserver.cpp3
-rw-r--r--src/webchannel/qwebsockettransport.cpp101
-rw-r--r--src/webchannel/qwebsockettransport.h81
-rw-r--r--src/webchannel/webchannel.pro7
19 files changed, 658 insertions, 109 deletions
diff --git a/src/imports/webchannel/plugin.cpp b/src/imports/webchannel/plugin.cpp
index 92aac79..589e3cb 100644
--- a/src/imports/webchannel/plugin.cpp
+++ b/src/imports/webchannel/plugin.cpp
@@ -43,6 +43,11 @@
#include <QtQml/QQmlExtensionPlugin>
#include "qmlwebchannel.h"
+#include "qwebsockettransport.h"
+#include "qmlwebviewtransport.h"
+#include "qwebchanneltransportinterface.h"
+
+QML_DECLARE_INTERFACE_HASMETATYPE(QWebChannelTransportInterface);
QT_BEGIN_NAMESPACE
@@ -57,10 +62,13 @@ public:
void QWebChannelPlugin::registerTypes(const char *uri)
{
+ qmlRegisterInterface<QWebChannelTransportInterface>("QWebChannelTransportInterface");
+
int major = 1;
int minor = 0;
qmlRegisterType<QmlWebChannel>(uri, major, minor, "WebChannel");
-
+ qmlRegisterType<QWebSocketTransport>(uri, major, minor, "WebSocketTransport");
+ qmlRegisterType<QmlWebViewTransport>(uri, major, minor, "WebViewTransport");
}
QT_END_NAMESPACE
diff --git a/src/imports/webchannel/qmlwebchannel.cpp b/src/imports/webchannel/qmlwebchannel.cpp
index 7c70f5c..dc7398d 100644
--- a/src/imports/webchannel/qmlwebchannel.cpp
+++ b/src/imports/webchannel/qmlwebchannel.cpp
@@ -51,7 +51,6 @@ QT_USE_NAMESPACE
QmlWebChannel::QmlWebChannel(QObject *parent)
: QWebChannel(parent)
{
-
}
QmlWebChannel::~QmlWebChannel()
@@ -99,6 +98,37 @@ QmlWebChannelAttached *QmlWebChannel::qmlAttachedProperties(QObject *obj)
return new QmlWebChannelAttached(obj);
}
+void QmlWebChannel::connectTo(QObject *transport)
+{
+ if (QWebChannelTransportInterface *iface = qobject_cast<QWebChannelTransportInterface*>(transport)) {
+ m_connectedObjects.insert(transport, iface);
+ QWebChannel::connectTo(iface);
+ connect(transport, SIGNAL(destroyed(QObject*)), SLOT(transportDestroyed(QObject*)), Qt::UniqueConnection);
+ } else {
+ qWarning() << "Cannot connect to transport" << transport << " - it does not implement the QWebChannelTransportInterface.";
+ }
+}
+
+void QmlWebChannel::disconnectFrom(QObject *transport)
+{
+ if (QWebChannelTransportInterface *iface = qobject_cast<QWebChannelTransportInterface*>(transport)) {
+ QWebChannel::disconnectFrom(iface);
+ disconnect(transport, SIGNAL(destroyed(QObject*)), this, SLOT(transportDestroyed(QObject*)));
+ m_connectedObjects.remove(transport);
+ } else {
+ qWarning() << "Cannot disconnect from transport" << transport << " - it does not implement the QWebChannelTransportInterface.";
+ }
+}
+
+void QmlWebChannel::transportDestroyed(QObject *transport)
+{
+ QWebChannelTransportInterface *iface = m_connectedObjects.take(transport);
+ const int idx = d->transports.indexOf(iface);
+ if (idx != -1) {
+ d->transports.remove(idx);
+ }
+}
+
QQmlListProperty<QObject> QmlWebChannel::registeredObjects()
{
return QQmlListProperty<QObject>(this, 0,
@@ -144,3 +174,37 @@ void QmlWebChannel::registeredObjects_clear(QQmlListProperty<QObject> *prop)
}
return channel->m_registeredObjects.clear();
}
+
+QQmlListProperty<QWebChannelTransportInterface> QmlWebChannel::transports()
+{
+ return QQmlListProperty<QWebChannelTransportInterface>(this, 0,
+ transports_append,
+ transports_count,
+ transports_at,
+ transports_clear);
+}
+
+void QmlWebChannel::transports_append(QQmlListProperty<QWebChannelTransportInterface> *prop, QWebChannelTransportInterface *transport)
+{
+ QWebChannel *channel = static_cast<QWebChannel*>(prop->object);
+ channel->connectTo(transport);
+}
+
+int QmlWebChannel::transports_count(QQmlListProperty<QWebChannelTransportInterface> *prop)
+{
+ return static_cast<QmlWebChannel*>(prop->object)->d->transports.size();
+}
+
+QWebChannelTransportInterface *QmlWebChannel::transports_at(QQmlListProperty<QWebChannelTransportInterface> *prop, int index)
+{
+ return static_cast<QmlWebChannel*>(prop->object)->d->transports.at(index);
+}
+
+void QmlWebChannel::transports_clear(QQmlListProperty<QWebChannelTransportInterface> *prop)
+{
+ QWebChannel *channel = static_cast<QWebChannel*>(prop->object);
+ foreach (QWebChannelTransportInterface *transport, channel->d->transports) {
+ channel->disconnectFrom(transport);
+ }
+ Q_ASSERT(channel->d->transports.isEmpty());
+}
diff --git a/src/imports/webchannel/qmlwebchannel.h b/src/imports/webchannel/qmlwebchannel.h
index bcbb9cf..c45796f 100644
--- a/src/imports/webchannel/qmlwebchannel.h
+++ b/src/imports/webchannel/qmlwebchannel.h
@@ -45,6 +45,7 @@
#include <qwebchannel.h>
#include "qmlwebchannelattached.h"
+#include "qwebchanneltransportinterface.h"
#include <QVector>
@@ -53,13 +54,13 @@
QT_BEGIN_NAMESPACE
-class QmlWebChannelAttached;
-
class QmlWebChannel : public QWebChannel
{
Q_OBJECT
+ Q_PROPERTY( QQmlListProperty<QWebChannelTransportInterface> connections READ transports );
Q_PROPERTY( QQmlListProperty<QObject> registeredObjects READ registeredObjects )
+
public:
QmlWebChannel(QObject *parent = 0);
virtual ~QmlWebChannel();
@@ -67,13 +68,19 @@ public:
Q_INVOKABLE void registerObjects(const QVariantMap& objects);
QQmlListProperty<QObject> registeredObjects();
+ QQmlListProperty<QWebChannelTransportInterface> transports();
+
// TODO: remove this by replacing QML with C++ tests
Q_INVOKABLE bool test_clientIsIdle() const;
static QmlWebChannelAttached* qmlAttachedProperties(QObject *obj);
+ Q_INVOKABLE void connectTo(QObject *transport);
+ Q_INVOKABLE void disconnectFrom(QObject *transport);
+
private slots:
void objectIdChanged(const QString &newId);
+ void transportDestroyed(QObject *transport);
private:
static void registeredObjects_append(QQmlListProperty<QObject> *prop, QObject* item);
@@ -81,7 +88,14 @@ private:
static QObject *registeredObjects_at(QQmlListProperty<QObject> *prop, int index);
static void registeredObjects_clear(QQmlListProperty<QObject> *prop);
+ static void transports_append(QQmlListProperty<QWebChannelTransportInterface> *prop, QWebChannelTransportInterface* item);
+ static int transports_count(QQmlListProperty<QWebChannelTransportInterface> *prop);
+ static QWebChannelTransportInterface *transports_at(QQmlListProperty<QWebChannelTransportInterface> *prop, int index);
+ static void transports_clear(QQmlListProperty<QWebChannelTransportInterface> *prop);
+
QVector<QObject*> m_registeredObjects;
+ // required as when the object is destroyed, we must still find the address of the base class somehow
+ QHash<QObject*, QWebChannelTransportInterface*> m_connectedObjects;
};
QML_DECLARE_TYPE( QmlWebChannel )
diff --git a/src/imports/webchannel/qmlwebviewtransport.cpp b/src/imports/webchannel/qmlwebviewtransport.cpp
new file mode 100644
index 0000000..7fb9d16
--- /dev/null
+++ b/src/imports/webchannel/qmlwebviewtransport.cpp
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtWebChannel module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmlwebviewtransport.h"
+
+#include <QVariantMap>
+
+QT_USE_NAMESPACE
+
+QmlWebViewTransport::QmlWebViewTransport(QObject *parent)
+ : QObject(parent)
+ , m_webViewExperimental(Q_NULLPTR)
+ , m_handler(Q_NULLPTR)
+{
+}
+
+QmlWebViewTransport::~QmlWebViewTransport()
+{
+
+}
+
+void QmlWebViewTransport::setWebViewExperimental(QObject *webViewExperimental)
+{
+ if (webViewExperimental != m_webViewExperimental) {
+ if (m_webViewExperimental) {
+ disconnect(m_webViewExperimental, 0, this, 0);
+ }
+ m_webViewExperimental = webViewExperimental;
+ connect(m_webViewExperimental, SIGNAL(messageReceived(QVariantMap)), this, SLOT(handleWebViewMessage(QVariantMap)));
+ emit webViewChanged(webViewExperimental);
+ }
+}
+
+QObject *QmlWebViewTransport::webViewExperimental() const
+{
+ return m_webViewExperimental;
+}
+
+void QmlWebViewTransport::sendMessage(const QString &message) const
+{
+ if (!m_webViewExperimental) {
+ qWarning("Cannot send message - did you forget to set the webViewExperimental property?");
+ return;
+ }
+ QMetaObject::invokeMethod(m_webViewExperimental, "postMessage", Q_ARG(QString, message));
+}
+
+void QmlWebViewTransport::sendMessage(const QByteArray &message) const
+{
+ sendMessage(QString::fromUtf8(message));
+}
+
+void QmlWebViewTransport::handleWebViewMessage(const QVariantMap &message)
+{
+ if (m_handler) {
+ const QString &data = message[QStringLiteral("data")].toString();
+ m_handler->handleMessage(data);
+ emit messageReceived(data);
+ }
+}
+
+void QmlWebViewTransport::setMessageHandler(QWebChannelMessageHandlerInterface *handler)
+{
+ m_handler = handler;
+}
diff --git a/src/imports/webchannel/qmlwebviewtransport.h b/src/imports/webchannel/qmlwebviewtransport.h
new file mode 100644
index 0000000..98dc504
--- /dev/null
+++ b/src/imports/webchannel/qmlwebviewtransport.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtWebChannel module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMLWEBVIEWTRANSPORT_H
+#define QMLWEBVIEWTRANSPORT_H
+
+#include <qwebchanneltransportinterface.h>
+
+QT_BEGIN_NAMESPACE
+
+class QmlWebViewTransport : public QObject, public QWebChannelTransportInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QWebChannelTransportInterface)
+ Q_PROPERTY(QObject *webViewExperimental READ webViewExperimental WRITE setWebViewExperimental NOTIFY webViewChanged)
+public:
+ explicit QmlWebViewTransport(QObject *parent = 0);
+ ~QmlWebViewTransport() Q_DECL_OVERRIDE;
+
+ void sendMessage(const QString &message) const Q_DECL_OVERRIDE;
+ void sendMessage(const QByteArray &message) const Q_DECL_OVERRIDE;
+ void setMessageHandler(QWebChannelMessageHandlerInterface *handler) Q_DECL_OVERRIDE;
+
+ void setWebViewExperimental(QObject *webViewExperimental);
+ QObject *webViewExperimental() const;
+
+signals:
+ void webViewChanged(QObject *webViewExperimental);
+ void messageReceived(const QString &message);
+
+private slots:
+ void handleWebViewMessage(const QVariantMap &message);
+
+private:
+ QObject *m_webViewExperimental;
+ QWebChannelMessageHandlerInterface *m_handler;
+};
+
+QT_END_NAMESPACE
+
+#endif // QMLWEBVIEWTRANSPORT_H
diff --git a/src/imports/webchannel/webchannel.pro b/src/imports/webchannel/webchannel.pro
index c1959f5..3042854 100644
--- a/src/imports/webchannel/webchannel.pro
+++ b/src/imports/webchannel/webchannel.pro
@@ -6,10 +6,12 @@ VPATH += ../../webchannel
SOURCES += \
plugin.cpp \
qmlwebchannel.cpp \
- qmlwebchannelattached.cpp
+ qmlwebchannelattached.cpp \
+ qmlwebviewtransport.cpp
HEADERS += \
qmlwebchannel.h \
- qmlwebchannelattached.h
+ qmlwebchannelattached.h \
+ qmlwebviewtransport.h
load(qml_plugin)
diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp
index bd2a22b..1ac3ad9 100644
--- a/src/webchannel/qmetaobjectpublisher.cpp
+++ b/src/webchannel/qmetaobjectpublisher.cpp
@@ -524,7 +524,7 @@ bool QMetaObjectPublisher::handleRequest(const QJsonObject &message)
return false;
}
-void QMetaObjectPublisher::handleRawMessage(const QString &message)
+void QMetaObjectPublisher::handleMessage(const QString &message)
{
const QJsonDocument doc = QJsonDocument::fromJson(message.toUtf8());
if (doc.isObject()) {
diff --git a/src/webchannel/qmetaobjectpublisher_p.h b/src/webchannel/qmetaobjectpublisher_p.h
index 3e80d24..ff077e7 100644
--- a/src/webchannel/qmetaobjectpublisher_p.h
+++ b/src/webchannel/qmetaobjectpublisher_p.h
@@ -50,16 +50,17 @@
#include <QBasicTimer>
#include <QPointer>
+#include "qwebchannelglobal.h"
+#include "qwebchanneltransportinterface.h"
+
QT_BEGIN_NAMESPACE
class QWebChannel;
-#include "qwebchannelglobal.h"
-
-class Q_WEBCHANNEL_EXPORT QMetaObjectPublisher : public QObject
+class Q_WEBCHANNEL_EXPORT QMetaObjectPublisher : public QObject, public QWebChannelMessageHandlerInterface
{
Q_OBJECT
-
+ Q_INTERFACES(QWebChannelMessageHandlerInterface)
public:
QMetaObjectPublisher(QWebChannel *webChannel);
virtual ~QMetaObjectPublisher();
@@ -160,14 +161,10 @@ public:
*/
void setBlockUpdates(bool block);
-public slots:
/**
- * Helper slot which you can connect directly to WebChannel's rawMessageReceived signal.
- *
- * This slot then tries to parse the message as JSON and if it succeeds, calls handleRequest
- * with the obtained JSON object.
+ * Parse the message as JSON and if it succeeds, call handleRequest with the obtained JSON object.
*/
- void handleRawMessage(const QString &message);
+ void handleMessage(const QString &message) Q_DECL_OVERRIDE;
signals:
void blockUpdatesChanged(bool block);
diff --git a/src/webchannel/qwebchannel.cpp b/src/webchannel/qwebchannel.cpp
index b51a056..a080aae 100644
--- a/src/webchannel/qwebchannel.cpp
+++ b/src/webchannel/qwebchannel.cpp
@@ -43,7 +43,7 @@
#include "qwebchannel.h"
#include "qwebchannel_p.h"
#include "qmetaobjectpublisher_p.h"
-#include "qwebchannelsocket_p.h"
+#include "qwebchanneltransportinterface.h"
#include <QJsonDocument>
#include <QJsonObject>
@@ -52,6 +52,11 @@ QT_BEGIN_NAMESPACE
void QWebChannelPrivate::sendJSONMessage(const QJsonValue &id, const QJsonValue &data, bool response) const
{
+ if (transports.isEmpty()) {
+ qWarning("QWebChannel is not connected to any transports, cannot send messages.");
+ return;
+ }
+
QJsonObject obj;
if (response) {
obj[QStringLiteral("response")] = true;
@@ -61,55 +66,27 @@ void QWebChannelPrivate::sendJSONMessage(const QJsonValue &id, const QJsonValue
obj[QStringLiteral("data")] = data;
}
QJsonDocument doc(obj);
- socket->sendMessage(doc.toJson(QJsonDocument::Compact));
+ const QByteArray &message = doc.toJson(QJsonDocument::Compact);
+
+ foreach (QWebChannelTransportInterface *transport, transports) {
+ transport->sendMessage(message);
+ }
}
QWebChannel::QWebChannel(QObject *parent)
: QObject(parent)
, d(new QWebChannelPrivate)
{
- d->socket = new QWebChannelSocket(this);
-
- connect(d->socket, SIGNAL(textDataReceived(QString)),
- SIGNAL(rawMessageReceived(QString)));
- connect(d->socket, SIGNAL(failed(QString)),
- SIGNAL(failed(QString)));
- connect(d->socket, SIGNAL(initialized()),
- SIGNAL(initialized()));
- connect(d->socket, SIGNAL(baseUrlChanged(QString)),
- SIGNAL(baseUrlChanged(QString)));
- connect(d->socket, SIGNAL(pongReceived()),
- SIGNAL(pongReceived()));
-
- d->socket->initLater();
-
d->publisher = new QMetaObjectPublisher(this);
connect(d->publisher, SIGNAL(blockUpdatesChanged(bool)),
SIGNAL(blockUpdatesChanged(bool)));
- connect(d->socket, SIGNAL(textDataReceived(QString)),
- d->publisher, SLOT(handleRawMessage(QString)));
}
QWebChannel::~QWebChannel()
{
-}
-
-QString QWebChannel::baseUrl() const
-{
- return d->socket->m_baseUrl;
-}
-
-void QWebChannel::setUseSecret(bool s)
-{
- if (d->socket->m_useSecret == s)
- return;
- d->socket->m_useSecret = s;
- d->socket->initLater();
-}
-
-bool QWebChannel::useSecret() const
-{
- return d->socket->m_useSecret;
+ foreach (QWebChannelTransportInterface *transport, d->transports) {
+ transport->setMessageHandler(Q_NULLPTR);
+ }
}
void QWebChannel::registerObjects(const QHash< QString, QObject * > &objects)
@@ -141,24 +118,32 @@ void QWebChannel::setBlockUpdates(bool block)
d->publisher->setBlockUpdates(block);
}
-void QWebChannel::respond(const QJsonValue& messageId, const QJsonValue& data) const
+void QWebChannel::connectTo(QWebChannelTransportInterface *transport)
{
- d->sendJSONMessage(messageId, data, true);
+ Q_ASSERT(transport);
+ if (!d->transports.contains(transport)) {
+ d->transports << transport;
+ transport->setMessageHandler(d->publisher);
+ }
}
-void QWebChannel::sendMessage(const QJsonValue& id, const QJsonValue& data) const
+void QWebChannel::disconnectFrom(QWebChannelTransportInterface *transport)
{
- d->sendJSONMessage(id, data, false);
+ const int idx = d->transports.indexOf(transport);
+ if (idx != -1) {
+ transport->setMessageHandler(Q_NULLPTR);
+ d->transports.remove(idx);
+ }
}
-void QWebChannel::sendRawMessage(const QString& message) const
+void QWebChannel::respond(const QJsonValue& messageId, const QJsonValue& data) const
{
- d->socket->sendMessage(message.toUtf8());
+ d->sendJSONMessage(messageId, data, true);
}
-void QWebChannel::ping() const
+void QWebChannel::sendMessage(const QJsonValue& id, const QJsonValue& data) const
{
- d->socket->ping();
+ d->sendJSONMessage(id, data, false);
}
QT_END_NAMESPACE
diff --git a/src/webchannel/qwebchannel.h b/src/webchannel/qwebchannel.h
index bf9c5fd..f6965e0 100644
--- a/src/webchannel/qwebchannel.h
+++ b/src/webchannel/qwebchannel.h
@@ -51,24 +51,17 @@
QT_BEGIN_NAMESPACE
struct QWebChannelPrivate;
+class QWebChannelTransportInterface;
class Q_WEBCHANNEL_EXPORT QWebChannel : public QObject
{
Q_OBJECT
Q_DISABLE_COPY(QWebChannel)
- Q_PROPERTY(QString baseUrl READ baseUrl NOTIFY baseUrlChanged)
- Q_PROPERTY(bool useSecret READ useSecret WRITE setUseSecret)
Q_PROPERTY(bool blockUpdates READ blockUpdates WRITE setBlockUpdates NOTIFY blockUpdatesChanged);
-
public:
QWebChannel(QObject *parent = 0);
~QWebChannel();
- QString baseUrl() const;
-
- void setUseSecret(bool);
- bool useSecret() const;
-
/**
* Register a map of string ID to QObject* objects.
*
@@ -96,21 +89,15 @@ public:
*/
void setBlockUpdates(bool block);
-signals:
- void baseUrlChanged(const QString& baseUrl);
- void rawMessageReceived(const QString& rawMessage);
- void pongReceived();
- void initialized();
-
- void failed(const QString& reason);
+ void connectTo(QWebChannelTransportInterface *transport);
+ void disconnectFrom(QWebChannelTransportInterface *transport);
+signals:
void blockUpdatesChanged(bool block);
public slots:
void sendMessage(const QJsonValue& id, const QJsonValue& data = QJsonValue()) const;
void respond(const QJsonValue& messageId, const QJsonValue& data = QJsonValue()) const;
- void sendRawMessage(const QString& rawMessage) const;
- void ping() const;
private:
QScopedPointer<QWebChannelPrivate> d;
diff --git a/src/webchannel/qwebchannel.js b/src/webchannel/qwebchannel.js
index 5ca051c..887c5a0 100644
--- a/src/webchannel/qwebchannel.js
+++ b/src/webchannel/qwebchannel.js
@@ -42,7 +42,7 @@
"use strict";
-var QWebChannel = function(baseUrl, initCallback, rawChannel)
+var QWebChannel = function(baseUrlOrSocket, initCallback, rawChannel)
{
var channel = this;
// support multiple channels listening to the same socket
@@ -52,34 +52,14 @@ var QWebChannel = function(baseUrl, initCallback, rawChannel)
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
- ///TODO: use ssl?
- var socketUrl = "ws://" + baseUrl;
- this.socket = new WebSocket(socketUrl, "QWebChannel");
this.send = function(data)
{
if (typeof(data) !== "string") {
data = JSON.stringify(data);
}
channel.socket.send(data);
- };
-
- this.socket.onopen = function()
- {
- if (rawChannel) {
- initCallback(channel);
- } else {
- channel.initMetaObjectPublisher(initCallback);
- }
- };
- this.socket.onclose = function()
- {
- console.error("web channel closed");
- };
- this.socket.onerror = function(error)
- {
- console.error("web channel error: " + error);
- };
- this.socket.onmessage = function(message)
+ }
+ this.messageReceived = function(message)
{
var jsonData = JSON.parse(message.data);
if (jsonData.id === undefined) {
@@ -99,7 +79,41 @@ var QWebChannel = function(baseUrl, initCallback, rawChannel)
(callback)(jsonData.data); }
);
}
- };
+ }
+
+ this.initialized = function()
+ {
+ if (rawChannel) {
+ initCallback(channel);
+ } else {
+ channel.initMetaObjectPublisher(initCallback);
+ }
+ }
+
+ if (typeof baseUrlOrSocket === 'object') {
+ this.socket = baseUrlOrSocket;
+ this.socket.send = function(data)
+ {
+ channel.socket.postMessage(data);
+ }
+ this.socket.onmessage = this.messageReceived
+ setTimeout(this.initialized, 0);
+ } else {
+ ///TODO: use ssl?
+ var socketUrl = "ws://" + baseUrlOrSocket;
+ this.socket = new WebSocket(socketUrl, "QWebChannel");
+
+ this.socket.onopen = this.initialized
+ this.socket.onclose = function()
+ {
+ console.error("web channel closed");
+ };
+ this.socket.onerror = function(error)
+ {
+ console.error("web channel error: " + error);
+ };
+ this.socket.onmessage = this.messageReceived
+ }
this.subscriptions = {};
this.subscribe = function(id, callback)
@@ -136,7 +150,6 @@ var QWebChannel = function(baseUrl, initCallback, rawChannel)
// prevent multiple initialization which might happen with multiple webchannel clients.
var initialized = false;
- console.log(channel);
channel.subscribe(
"Qt.signal",
function(payload) {
diff --git a/src/webchannel/qwebchannel_p.h b/src/webchannel/qwebchannel_p.h
index 63f5a0a..954134e 100644
--- a/src/webchannel/qwebchannel_p.h
+++ b/src/webchannel/qwebchannel_p.h
@@ -43,16 +43,19 @@
#define QWEBCHANNEL_P_H
#include "qwebchannelglobal.h"
+#include "qwebchanneltransportinterface.h"
+
+#include <QVector>
QT_BEGIN_NAMESPACE
class QJsonValue;
-class QWebChannelSocket;
+class QWebChannelTransportInterface;
class QMetaObjectPublisher;
struct Q_WEBCHANNEL_EXPORT QWebChannelPrivate
{
- QWebChannelSocket *socket;
+ QVector<QWebChannelTransportInterface*> transports;
QMetaObjectPublisher *publisher;
void sendJSONMessage(const QJsonValue &id, const QJsonValue &data, bool response) const;
diff --git a/src/webchannel/qwebchannelsocket.cpp b/src/webchannel/qwebchannelsocket.cpp
index 84e6685..b3daf8f 100644
--- a/src/webchannel/qwebchannelsocket.cpp
+++ b/src/webchannel/qwebchannelsocket.cpp
@@ -48,11 +48,14 @@ QT_BEGIN_NAMESPACE
QWebChannelSocket::QWebChannelSocket(QObject *parent)
: QWebSocketServer(parent)
+ , m_messageHandler(Q_NULLPTR)
, m_useSecret(true)
, m_starting(false)
{
connect(this, SIGNAL(error(QAbstractSocket::SocketError)),
SLOT(socketError()));
+ connect(this, SIGNAL(textDataReceived(QString)),
+ SLOT(messageReceived(QString)));
}
void QWebChannelSocket::initLater()
@@ -100,4 +103,11 @@ void QWebChannelSocket::socketError()
emit failed(errorString());
}
+void QWebChannelSocket::messageReceived(const QString &message)
+{
+ if (m_messageHandler) {
+ m_messageHandler->handleMessage(message);
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/webchannel/qwebchannelsocket_p.h b/src/webchannel/qwebchannelsocket_p.h
index 3f58f91..9d6cde5 100644
--- a/src/webchannel/qwebchannelsocket_p.h
+++ b/src/webchannel/qwebchannelsocket_p.h
@@ -43,6 +43,7 @@
#define QWEBCHANNELSOCKET_P_H
#include "qwebsocketserver_p.h"
+#include "qwebchanneltransportinterface.h"
QT_BEGIN_NAMESPACE
@@ -52,11 +53,12 @@ class QWebChannelSocket : public QWebSocketServer
public:
QByteArray m_secret;
QString m_baseUrl;
+ QWebChannelMessageHandlerInterface *m_messageHandler;
bool m_useSecret;
bool m_starting;
- QWebChannelSocket(QObject *parent);
+ explicit QWebChannelSocket(QObject *parent = 0);
void initLater();
@@ -71,6 +73,7 @@ protected:
private slots:
void init();
void socketError();
+ void messageReceived(const QString &message);
};
QT_END_NAMESPACE
diff --git a/src/webchannel/qwebchanneltransportinterface.h b/src/webchannel/qwebchanneltransportinterface.h
new file mode 100644
index 0000000..9044c68
--- /dev/null
+++ b/src/webchannel/qwebchanneltransportinterface.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtWebChannel module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWEBCHANNELTRANSPORTINTERFACE_H
+#define QWEBCHANNELTRANSPORTINTERFACE_H
+
+#include <QObject>
+
+#include <QtWebChannel/qwebchannelglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_WEBCHANNEL_EXPORT QWebChannelMessageHandlerInterface
+{
+public:
+ virtual ~QWebChannelMessageHandlerInterface() {}
+
+ /**
+ * Handle a text message from a web channel client.
+ */
+ virtual void handleMessage(const QString &message) = 0;
+};
+
+#define QWebChannelMessageHandlerInterface_iid "org.qt-project.Qt.QWebChannelMessageHandlerInterface"
+Q_DECLARE_INTERFACE(QWebChannelMessageHandlerInterface, QWebChannelMessageHandlerInterface_iid);
+Q_DECLARE_METATYPE(QWebChannelMessageHandlerInterface*)
+
+class Q_WEBCHANNEL_EXPORT QWebChannelTransportInterface
+{
+public:
+ virtual ~QWebChannelTransportInterface() {}
+
+ /**
+ * Send a text message to all web channel clients.
+ */
+ virtual void sendMessage(const QString &message) const = 0;
+
+ /**
+ * Send a binary message to all web channel clients.
+ */
+ virtual void sendMessage(const QByteArray &message) const = 0;
+
+ /**
+ * Sets the message handler that will be called on incoming messages from web channel clients.
+ */
+ virtual void setMessageHandler(QWebChannelMessageHandlerInterface *handler) = 0;
+};
+
+#define QWebChannelTransportInterface_iid "org.qt-project.Qt.QWebChannelTransportInterface"
+Q_DECLARE_INTERFACE(QWebChannelTransportInterface, QWebChannelTransportInterface_iid);
+Q_DECLARE_METATYPE(QWebChannelTransportInterface*)
+
+QT_END_NAMESPACE
+
+#endif // QWEBCHANNELTRANSPORTINTERFACE_H
diff --git a/src/webchannel/qwebsocketserver.cpp b/src/webchannel/qwebsocketserver.cpp
index 4404dc1..5a5b5a7 100644
--- a/src/webchannel/qwebsocketserver.cpp
+++ b/src/webchannel/qwebsocketserver.cpp
@@ -387,6 +387,9 @@ void QWebSocketServer::sendMessage(const QByteArray& message) const
void QWebSocketServer::sendFrame(Frame::Opcode opcode, const QByteArray& data) const
{
+ if (m_connections.isEmpty()) {
+ return;
+ }
const QByteArray& header = frameHeader(opcode, data.size());
QHash< QTcpSocket*, Connection >::const_iterator it = m_connections.constBegin();
while (it != m_connections.constEnd()) {
diff --git a/src/webchannel/qwebsockettransport.cpp b/src/webchannel/qwebsockettransport.cpp
new file mode 100644
index 0000000..be991a8
--- /dev/null
+++ b/src/webchannel/qwebsockettransport.cpp
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtWebChannel module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwebsockettransport.h"
+#include "qwebchannelsocket_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QWebSocketTransport::QWebSocketTransport(QObject *parent)
+ : QObject(parent)
+ , d(new QWebChannelSocket)
+{
+ connect(d.data(), SIGNAL(textDataReceived(QString)),
+ SIGNAL(messageReceived(QString)));
+ connect(d.data(), SIGNAL(failed(QString)),
+ SIGNAL(failed(QString)));
+ connect(d.data(), SIGNAL(initialized()),
+ SIGNAL(initialized()));
+ connect(d.data(), SIGNAL(baseUrlChanged(QString)),
+ SIGNAL(baseUrlChanged(QString)));
+
+ d->initLater();
+}
+
+QWebSocketTransport::~QWebSocketTransport()
+{
+
+}
+
+void QWebSocketTransport::sendMessage(const QByteArray &message) const
+{
+ d->sendMessage(message);
+}
+
+void QWebSocketTransport::sendMessage(const QString &message) const
+{
+ d->sendMessage(message.toUtf8());
+}
+
+void QWebSocketTransport::setMessageHandler(QWebChannelMessageHandlerInterface *handler)
+{
+ d->m_messageHandler = handler;
+}
+
+QString QWebSocketTransport::baseUrl() const
+{
+ return d->m_baseUrl;
+}
+
+void QWebSocketTransport::setUseSecret(bool s)
+{
+ if (d->m_useSecret == s)
+ return;
+ d->m_useSecret = s;
+ d->initLater();
+}
+
+bool QWebSocketTransport::useSecret() const
+{
+ return d->m_useSecret;
+}
+
+QT_END_NAMESPACE
diff --git a/src/webchannel/qwebsockettransport.h b/src/webchannel/qwebsockettransport.h
new file mode 100644
index 0000000..d8d164a
--- /dev/null
+++ b/src/webchannel/qwebsockettransport.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtWebChannel module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWEBSOCKETTRANSPORT_H
+#define QWEBSOCKETTRANSPORT_H
+
+#include "qwebchanneltransportinterface.h"
+
+QT_BEGIN_NAMESPACE
+
+class QWebChannelSocket;
+class Q_WEBCHANNEL_EXPORT QWebSocketTransport : public QObject, public QWebChannelTransportInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QWebChannelTransportInterface)
+ Q_PROPERTY(QString baseUrl READ baseUrl NOTIFY baseUrlChanged)
+ Q_PROPERTY(bool useSecret READ useSecret WRITE setUseSecret)
+public:
+ explicit QWebSocketTransport(QObject *parent = 0);
+ ~QWebSocketTransport() Q_DECL_OVERRIDE;
+
+ void sendMessage(const QByteArray &message) const Q_DECL_OVERRIDE;
+ void sendMessage(const QString &message) const Q_DECL_OVERRIDE;
+ void setMessageHandler(QWebChannelMessageHandlerInterface *handler) Q_DECL_OVERRIDE;
+
+ QString baseUrl() const;
+
+ void setUseSecret(bool);
+ bool useSecret() const;
+
+Q_SIGNALS:
+ void baseUrlChanged(const QString &baseUrl);
+ void failed(const QString &reason);
+ void initialized();
+ void messageReceived(const QString &message);
+
+private:
+ QScopedPointer<QWebChannelSocket> d;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWEBSOCKETTRANSPORT_H
diff --git a/src/webchannel/webchannel.pro b/src/webchannel/webchannel.pro
index 36cd686..279eb37 100644
--- a/src/webchannel/webchannel.pro
+++ b/src/webchannel/webchannel.pro
@@ -11,7 +11,9 @@ OTHER_FILES = \
qwebchannel.js
PUBLIC_HEADERS += \
- qwebchannel.h
+ qwebchannel.h \
+ qwebchanneltransport.h \
+ qwebsockettransport.h
PRIVATE_HEADERS += \
qwebchannel_p.h \
@@ -25,7 +27,8 @@ SOURCES += \
qwebchannel.cpp \
qmetaobjectpublisher.cpp \
qwebsocketserver.cpp \
- qwebchannelsocket.cpp
+ qwebchannelsocket.cpp \
+ qwebsockettransport.cpp
qtHaveModule(qml) {
QT += qml