diff options
Diffstat (limited to 'src')
18 files changed, 186 insertions, 603 deletions
diff --git a/src/imports/webchannel/plugin.cpp b/src/imports/webchannel/plugin.cpp index 589e3cb..6507112 100644 --- a/src/imports/webchannel/plugin.cpp +++ b/src/imports/webchannel/plugin.cpp @@ -43,11 +43,6 @@ #include <QtQml/QQmlExtensionPlugin> #include "qmlwebchannel.h" -#include "qwebsockettransport.h" -#include "qmlwebviewtransport.h" -#include "qwebchanneltransportinterface.h" - -QML_DECLARE_INTERFACE_HASMETATYPE(QWebChannelTransportInterface); QT_BEGIN_NAMESPACE @@ -62,13 +57,9 @@ 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/plugins.qmltypes b/src/imports/webchannel/plugins.qmltypes index 6d08f9c..789f2b4 100644 --- a/src/imports/webchannel/plugins.qmltypes +++ b/src/imports/webchannel/plugins.qmltypes @@ -4,95 +4,65 @@ import QtQuick.tooling 1.1 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -notrelocatable QtWebChannel 5.3' +// 'qmlplugindump -notrelocatable QtWebChannel 1.0' Module { Component { - name: "QMetaObjectPublisher" + name: "QWebChannel" prototype: "QObject" - exports: ["QtWebChannel/MetaObjectPublisher 5.3"] - exportMetaObjectRevisions: [0] - Property { name: "webChannel"; type: "QWebChannel"; isPointer: true } Property { name: "blockUpdates"; type: "bool" } Signal { - name: "webChannelChanged" - Parameter { name: "channel"; type: "QWebChannel"; isPointer: true } - } - Signal { name: "blockUpdatesChanged" Parameter { name: "block"; type: "bool" } } Method { - name: "classInfoForObjects" - type: "QVariantMap" - Parameter { name: "objects"; type: "QVariantMap" } - } - Method { - name: "classInfoForObject" - type: "QVariantMap" - Parameter { name: "object"; type: "QObject"; isPointer: true } + name: "sendMessage" + Parameter { name: "id"; type: "QJsonValue" } + Parameter { name: "data"; type: "QJsonValue" } } Method { - name: "registerObjects" - Parameter { name: "objects"; type: "QVariantMap" } + name: "sendMessage" + Parameter { name: "id"; type: "QJsonValue" } } Method { - name: "handleRequest" - type: "bool" - Parameter { name: "message"; type: "QJsonObject" } + name: "registerObject" + Parameter { name: "id"; type: "string" } + Parameter { name: "object"; type: "QObject"; isPointer: true } } - Method { name: "bench_ensureUpdatesInitialized" } - Method { name: "bench_sendPendingPropertyUpdates" } Method { - name: "bench_registerObjects" - Parameter { name: "objects"; type: "QVariantMap" } + name: "deregisterObject" + Parameter { name: "object"; type: "QObject"; isPointer: true } } - Method { name: "bench_initializeClients" } - Method { name: "test_clientIsIdle"; type: "bool" } } Component { - name: "QWebChannel" - prototype: "QObject" - exports: ["QtWebChannel/WebChannel 5.3"] + name: "QmlWebChannel" + prototype: "QWebChannel" + exports: ["QtWebChannel/WebChannel 1.0"] exportMetaObjectRevisions: [0] - Property { name: "baseUrl"; type: "string"; isReadonly: true } - Property { name: "useSecret"; type: "bool" } - Signal { - name: "baseUrlChanged" - Parameter { name: "baseUrl"; type: "string" } - } - Signal { - name: "rawMessageReceived" - Parameter { name: "rawMessage"; type: "string" } - } - Signal { name: "pongReceived" } - Signal { name: "initialized" } - Signal { - name: "failed" - Parameter { name: "reason"; type: "string" } - } + attachedType: "QmlWebChannelAttached" + Property { name: "transports"; type: "QObject"; isList: true; isReadonly: true } + Property { name: "registeredObjects"; type: "QObject"; isList: true; isReadonly: true } Method { - name: "sendMessage" - Parameter { name: "id"; type: "QJsonValue" } - Parameter { name: "data"; type: "QJsonValue" } - } - Method { - name: "sendMessage" - Parameter { name: "id"; type: "QJsonValue" } + name: "registerObjects" + Parameter { name: "objects"; type: "QVariantMap" } } + Method { name: "test_clientIsIdle"; type: "bool" } Method { - name: "respond" - Parameter { name: "messageId"; type: "QJsonValue" } - Parameter { name: "data"; type: "QJsonValue" } + name: "connectTo" + Parameter { name: "transport"; type: "QObject"; isPointer: true } } Method { - name: "respond" - Parameter { name: "messageId"; type: "QJsonValue" } + name: "disconnectFrom" + Parameter { name: "transport"; type: "QObject"; isPointer: true } } - Method { - name: "sendRawMessage" - Parameter { name: "rawMessage"; type: "string" } + } + Component { + name: "QmlWebChannelAttached" + prototype: "QObject" + Property { name: "id"; type: "string" } + Signal { + name: "idChanged" + Parameter { name: "id"; type: "string" } } - Method { name: "ping" } } } diff --git a/src/imports/webchannel/qmlwebchannel.cpp b/src/imports/webchannel/qmlwebchannel.cpp index dc7398d..e61e9c8 100644 --- a/src/imports/webchannel/qmlwebchannel.cpp +++ b/src/imports/webchannel/qmlwebchannel.cpp @@ -43,6 +43,7 @@ #include "qwebchannel_p.h" #include "qmetaobjectpublisher_p.h" +#include "qwebchannelabstracttransport.h" #include <QtQml/QQmlContext> @@ -100,32 +101,19 @@ QmlWebChannelAttached *QmlWebChannel::qmlAttachedProperties(QObject *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); + if (QWebChannelAbstractTransport *realTransport = qobject_cast<QWebChannelAbstractTransport*>(transport)) { + QWebChannel::connectTo(realTransport); } else { - qWarning() << "Cannot connect to transport" << transport << " - it does not implement the QWebChannelTransportInterface."; + qWarning() << "Cannot connect to transport" << transport << " - it is not a QWebChannelAbstractTransport."; } } 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); + if (QWebChannelAbstractTransport *realTransport = qobject_cast<QWebChannelAbstractTransport*>(transport)) { + QWebChannel::disconnectFrom(realTransport); } 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); + qWarning() << "Cannot disconnect from transport" << transport << " - it is not a QWebChannelAbstractTransport."; } } @@ -175,35 +163,36 @@ void QmlWebChannel::registeredObjects_clear(QQmlListProperty<QObject> *prop) return channel->m_registeredObjects.clear(); } -QQmlListProperty<QWebChannelTransportInterface> QmlWebChannel::transports() +QQmlListProperty<QObject> QmlWebChannel::transports() { - return QQmlListProperty<QWebChannelTransportInterface>(this, 0, + return QQmlListProperty<QObject>(this, 0, transports_append, transports_count, transports_at, transports_clear); } -void QmlWebChannel::transports_append(QQmlListProperty<QWebChannelTransportInterface> *prop, QWebChannelTransportInterface *transport) +void QmlWebChannel::transports_append(QQmlListProperty<QObject> *prop, QObject *transport) { - QWebChannel *channel = static_cast<QWebChannel*>(prop->object); + QmlWebChannel *channel = static_cast<QmlWebChannel*>(prop->object); channel->connectTo(transport); } -int QmlWebChannel::transports_count(QQmlListProperty<QWebChannelTransportInterface> *prop) +int QmlWebChannel::transports_count(QQmlListProperty<QObject> *prop) { return static_cast<QmlWebChannel*>(prop->object)->d->transports.size(); } -QWebChannelTransportInterface *QmlWebChannel::transports_at(QQmlListProperty<QWebChannelTransportInterface> *prop, int index) +QObject *QmlWebChannel::transports_at(QQmlListProperty<QObject> *prop, int index) { - return static_cast<QmlWebChannel*>(prop->object)->d->transports.at(index); + QmlWebChannel *channel = static_cast<QmlWebChannel*>(prop->object); + return dynamic_cast<QObject*>(channel->d->transports.at(index)); } -void QmlWebChannel::transports_clear(QQmlListProperty<QWebChannelTransportInterface> *prop) +void QmlWebChannel::transports_clear(QQmlListProperty<QObject> *prop) { QWebChannel *channel = static_cast<QWebChannel*>(prop->object); - foreach (QWebChannelTransportInterface *transport, channel->d->transports) { + foreach (QWebChannelAbstractTransport *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 3610307..6bc7127 100644 --- a/src/imports/webchannel/qmlwebchannel.h +++ b/src/imports/webchannel/qmlwebchannel.h @@ -45,7 +45,6 @@ #include <qwebchannel.h> #include "qmlwebchannelattached.h" -#include "qwebchanneltransportinterface.h" #include <QVector> @@ -58,7 +57,7 @@ class QmlWebChannel : public QWebChannel { Q_OBJECT - Q_PROPERTY( QQmlListProperty<QWebChannelTransportInterface> connections READ transports ); + Q_PROPERTY( QQmlListProperty<QObject> transports READ transports ); Q_PROPERTY( QQmlListProperty<QObject> registeredObjects READ registeredObjects ) public: @@ -68,7 +67,7 @@ public: Q_INVOKABLE void registerObjects(const QVariantMap &objects); QQmlListProperty<QObject> registeredObjects(); - QQmlListProperty<QWebChannelTransportInterface> transports(); + QQmlListProperty<QObject> transports(); // TODO: remove this by replacing QML with C++ tests Q_INVOKABLE bool test_clientIsIdle() const; @@ -80,7 +79,6 @@ public: private Q_SLOTS: void objectIdChanged(const QString &newId); - void transportDestroyed(QObject *transport); private: static void registeredObjects_append(QQmlListProperty<QObject> *prop, QObject *item); @@ -88,14 +86,12 @@ 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); + static void transports_append(QQmlListProperty<QObject> *prop, QObject *item); + static int transports_count(QQmlListProperty<QObject> *prop); + static QObject *transports_at(QQmlListProperty<QObject> *prop, int index); + static void transports_clear(QQmlListProperty<QObject> *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 deleted file mode 100644 index 3d4e2ed..0000000 --- a/src/imports/webchannel/qmlwebviewtransport.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/**************************************************************************** -** -** 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, int /*clientId*/) 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, int clientId) const -{ - sendMessage(QString::fromUtf8(message), clientId); -} - -void QmlWebViewTransport::handleWebViewMessage(const QVariantMap &message) -{ - if (m_handler) { - const QString &data = message[QStringLiteral("data")].toString(); - m_handler->handleMessage(data, this, -1); - emit messageReceived(data); - } -} - -void QmlWebViewTransport::setMessageHandler(QWebChannelMessageHandlerInterface *handler) -{ - m_handler = handler; -} diff --git a/src/imports/webchannel/webchannel.pro b/src/imports/webchannel/webchannel.pro index 3042854..c1959f5 100644 --- a/src/imports/webchannel/webchannel.pro +++ b/src/imports/webchannel/webchannel.pro @@ -6,12 +6,10 @@ VPATH += ../../webchannel SOURCES += \ plugin.cpp \ qmlwebchannel.cpp \ - qmlwebchannelattached.cpp \ - qmlwebviewtransport.cpp + qmlwebchannelattached.cpp HEADERS += \ qmlwebchannel.h \ - qmlwebchannelattached.h \ - qmlwebviewtransport.h + qmlwebchannelattached.h load(qml_plugin) diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp index 2914714..096bf7b 100644 --- a/src/webchannel/qmetaobjectpublisher.cpp +++ b/src/webchannel/qmetaobjectpublisher.cpp @@ -42,6 +42,7 @@ #include "qmetaobjectpublisher_p.h" #include "qwebchannel.h" #include "qwebchannel_p.h" +#include "qwebchannelabstracttransport.h" #include <QEvent> #include <QJsonDocument> @@ -394,7 +395,7 @@ QByteArray QMetaObjectPublisher::invokeMethod(QObject *const object, const int m void QMetaObjectPublisher::signalEmitted(const QObject *object, const int signalIndex, const QVariantList &arguments) { - if (!webChannel) { + if (!webChannel || webChannel->d->transports.isEmpty()) { return; } if (!signalToPropertyMap.value(object).contains(signalIndex)) { @@ -544,15 +545,18 @@ QByteArray QMetaObjectPublisher::handleRequest(const QJsonObject &message) return QByteArray(); } -void QMetaObjectPublisher::handleMessage(const QString &message, QWebChannelTransportInterface *transport, int clientId) +void QMetaObjectPublisher::handleMessage(const QString &message) { + QWebChannelAbstractTransport *transport = qobject_cast<QWebChannelAbstractTransport*>(sender()); + Q_ASSERT(transport); + const QJsonDocument doc = QJsonDocument::fromJson(message.toUtf8()); if (!doc.isObject()) { return; } const QByteArray &response = handleRequest(doc.object()); if (!response.isEmpty()) { - transport->sendMessage(response, clientId); + transport->sendTextMessage(QString::fromUtf8(response)); } } diff --git a/src/webchannel/qmetaobjectpublisher_p.h b/src/webchannel/qmetaobjectpublisher_p.h index 49b3ed0..dda18ae 100644 --- a/src/webchannel/qmetaobjectpublisher_p.h +++ b/src/webchannel/qmetaobjectpublisher_p.h @@ -51,16 +51,14 @@ #include <QPointer> #include "qwebchannelglobal.h" -#include "qwebchanneltransportinterface.h" QT_BEGIN_NAMESPACE class QWebChannel; - -class Q_WEBCHANNEL_EXPORT QMetaObjectPublisher : public QObject, public QWebChannelMessageHandlerInterface +class Q_WEBCHANNEL_EXPORT QMetaObjectPublisher : public QObject { Q_OBJECT - Q_INTERFACES(QWebChannelMessageHandlerInterface) + public: explicit QMetaObjectPublisher(QWebChannel *webChannel); virtual ~QMetaObjectPublisher(); @@ -161,13 +159,14 @@ public: */ void setBlockUpdates(bool block); +Q_SIGNALS: + void blockUpdatesChanged(bool block); + +public Q_SLOTS: /** * Parse the message as JSON and if it succeeds, call handleRequest with the obtained JSON object. */ - void handleMessage(const QString &message, QWebChannelTransportInterface* transport, int clientId) Q_DECL_OVERRIDE; - -Q_SIGNALS: - void blockUpdatesChanged(bool block); + void handleMessage(const QString &message); protected: void timerEvent(QTimerEvent *) Q_DECL_OVERRIDE; diff --git a/src/webchannel/qwebchannel.cpp b/src/webchannel/qwebchannel.cpp index 75d1a4b..e4cf0d6 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 "qwebchanneltransportinterface.h" +#include "qwebchannelabstracttransport.h" #include <QJsonDocument> #include <QJsonObject> @@ -64,6 +64,14 @@ QByteArray generateJSONMessage(const QJsonValue &id, const QJsonValue &data, boo return doc.toJson(QJsonDocument::Compact); } +void QWebChannelPrivate::_q_transportDestroyed(QObject *object) +{ + const int idx = transports.indexOf(static_cast<QWebChannelAbstractTransport*>(object)); + if (idx != -1) { + transports.remove(idx); + } +} + QWebChannel::QWebChannel(QObject *parent) : QObject(parent) , d(new QWebChannelPrivate) @@ -75,9 +83,6 @@ QWebChannel::QWebChannel(QObject *parent) QWebChannel::~QWebChannel() { - foreach (QWebChannelTransportInterface *transport, d->transports) { - transport->setMessageHandler(Q_NULLPTR); - } } void QWebChannel::registerObjects(const QHash< QString, QObject * > &objects) @@ -109,20 +114,24 @@ void QWebChannel::setBlockUpdates(bool block) d->publisher->setBlockUpdates(block); } -void QWebChannel::connectTo(QWebChannelTransportInterface *transport) +void QWebChannel::connectTo(QWebChannelAbstractTransport *transport) { Q_ASSERT(transport); if (!d->transports.contains(transport)) { d->transports << transport; - transport->setMessageHandler(d->publisher); + connect(transport, &QWebChannelAbstractTransport::textMessageReceived, + d->publisher, &QMetaObjectPublisher::handleMessage, + Qt::UniqueConnection); + connect(transport, SIGNAL(destroyed(QObject*)), + this, SLOT(_q_transportDestroyed(QObject*))); } } -void QWebChannel::disconnectFrom(QWebChannelTransportInterface *transport) +void QWebChannel::disconnectFrom(QWebChannelAbstractTransport *transport) { const int idx = d->transports.indexOf(transport); if (idx != -1) { - transport->setMessageHandler(Q_NULLPTR); + disconnect(transport, 0, this, 0); d->transports.remove(idx); } } @@ -135,9 +144,12 @@ void QWebChannel::sendMessage(const QJsonValue &id, const QJsonValue &data) cons } const QByteArray &message = generateJSONMessage(id, data, false); - foreach (QWebChannelTransportInterface *transport, d->transports) { - transport->sendMessage(message); + const QString &messageText = QString::fromUtf8(message); + foreach (QWebChannelAbstractTransport *transport, d->transports) { + transport->sendTextMessage(messageText); } } QT_END_NAMESPACE + +#include "moc_qwebchannel.cpp" diff --git a/src/webchannel/qwebchannel.h b/src/webchannel/qwebchannel.h index 76e77b8..5016b52 100644 --- a/src/webchannel/qwebchannel.h +++ b/src/webchannel/qwebchannel.h @@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE struct QWebChannelPrivate; -class QWebChannelTransportInterface; +class QWebChannelAbstractTransport; class Q_WEBCHANNEL_EXPORT QWebChannel : public QObject { @@ -89,8 +89,8 @@ public: */ void setBlockUpdates(bool block); - void connectTo(QWebChannelTransportInterface *transport); - void disconnectFrom(QWebChannelTransportInterface *transport); + void connectTo(QWebChannelAbstractTransport *transport); + void disconnectFrom(QWebChannelAbstractTransport *transport); Q_SIGNALS: void blockUpdatesChanged(bool block); @@ -100,6 +100,8 @@ public Q_SLOTS: private: QScopedPointer<QWebChannelPrivate> d; + Q_PRIVATE_SLOT(d, void _q_transportDestroyed(QObject*)); + friend class QMetaObjectPublisher; friend class QmlWebChannel; friend class TestWebChannel; }; diff --git a/src/webchannel/qwebchannel.js b/src/webchannel/qwebchannel.js index 278f423..291c10b 100644 --- a/src/webchannel/qwebchannel.js +++ b/src/webchannel/qwebchannel.js @@ -102,10 +102,8 @@ var QWebChannel = function(baseUrlOrSocket, initCallback, rawChannel) this.socket.onmessage = this.messageReceived setTimeout(this.initialized, 0); } else { - ///TODO: use ssl? - var socketUrl = "ws://" + baseUrlOrSocket; ///TODO: use QWebChannel protocol, once custom protcols are supported by QtWebSocket - this.socket = new WebSocket(socketUrl /*, "QWebChannel" */); + this.socket = new WebSocket(baseUrlOrSocket/*, "QWebChannel" */); this.socket.onopen = this.initialized this.socket.onclose = function() @@ -147,7 +145,7 @@ var QWebChannel = function(baseUrlOrSocket, initCallback, rawChannel) channel.send({"id": id, "data": data}); }; - this.objectMap = {}; + this.objects = {}; this.initMetaObjectPublisher = function(doneCallback) { @@ -157,7 +155,7 @@ var QWebChannel = function(baseUrlOrSocket, initCallback, rawChannel) channel.subscribe( QWebChannelMessageTypes.signal, function(payload) { - var object = window[payload.object] || channel.objectMap[payload.object]; + var object = channel.objects[payload.object]; if (object) { object.signalEmitted(payload.signal, payload.args); } else { @@ -171,7 +169,7 @@ var QWebChannel = function(baseUrlOrSocket, initCallback, rawChannel) function(payload) { for (var i in payload) { var data = payload[i]; - var object = window[data.object] || channel.objectMap[data.object]; + var object = channel.objects[data.object]; if (object) { object.propertyUpdate(data.signals, data.properties); } else { @@ -192,7 +190,6 @@ var QWebChannel = function(baseUrlOrSocket, initCallback, rawChannel) for (var objectName in payload) { var data = payload[objectName]; var object = new QObject(objectName, data, channel); - window[objectName] = object; } if (doneCallback) { doneCallback(channel); @@ -213,7 +210,7 @@ var QWebChannel = function(baseUrlOrSocket, initCallback, rawChannel) function QObject(name, data, webChannel) { this.__id__ = name; - webChannel.objectMap[name] = this; + webChannel.objects[name] = this; // List of callbacks that get invoked upon signal emission this.__objectSignals__ = {}; @@ -233,18 +230,23 @@ function QObject(name, data, webChannel) return response; } var objectId = response.id; - if (webChannel.objectMap[objectId]) - return webChannel.objectMap[objectId]; + if (webChannel.objects[objectId]) + return webChannel.objects[objectId]; var qObject = new QObject( objectId, response.data, webChannel ); qObject.destroyed.connect(function() { - if (webChannel.objectMap[objectId] === qObject) { - delete webChannel.objectMap[objectId]; + if (webChannel.objects[objectId] === qObject) { + delete webChannel.objects[objectId]; // reset the now deleted QObject to an empty {} object // just assigning {} though would not have the desired effect, but the // below also ensures all external references will see the empty map - for (var prop in qObject) { - delete qObject[prop]; + // NOTE: this detour is necessary to workaround QTBUG-40021 + var propertyNames = []; + for (var propertyName in qObject) { + propertyNames.push(propertyName); + } + for (var idx in propertyNames) { + delete qObject[propertyNames[idx]]; } } }); diff --git a/src/webchannel/qwebchannel_p.h b/src/webchannel/qwebchannel_p.h index b81640e..fbdf2ef 100644 --- a/src/webchannel/qwebchannel_p.h +++ b/src/webchannel/qwebchannel_p.h @@ -43,22 +43,23 @@ #define QWEBCHANNEL_P_H #include "qwebchannelglobal.h" -#include "qwebchanneltransportinterface.h" #include <QVector> QT_BEGIN_NAMESPACE class QJsonValue; -class QWebChannelTransportInterface; +class QWebChannelAbstractTransport; class QMetaObjectPublisher; Q_WEBCHANNEL_EXPORT QByteArray generateJSONMessage(const QJsonValue &id, const QJsonValue &data, bool response); struct Q_WEBCHANNEL_EXPORT QWebChannelPrivate { - QVector<QWebChannelTransportInterface*> transports; + QVector<QWebChannelAbstractTransport*> transports; QMetaObjectPublisher *publisher; + + void _q_transportDestroyed(QObject* object); }; QT_END_NAMESPACE diff --git a/src/webchannel/qwebchanneltransportinterface.h b/src/webchannel/qwebchannelabstracttransport.cpp index c532732..86c3121 100644 --- a/src/webchannel/qwebchanneltransportinterface.h +++ b/src/webchannel/qwebchannelabstracttransport.cpp @@ -39,56 +39,20 @@ ** ****************************************************************************/ -#ifndef QWEBCHANNELTRANSPORTINTERFACE_H -#define QWEBCHANNELTRANSPORTINTERFACE_H - -#include <QObject> - -#include <QtWebChannel/qwebchannelglobal.h> +#include "qwebchannelabstracttransport.h" QT_BEGIN_NAMESPACE -class QWebChannelTransportInterface; -class Q_WEBCHANNEL_EXPORT QWebChannelMessageHandlerInterface +QWebChannelAbstractTransport::QWebChannelAbstractTransport(QObject *parent) +: QObject(parent) { -public: - virtual ~QWebChannelMessageHandlerInterface() {} - - /** - * Handle a text message from a web channel client. - */ - virtual void handleMessage(const QString &message, QWebChannelTransportInterface* transport, int clientId) = 0; -}; -#define QWebChannelMessageHandlerInterface_iid "org.qt-project.Qt.QWebChannelMessageHandlerInterface" -Q_DECLARE_INTERFACE(QWebChannelMessageHandlerInterface, QWebChannelMessageHandlerInterface_iid); -Q_DECLARE_METATYPE(QWebChannelMessageHandlerInterface*) +} -class Q_WEBCHANNEL_EXPORT QWebChannelTransportInterface +QWebChannelAbstractTransport::~QWebChannelAbstractTransport() { -public: - virtual ~QWebChannelTransportInterface() {} - /** - * Send a text message to all web channel clients. - */ - virtual void sendMessage(const QString &message, int clientId = -1) const = 0; +} - /** - * Send a binary message to all web channel clients. - */ - virtual void sendMessage(const QByteArray &message, int clientId = -1) 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/qwebsockettransport_p.h b/src/webchannel/qwebchannelabstracttransport.h index b9bd9b0..c90f4b1 100644 --- a/src/webchannel/qwebsockettransport_p.h +++ b/src/webchannel/qwebchannelabstracttransport.h @@ -39,51 +39,34 @@ ** ****************************************************************************/ -#ifndef QWEBCHANNELSOCKET_P_H -#define QWEBCHANNELSOCKET_P_H +#ifndef QWEBCHANNELABSTRACTTRANSPORT_H +#define QWEBCHANNELABSTRACTTRANSPORT_H -#include <QtWebSockets/QWebSocketServer> - -#include "qwebchanneltransportinterface.h" +#include <QObject> +#include <qwebchannelglobal.h> QT_BEGIN_NAMESPACE -class QWebSocketTransport; -class QWebSocketTransportPrivate : public QWebSocketServer +class Q_WEBCHANNEL_EXPORT QWebChannelAbstractTransport : public QObject { Q_OBJECT public: - QString m_secret; - QString m_baseUrl; - QWebChannelMessageHandlerInterface *m_messageHandler; - QWebSocketTransport *m_transport; - - bool m_useSecret; - bool m_starting; - - explicit QWebSocketTransportPrivate(QWebSocketTransport* transport, QObject *parent = 0); - virtual ~QWebSocketTransportPrivate(); + explicit QWebChannelAbstractTransport(QObject *parent = 0); + virtual ~QWebChannelAbstractTransport(); - void initLater(); - void sendMessage(const QString &message, int clientId); +public Q_SLOTS: + /** + * Send a text @p message to the remote client. + */ + virtual void sendTextMessage(const QString &message) = 0; Q_SIGNALS: - void failed(const QString &reason); - void initialized(); - void baseUrlChanged(const QString &baseUrl); - void textDataReceived(const QString &message); - -private Q_SLOTS: - void validateNewConnection(); - void init(); - void socketError(); - void messageReceived(const QString &message); - void clientDisconnected(); - -private: - QVector<QWebSocket*> m_clients; + /** + * Emitted when a new text message was received from the remote client. + */ + void textMessageReceived(const QString &message); }; QT_END_NAMESPACE -#endif // QWEBCHANNELSOCKET_P_H +#endif // QWEBCHANNELABSTRACTTRANSPORT_H diff --git a/src/webchannel/qwebsockettransport.h b/src/webchannel/qwebchannelwebsockettransport.cpp index b3e484f..59c9538 100644 --- a/src/webchannel/qwebsockettransport.h +++ b/src/webchannel/qwebchannelwebsockettransport.cpp @@ -39,43 +39,41 @@ ** ****************************************************************************/ -#ifndef QWEBSOCKETTRANSPORT_H -#define QWEBSOCKETTRANSPORT_H +#include "qwebchannelwebsockettransport.h" -#include "qwebchanneltransportinterface.h" +/*! + \inmodule QtWebChannel + \brief QWebChannelAbstractSocket implementation that uses a QWebSocket internally. + + The transport delegates all messages received over the QWebSocket over its + textMessageReceived signal. Analogously, all calls to sendTextMessage will + be send over the QWebSocket to the remote client. +*/ QT_BEGIN_NAMESPACE -class QWebSocketTransportPrivate; -class Q_WEBCHANNEL_EXPORT QWebSocketTransport : public QObject, public QWebChannelTransportInterface +struct QWebChannelWebSocketTransportPrivate { - 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, int clientId = -1) const Q_DECL_OVERRIDE; - void sendMessage(const QString &message, int clientId = -1) const Q_DECL_OVERRIDE; - void setMessageHandler(QWebChannelMessageHandlerInterface *handler) Q_DECL_OVERRIDE; + QWebSocket *socket; +}; - QString baseUrl() const; +QWebChannelWebSocketTransport::QWebChannelWebSocketTransport(QWebSocket *socket) +: QWebChannelAbstractTransport(socket) +, d(new QWebChannelWebSocketTransportPrivate) +{ + d->socket = socket; + connect(socket, &QWebSocket::textMessageReceived, + this, &QWebChannelWebSocketTransport::textMessageReceived); +} - void setUseSecret(bool); - bool useSecret() const; +QWebChannelWebSocketTransport::~QWebChannelWebSocketTransport() +{ -Q_SIGNALS: - void baseUrlChanged(const QString &baseUrl); - void failed(const QString &reason); - void initialized(); - void messageReceived(const QString &message); +} -private: - QScopedPointer<QWebSocketTransportPrivate> d; -}; +void QWebChannelWebSocketTransport::sendTextMessage(const QString &message) +{ + d->socket->sendTextMessage(message); +} QT_END_NAMESPACE - -#endif // QWEBSOCKETTRANSPORT_H diff --git a/src/imports/webchannel/qmlwebviewtransport.h b/src/webchannel/qwebchannelwebsockettransport.h index 8fbfdd9..b718b9b 100644 --- a/src/imports/webchannel/qmlwebviewtransport.h +++ b/src/webchannel/qwebchannelwebsockettransport.h @@ -39,41 +39,30 @@ ** ****************************************************************************/ -#ifndef QMLWEBVIEWTRANSPORT_H -#define QMLWEBVIEWTRANSPORT_H +#ifndef QWEBCHANNELWEBSOCKETTRANSPORT_H +#define QWEBCHANNELWEBSOCKETTRANSPORT_H -#include <qwebchanneltransportinterface.h> +#include <QObject> +#include <QtWebChannel/QWebChannelAbstractTransport> +#include <QtWebChannel/qwebchannelglobal.h> +#include <QtWebSockets/QWebSocket> QT_BEGIN_NAMESPACE -class QmlWebViewTransport : public QObject, public QWebChannelTransportInterface +struct QWebChannelWebSocketTransportPrivate; +class Q_WEBCHANNEL_EXPORT QWebChannelWebSocketTransport : public QWebChannelAbstractTransport { 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; + explicit QWebChannelWebSocketTransport(QWebSocket *socket); + virtual ~QWebChannelWebSocketTransport(); - void sendMessage(const QString &message, int clientId) const Q_DECL_OVERRIDE; - void sendMessage(const QByteArray &message, int clientId) const Q_DECL_OVERRIDE; - void setMessageHandler(QWebChannelMessageHandlerInterface *handler) Q_DECL_OVERRIDE; - - void setWebViewExperimental(QObject *webViewExperimental); - QObject *webViewExperimental() const; - -Q_SIGNALS: - void webViewChanged(QObject *webViewExperimental); - void messageReceived(const QString &message); - -private Q_SLOTS: - void handleWebViewMessage(const QVariantMap &message); + void sendTextMessage(const QString &message) Q_DECL_OVERRIDE; private: - QObject *m_webViewExperimental; - QWebChannelMessageHandlerInterface *m_handler; + QScopedPointer<QWebChannelWebSocketTransportPrivate> d; }; QT_END_NAMESPACE -#endif // QMLWEBVIEWTRANSPORT_H +#endif // QWEBCHANNELWEBSOCKETTRANSPORT_H diff --git a/src/webchannel/qwebsockettransport.cpp b/src/webchannel/qwebsockettransport.cpp deleted file mode 100644 index 8c25a9b..0000000 --- a/src/webchannel/qwebsockettransport.cpp +++ /dev/null @@ -1,212 +0,0 @@ -/**************************************************************************** -** -** 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 "qwebsockettransport_p.h" - -#include <QUuid> - -#include <QtWebSockets/QWebSocket> - -QT_USE_NAMESPACE - -//BEGIN QWebSocketTransportPrivate - -QWebSocketTransportPrivate::QWebSocketTransportPrivate(QWebSocketTransport *transport, QObject *parent) - : QWebSocketServer(QStringLiteral("QWebChannel Server"), NonSecureMode, parent) - , m_messageHandler(Q_NULLPTR) - , m_transport(transport) - , m_useSecret(true) - , m_starting(false) -{ - connect(this, SIGNAL(acceptError(QAbstractSocket::SocketError)), - SLOT(socketError())); - connect(this, SIGNAL(newConnection()), - SLOT(validateNewConnection())); -} - -QWebSocketTransportPrivate::~QWebSocketTransportPrivate() -{ - close(); - qDeleteAll(m_clients); -} - -void QWebSocketTransportPrivate::initLater() -{ - if (m_starting) - return; - metaObject()->invokeMethod(this, "init", Qt::QueuedConnection); - m_starting = true; -} - -void QWebSocketTransportPrivate::sendMessage(const QString &message, int clientId) -{ - if (clientId == -1) { - foreach (QWebSocket *client, m_clients) { - client->sendTextMessage(message); - } - } else { - m_clients.at(clientId)->sendTextMessage(message); - } -} - -void QWebSocketTransportPrivate::validateNewConnection() -{ - QWebSocket *client = nextPendingConnection(); - // FIXME: client->protocol() != QStringLiteral("QWebChannel") - // protocols are not supported in QtWebSockets yet... - if (m_useSecret && client->requestUrl().path() != m_secret) - { - client->close(QWebSocketProtocol::CloseCodeBadOperation); - client->deleteLater(); - } else { - connect(client, SIGNAL(textMessageReceived(QString)), - SLOT(messageReceived(QString))); - connect(client, SIGNAL(disconnected()), - SLOT(clientDisconnected())); - m_clients << client; - } -} - -void QWebSocketTransportPrivate::init() -{ - close(); - - m_starting = false; - if (m_useSecret) { - m_secret = QUuid::createUuid().toString(); - // replace { by / - m_secret[0] = QLatin1Char('/'); - // chop of trailing } - m_secret.chop(1); - } - - if (!listen(QHostAddress::LocalHost)) { - emit failed(errorString()); - return; - } - - m_baseUrl = QStringLiteral("127.0.0.1:%1%2").arg(serverPort()).arg(m_secret); - emit initialized(); - emit baseUrlChanged(m_baseUrl); -} - -void QWebSocketTransportPrivate::socketError() -{ - emit failed(errorString()); -} - -void QWebSocketTransportPrivate::messageReceived(const QString &message) -{ - if (m_messageHandler) { - QWebSocket *client = qobject_cast<QWebSocket*>(sender()); - m_messageHandler->handleMessage(message, m_transport, m_clients.indexOf(client)); - } - emit textDataReceived(message); -} - -void QWebSocketTransportPrivate::clientDisconnected() -{ - QWebSocket *client = qobject_cast<QWebSocket*>(sender()); - if (!client) { - return; - } - const int idx = m_clients.indexOf(client); - Q_ASSERT(idx != -1); - m_clients.remove(idx); - client->deleteLater(); -} - -//END QWebSocketTransportPrivate - -QWebSocketTransport::QWebSocketTransport(QObject *parent) - : QObject(parent) - , d(new QWebSocketTransportPrivate(this)) -{ - 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, int clientId) const -{ - d->sendMessage(QString::fromUtf8(message), clientId); -} - -void QWebSocketTransport::sendMessage(const QString &message, int clientId) const -{ - d->sendMessage(message, clientId); -} - -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; -} diff --git a/src/webchannel/webchannel.pro b/src/webchannel/webchannel.pro index c6e6d69..a50beaa 100644 --- a/src/webchannel/webchannel.pro +++ b/src/webchannel/webchannel.pro @@ -12,20 +12,20 @@ OTHER_FILES = \ PUBLIC_HEADERS += \ qwebchannel.h \ - qwebchanneltransport.h \ - qwebsockettransport.h + qwebchannelabstracttransport.h \ + qwebchannelwebsockettransport.h PRIVATE_HEADERS += \ qwebchannel_p.h \ qmetaobjectpublisher_p.h \ - qwebsockettransport_p.h \ variantargument_p.h \ signalhandler_p.h SOURCES += \ qwebchannel.cpp \ qmetaobjectpublisher.cpp \ - qwebsockettransport.cpp + qwebchannelabstracttransport.cpp \ + qwebchannelwebsockettransport.cpp qtHaveModule(qml) { QT += qml |