aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/qmldebug
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2017-09-28 11:32:42 +0200
committerUlf Hermann <ulf.hermann@qt.io>2017-10-04 16:17:48 +0000
commit2f9d82791ed030e21af30e61d89b6eef672231be (patch)
tree5d56f532c48c2dcdbd5d075842e51f88c1fd7791 /src/libs/qmldebug
parent451f4a1e7321110301a8c558eafd420164ddbf96 (diff)
QmlDebug: Move QmlDebugConnection into own file
Change-Id: I761658de7c19754cfaadf8cbbad7596a9bcdfbf3 Reviewed-by: hjk <hjk@qt.io>
Diffstat (limited to 'src/libs/qmldebug')
-rw-r--r--src/libs/qmldebug/declarativetoolsclient.cpp1
-rw-r--r--src/libs/qmldebug/qmldebug-lib.pri7
-rw-r--r--src/libs/qmldebug/qmldebug.qbs2
-rw-r--r--src/libs/qmldebug/qmldebugclient.cpp395
-rw-r--r--src/libs/qmldebug/qmldebugclient.h47
-rw-r--r--src/libs/qmldebug/qmldebugconnection.cpp431
-rw-r--r--src/libs/qmldebug/qmldebugconnection.h84
-rw-r--r--src/libs/qmldebug/qmltoolsclient.cpp1
8 files changed, 527 insertions, 441 deletions
diff --git a/src/libs/qmldebug/declarativetoolsclient.cpp b/src/libs/qmldebug/declarativetoolsclient.cpp
index 29060cdea2..cf59e01358 100644
--- a/src/libs/qmldebug/declarativetoolsclient.cpp
+++ b/src/libs/qmldebug/declarativetoolsclient.cpp
@@ -24,6 +24,7 @@
****************************************************************************/
#include "declarativetoolsclient.h"
+#include "qmldebugconnection.h"
#include <QMetaEnum>
#include <QStringList>
diff --git a/src/libs/qmldebug/qmldebug-lib.pri b/src/libs/qmldebug/qmldebug-lib.pri
index fe67974606..28c269ab35 100644
--- a/src/libs/qmldebug/qmldebug-lib.pri
+++ b/src/libs/qmldebug/qmldebug-lib.pri
@@ -19,7 +19,8 @@ HEADERS += \
$$PWD/declarativetoolsclient.h \
$$PWD/qmltoolsclient.h \
$$PWD/qmlenginecontrolclient.h \
- $$PWD/qmldebugcommandlinearguments.h
+ $$PWD/qmldebugcommandlinearguments.h \
+ $$PWD/qmldebugconnection.h
SOURCES += \
$$PWD/qmldebugclient.cpp \
@@ -31,5 +32,5 @@ SOURCES += \
$$PWD/declarativetoolsclient.cpp \
$$PWD/qmltoolsclient.cpp \
$$PWD/declarativeenginedebugclient.cpp \
- $$PWD/qmlenginecontrolclient.cpp
-
+ $$PWD/qmlenginecontrolclient.cpp \
+ $$PWD/qmldebugconnection.cpp
diff --git a/src/libs/qmldebug/qmldebug.qbs b/src/libs/qmldebug/qmldebug.qbs
index b681e54579..2f5c30e163 100644
--- a/src/libs/qmldebug/qmldebug.qbs
+++ b/src/libs/qmldebug/qmldebug.qbs
@@ -27,6 +27,8 @@ Project {
"qmldebugclient.cpp",
"qmldebugclient.h",
"qmldebugcommandlinearguments.h",
+ "qmldebugconnection.cpp",
+ "qmldebugconnection.h",
"qmldebugconstants.h",
"qmlenginecontrolclient.cpp",
"qmlenginecontrolclient.h",
diff --git a/src/libs/qmldebug/qmldebugclient.cpp b/src/libs/qmldebug/qmldebugclient.cpp
index ffa21a458c..d6957bec7e 100644
--- a/src/libs/qmldebug/qmldebugclient.cpp
+++ b/src/libs/qmldebug/qmldebugclient.cpp
@@ -24,25 +24,16 @@
****************************************************************************/
#include "qmldebugclient.h"
-
+#include "qmldebugconnection.h"
#include "qpacketprotocol.h"
#include <qdebug.h>
#include <qstringlist.h>
-#include <qnetworkproxy.h>
-#include <qlocalserver.h>
-#include <qlocalsocket.h>
#include <QPointer>
namespace QmlDebug {
-const int protocolVersion = 1;
-const int minimumDataStreamVersion = QDataStream::Qt_4_7;
-
-const QString serverId = QLatin1String("QDeclarativeDebugServer");
-const QString clientId = QLatin1String("QDeclarativeDebugClient");
-
class QmlDebugClientPrivate
{
public:
@@ -52,387 +43,6 @@ public:
QPointer<QmlDebugConnection> connection;
};
-class QmlDebugConnectionPrivate
-{
-public:
- QmlDebugConnectionPrivate();
- QPacketProtocol *protocol;
- QLocalServer *server;
- QIODevice *device; // Currently a QTcpSocket or a QLocalSocket
-
- bool gotHello;
- QHash <QString, float> serverPlugins;
- QHash<QString, QmlDebugClient *> plugins;
-
- int currentDataStreamVersion;
- int maximumDataStreamVersion;
-
- void advertisePlugins();
- void flush();
-};
-
-static QString socketStateToString(QAbstractSocket::SocketState state)
-{
- QString stateString;
- QDebug(&stateString) << state;
- return QmlDebugConnection::tr("Socket state changed to %1").arg(stateString);
-}
-
-static QString socketErrorToString(QAbstractSocket::SocketError error)
-{
- QString errorString;
- QDebug(&errorString) << error;
- return QmlDebugConnection::tr("Error: %1").arg(errorString);
-}
-
-QmlDebugConnectionPrivate::QmlDebugConnectionPrivate() :
- protocol(0), server(0), device(0), gotHello(false),
- currentDataStreamVersion(minimumDataStreamVersion),
- maximumDataStreamVersion(QDataStream::Qt_DefaultCompiledVersion)
-{
-}
-
-void QmlDebugConnectionPrivate::advertisePlugins()
-{
- if (!gotHello)
- return;
-
- QPacket pack(currentDataStreamVersion);
- pack << serverId << 1 << plugins.keys();
- protocol->send(pack.data());
- flush();
-}
-
-void QmlDebugConnection::socketConnected()
-{
- Q_D(QmlDebugConnection);
- QPacket pack(d->currentDataStreamVersion);
- pack << serverId << 0 << protocolVersion << d->plugins.keys() << d->maximumDataStreamVersion
- << true; // We accept multiple messages per packet
- d->protocol->send(pack.data());
- d->flush();
-}
-
-void QmlDebugConnection::socketDisconnected()
-{
- Q_D(QmlDebugConnection);
- if (d->gotHello) {
- d->gotHello = false;
- QHash<QString, QmlDebugClient*>::iterator iter = d->plugins.begin();
- for (; iter != d->plugins.end(); ++iter)
- iter.value()->stateChanged(QmlDebugClient::NotConnected);
- emit disconnected();
- } else if (d->device) {
- emit connectionFailed();
- }
- if (d->protocol) {
- d->protocol->disconnect();
- d->protocol->deleteLater();
- d->protocol = 0;
- }
- if (d->device) {
- // Don't allow any "connected()" or "disconnected()" signals to be triggered anymore.
- // As the protocol is gone this would lead to crashes.
- d->device->disconnect();
- // Don't immediately delete it as it may do some cleanup on returning from a signal.
- d->device->deleteLater();
- d->device = 0;
- }
-}
-
-void QmlDebugConnection::protocolReadyRead()
-{
- Q_D(QmlDebugConnection);
- if (!d->gotHello) {
- QPacket pack(d->currentDataStreamVersion, d->protocol->read());
- QString name;
-
- pack >> name;
-
- bool validHello = false;
- if (name == clientId) {
- int op = -1;
- pack >> op;
- if (op == 0) {
- int version = -1;
- pack >> version;
- if (version == protocolVersion) {
- QStringList pluginNames;
- QList<float> pluginVersions;
- pack >> pluginNames;
- if (!pack.atEnd())
- pack >> pluginVersions;
-
- const int pluginNamesSize = pluginNames.size();
- const int pluginVersionsSize = pluginVersions.size();
- for (int i = 0; i < pluginNamesSize; ++i) {
- float pluginVersion = 1.0;
- if (i < pluginVersionsSize)
- pluginVersion = pluginVersions.at(i);
- d->serverPlugins.insert(pluginNames.at(i), pluginVersion);
- }
-
- if (!pack.atEnd()) {
- pack >> d->currentDataStreamVersion;
- if (d->currentDataStreamVersion > d->maximumDataStreamVersion)
- qWarning() << "Server returned invalid data stream version!";
- }
- validHello = true;
- }
- }
- }
-
- if (!validHello) {
- qWarning("QML Debug Client: Invalid hello message");
- close();
- return;
- }
- d->gotHello = true;
-
- QHash<QString, QmlDebugClient *>::Iterator iter = d->plugins.begin();
- for (; iter != d->plugins.end(); ++iter) {
- QmlDebugClient::State newState = QmlDebugClient::Unavailable;
- if (d->serverPlugins.contains(iter.key()))
- newState = QmlDebugClient::Enabled;
- iter.value()->stateChanged(newState);
- }
- emit connected();
- }
-
- while (d->protocol && d->protocol->packetsAvailable()) {
- QPacket pack(d->currentDataStreamVersion, d->protocol->read());
- QString name;
- pack >> name;
-
- if (name == clientId) {
- int op = -1;
- pack >> op;
-
- if (op == 1) {
- // Service Discovery
- QHash<QString, float> oldServerPlugins = d->serverPlugins;
- d->serverPlugins.clear();
-
- QStringList pluginNames;
- QList<float> pluginVersions;
- pack >> pluginNames;
- if (!pack.atEnd())
- pack >> pluginVersions;
-
- const int pluginNamesSize = pluginNames.size();
- const int pluginVersionsSize = pluginVersions.size();
- for (int i = 0; i < pluginNamesSize; ++i) {
- float pluginVersion = 1.0;
- if (i < pluginVersionsSize)
- pluginVersion = pluginVersions.at(i);
- d->serverPlugins.insert(pluginNames.at(i), pluginVersion);
- }
-
- QHash<QString, QmlDebugClient *>::Iterator iter = d->plugins.begin();
- for (; iter != d->plugins.end(); ++iter) {
- const QString pluginName = iter.key();
- QmlDebugClient::State newState = QmlDebugClient::Unavailable;
- if (d->serverPlugins.contains(pluginName))
- newState = QmlDebugClient::Enabled;
-
- if (oldServerPlugins.contains(pluginName)
- != d->serverPlugins.contains(pluginName)) {
- iter.value()->stateChanged(newState);
- }
- }
- } else {
- qWarning() << "QML Debug Client: Unknown control message id" << op;
- }
- } else {
- QHash<QString, QmlDebugClient *>::Iterator iter = d->plugins.find(name);
- if (iter == d->plugins.end()) {
- qWarning() << "QML Debug Client: Message received for missing plugin" << name;
- } else {
- QmlDebugClient *client = *iter;
- QByteArray message;
- while (!pack.atEnd()) {
- pack >> message;
- client->messageReceived(message);
- }
- }
- }
- }
-}
-
-QmlDebugConnection::QmlDebugConnection(QObject *parent)
- : QObject(parent), d_ptr(new QmlDebugConnectionPrivate)
-{
-}
-
-QmlDebugConnection::~QmlDebugConnection()
-{
- socketDisconnected();
-}
-
-bool QmlDebugConnection::isConnected() const
-{
- Q_D(const QmlDebugConnection);
- // gotHello can only be set if the connection is open.
- return d->gotHello;
-}
-
-bool QmlDebugConnection::isConnecting() const
-{
- Q_D(const QmlDebugConnection);
- return !d->gotHello && d->device;
-}
-
-void QmlDebugConnection::close()
-{
- Q_D(QmlDebugConnection);
- if (d->device && d->device->isOpen())
- d->device->close(); // will trigger disconnected() at some point.
-}
-
-QmlDebugClient *QmlDebugConnection::client(const QString &name) const
-{
- Q_D(const QmlDebugConnection);
- return d->plugins.value(name, 0);
-}
-
-bool QmlDebugConnection::addClient(const QString &name, QmlDebugClient *client)
-{
- Q_D(QmlDebugConnection);
- if (d->plugins.contains(name))
- return false;
- d->plugins.insert(name, client);
- d->advertisePlugins();
- return true;
-}
-
-bool QmlDebugConnection::removeClient(const QString &name)
-{
- Q_D(QmlDebugConnection);
- if (!d->plugins.contains(name))
- return false;
- d->plugins.remove(name);
- d->advertisePlugins();
- return true;
-}
-
-float QmlDebugConnection::serviceVersion(const QString &serviceName) const
-{
- Q_D(const QmlDebugConnection);
- return d->serverPlugins.value(serviceName, -1);
-}
-
-bool QmlDebugConnection::sendMessage(const QString &name, const QByteArray &message)
-{
- Q_D(QmlDebugConnection);
- if (!d->gotHello || !d->serverPlugins.contains(name))
- return false;
-
- QPacket pack(d->currentDataStreamVersion);
- pack << name << message;
- d->protocol->send(pack.data());
- d->flush();
- return true;
-}
-
-void QmlDebugConnectionPrivate::flush()
-{
- if (QAbstractSocket *socket = qobject_cast<QAbstractSocket *>(device))
- socket->flush();
- else if (QLocalSocket *socket = qobject_cast<QLocalSocket *>(device))
- socket->flush();
-}
-
-void QmlDebugConnection::connectToHost(const QString &hostName, quint16 port)
-{
- Q_D(QmlDebugConnection);
- socketDisconnected();
- QTcpSocket *socket = new QTcpSocket(this);
- socket->setProxy(QNetworkProxy::NoProxy);
- d->device = socket;
- d->protocol = new QPacketProtocol(socket, this);
- QObject::connect(d->protocol, &QPacketProtocol::readyRead,
- this, &QmlDebugConnection::protocolReadyRead);
- connect(socket, &QAbstractSocket::stateChanged,
- this, [this](QAbstractSocket::SocketState state) {
- emit logStateChange(socketStateToString(state));
- });
-
- connect(socket, static_cast<void (QTcpSocket::*)(QAbstractSocket::SocketError)>
- (&QAbstractSocket::error), this, [this](QAbstractSocket::SocketError error) {
- emit logError(socketErrorToString(error));
- socketDisconnected();
- });
- connect(socket, &QAbstractSocket::connected, this, &QmlDebugConnection::socketConnected);
- connect(socket, &QAbstractSocket::disconnected, this, &QmlDebugConnection::socketDisconnected);
- socket->connectToHost(hostName.isEmpty() ? QString("localhost") : hostName, port);
-}
-
-void QmlDebugConnection::startLocalServer(const QString &fileName)
-{
- Q_D(QmlDebugConnection);
- if (d->gotHello)
- close();
- if (d->server)
- d->server->deleteLater();
- d->server = new QLocalServer(this);
- // QueuedConnection so that waitForNewConnection() returns true.
- connect(d->server, &QLocalServer::newConnection,
- this, &QmlDebugConnection::newConnection, Qt::QueuedConnection);
- if (!d->server->listen(fileName))
- emit connectionFailed();
-}
-
-void QmlDebugConnection::newConnection()
-{
- Q_D(QmlDebugConnection);
- delete d->device;
- QLocalSocket *socket = d->server->nextPendingConnection();
- d->server->close();
- d->device = socket;
- delete d->protocol;
- d->protocol = new QPacketProtocol(socket, this);
- QObject::connect(d->protocol, &QPacketProtocol::readyRead,
- this, &QmlDebugConnection::protocolReadyRead);
-
- connect(socket, &QLocalSocket::disconnected, this, &QmlDebugConnection::socketDisconnected);
-
- connect(socket, static_cast<void (QLocalSocket::*)(QLocalSocket::LocalSocketError)>
- (&QLocalSocket::error), this, [this](QLocalSocket::LocalSocketError error) {
- emit logError(socketErrorToString(static_cast<QAbstractSocket::SocketError>(error)));
- socketDisconnected();
- });
-
- connect(socket, &QLocalSocket::stateChanged,
- this, [this](QLocalSocket::LocalSocketState state) {
- logStateChange(socketStateToString(static_cast<QAbstractSocket::SocketState>(state)));
- });
-
- socketConnected();
-}
-
-int QmlDebugConnection::currentDataStreamVersion() const
-{
- Q_D(const QmlDebugConnection);
- return d->currentDataStreamVersion;
-}
-
-void QmlDebugConnection::setMaximumDataStreamVersion(int maximumVersion)
-{
- Q_D(QmlDebugConnection);
- d->maximumDataStreamVersion = maximumVersion;
-}
-
-QAbstractSocket::SocketState QmlDebugConnection::socketState() const
-{
- Q_D(const QmlDebugConnection);
- if (QAbstractSocket *socket = qobject_cast<QAbstractSocket *>(d->device))
- return socket->state();
- else if (QLocalSocket *socket = qobject_cast<QLocalSocket *>(d->device))
- return static_cast<QAbstractSocket::SocketState>(socket->state());
- else
- return QAbstractSocket::UnconnectedState;
-}
-
QmlDebugClientPrivate::QmlDebugClientPrivate()
{
}
@@ -497,7 +107,8 @@ QmlDebugConnection *QmlDebugClient::connection() const
int QmlDebugClient::dataStreamVersion() const
{
Q_D(const QmlDebugClient);
- return (d->connection ? d->connection->currentDataStreamVersion() : minimumDataStreamVersion);
+ return (d->connection ? d->connection->currentDataStreamVersion()
+ : QmlDebugConnection::minimumDataStreamVersion());
}
void QmlDebugClient::sendMessage(const QByteArray &message)
diff --git a/src/libs/qmldebug/qmldebugclient.h b/src/libs/qmldebug/qmldebugclient.h
index b39ec5f3db..fb5421d43d 100644
--- a/src/libs/qmldebug/qmldebugclient.h
+++ b/src/libs/qmldebug/qmldebugclient.h
@@ -32,52 +32,7 @@
namespace QmlDebug {
-class QmlDebugClient;
-class QmlDebugConnectionPrivate;
-class QMLDEBUG_EXPORT QmlDebugConnection : public QObject
-{
- Q_OBJECT
- Q_DISABLE_COPY(QmlDebugConnection)
- Q_DECLARE_PRIVATE(QmlDebugConnection)
-public:
- QmlDebugConnection(QObject * = 0);
- ~QmlDebugConnection();
-
- void connectToHost(const QString &hostName, quint16 port);
- void startLocalServer(const QString &fileName);
- QAbstractSocket::SocketState socketState() const;
-
- int currentDataStreamVersion() const;
- void setMaximumDataStreamVersion(int maximumVersion);
-
- bool isConnected() const;
- bool isConnecting() const;
- void close();
-
- QmlDebugClient *client(const QString &name) const;
- bool addClient(const QString &name, QmlDebugClient *client);
- bool removeClient(const QString &name);
-
- float serviceVersion(const QString &serviceName) const;
- bool sendMessage(const QString &name, const QByteArray &message);
-
-signals:
- void connected();
- void disconnected();
- void connectionFailed();
-
- void logError(const QString &error);
- void logStateChange(const QString &state);
-
-private:
- void newConnection();
- void socketConnected();
- void socketDisconnected();
- void protocolReadyRead();
-
- QScopedPointer<QmlDebugConnectionPrivate> d_ptr;
-};
-
+class QmlDebugConnection;
class QmlDebugClientPrivate;
class QMLDEBUG_EXPORT QmlDebugClient : public QObject
{
diff --git a/src/libs/qmldebug/qmldebugconnection.cpp b/src/libs/qmldebug/qmldebugconnection.cpp
new file mode 100644
index 0000000000..996896444e
--- /dev/null
+++ b/src/libs/qmldebug/qmldebugconnection.cpp
@@ -0,0 +1,431 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#include "qmldebugconnection.h"
+#include "qmldebugclient.h"
+#include "qpacketprotocol.h"
+
+#include <utils/temporaryfile.h>
+
+#include <QLocalServer>
+#include <QLocalSocket>
+#include <QNetworkProxy>
+#include <QTcpServer>
+#include <QTcpSocket>
+
+namespace QmlDebug {
+
+const int protocolVersion = 1;
+
+const QString serverId = QLatin1String("QDeclarativeDebugServer");
+const QString clientId = QLatin1String("QDeclarativeDebugClient");
+
+class QmlDebugConnectionPrivate
+{
+public:
+ QmlDebugConnectionPrivate();
+ QPacketProtocol *protocol;
+ QLocalServer *server;
+ QIODevice *device; // Currently a QTcpSocket or a QLocalSocket
+
+ bool gotHello;
+ QHash <QString, float> serverPlugins;
+ QHash<QString, QmlDebugClient *> plugins;
+
+ int currentDataStreamVersion;
+ int maximumDataStreamVersion;
+
+ void advertisePlugins();
+ void flush();
+};
+
+static QString socketStateToString(QAbstractSocket::SocketState state)
+{
+ QString stateString;
+ QDebug(&stateString) << state;
+ return QmlDebugConnection::tr("Socket state changed to %1").arg(stateString);
+}
+
+static QString socketErrorToString(QAbstractSocket::SocketError error)
+{
+ QString errorString;
+ QDebug(&errorString) << error;
+ return QmlDebugConnection::tr("Error: %1").arg(errorString);
+}
+
+QmlDebugConnectionPrivate::QmlDebugConnectionPrivate() :
+ protocol(0), server(0), device(0), gotHello(false),
+ currentDataStreamVersion(QmlDebugConnection::minimumDataStreamVersion()),
+ maximumDataStreamVersion(QDataStream::Qt_DefaultCompiledVersion)
+{
+}
+
+void QmlDebugConnectionPrivate::advertisePlugins()
+{
+ if (!gotHello)
+ return;
+
+ QPacket pack(currentDataStreamVersion);
+ pack << serverId << 1 << plugins.keys();
+ protocol->send(pack.data());
+ flush();
+}
+
+void QmlDebugConnection::socketConnected()
+{
+ Q_D(QmlDebugConnection);
+ QPacket pack(d->currentDataStreamVersion);
+ pack << serverId << 0 << protocolVersion << d->plugins.keys() << d->maximumDataStreamVersion
+ << true; // We accept multiple messages per packet
+ d->protocol->send(pack.data());
+ d->flush();
+}
+
+void QmlDebugConnection::socketDisconnected()
+{
+ Q_D(QmlDebugConnection);
+ if (d->gotHello) {
+ d->gotHello = false;
+ QHash<QString, QmlDebugClient*>::iterator iter = d->plugins.begin();
+ for (; iter != d->plugins.end(); ++iter)
+ iter.value()->stateChanged(QmlDebugClient::NotConnected);
+ emit disconnected();
+ } else if (d->device) {
+ emit connectionFailed();
+ }
+ if (d->protocol) {
+ d->protocol->disconnect();
+ d->protocol->deleteLater();
+ d->protocol = 0;
+ }
+ if (d->device) {
+ // Don't allow any "connected()" or "disconnected()" signals to be triggered anymore.
+ // As the protocol is gone this would lead to crashes.
+ d->device->disconnect();
+ // Don't immediately delete it as it may do some cleanup on returning from a signal.
+ d->device->deleteLater();
+ d->device = 0;
+ }
+}
+
+void QmlDebugConnection::protocolReadyRead()
+{
+ Q_D(QmlDebugConnection);
+ if (!d->gotHello) {
+ QPacket pack(d->currentDataStreamVersion, d->protocol->read());
+ QString name;
+
+ pack >> name;
+
+ bool validHello = false;
+ if (name == clientId) {
+ int op = -1;
+ pack >> op;
+ if (op == 0) {
+ int version = -1;
+ pack >> version;
+ if (version == protocolVersion) {
+ QStringList pluginNames;
+ QList<float> pluginVersions;
+ pack >> pluginNames;
+ if (!pack.atEnd())
+ pack >> pluginVersions;
+
+ const int pluginNamesSize = pluginNames.size();
+ const int pluginVersionsSize = pluginVersions.size();
+ for (int i = 0; i < pluginNamesSize; ++i) {
+ float pluginVersion = 1.0;
+ if (i < pluginVersionsSize)
+ pluginVersion = pluginVersions.at(i);
+ d->serverPlugins.insert(pluginNames.at(i), pluginVersion);
+ }
+
+ if (!pack.atEnd()) {
+ pack >> d->currentDataStreamVersion;
+ if (d->currentDataStreamVersion > d->maximumDataStreamVersion)
+ qWarning() << "Server returned invalid data stream version!";
+ }
+ validHello = true;
+ }
+ }
+ }
+
+ if (!validHello) {
+ qWarning("QML Debug Client: Invalid hello message");
+ close();
+ return;
+ }
+ d->gotHello = true;
+
+ QHash<QString, QmlDebugClient *>::Iterator iter = d->plugins.begin();
+ for (; iter != d->plugins.end(); ++iter) {
+ QmlDebugClient::State newState = QmlDebugClient::Unavailable;
+ if (d->serverPlugins.contains(iter.key()))
+ newState = QmlDebugClient::Enabled;
+ iter.value()->stateChanged(newState);
+ }
+ emit connected();
+ }
+
+ while (d->protocol && d->protocol->packetsAvailable()) {
+ QPacket pack(d->currentDataStreamVersion, d->protocol->read());
+ QString name;
+ pack >> name;
+
+ if (name == clientId) {
+ int op = -1;
+ pack >> op;
+
+ if (op == 1) {
+ // Service Discovery
+ QHash<QString, float> oldServerPlugins = d->serverPlugins;
+ d->serverPlugins.clear();
+
+ QStringList pluginNames;
+ QList<float> pluginVersions;
+ pack >> pluginNames;
+ if (!pack.atEnd())
+ pack >> pluginVersions;
+
+ const int pluginNamesSize = pluginNames.size();
+ const int pluginVersionsSize = pluginVersions.size();
+ for (int i = 0; i < pluginNamesSize; ++i) {
+ float pluginVersion = 1.0;
+ if (i < pluginVersionsSize)
+ pluginVersion = pluginVersions.at(i);
+ d->serverPlugins.insert(pluginNames.at(i), pluginVersion);
+ }
+
+ QHash<QString, QmlDebugClient *>::Iterator iter = d->plugins.begin();
+ for (; iter != d->plugins.end(); ++iter) {
+ const QString pluginName = iter.key();
+ QmlDebugClient::State newState = QmlDebugClient::Unavailable;
+ if (d->serverPlugins.contains(pluginName))
+ newState = QmlDebugClient::Enabled;
+
+ if (oldServerPlugins.contains(pluginName)
+ != d->serverPlugins.contains(pluginName)) {
+ iter.value()->stateChanged(newState);
+ }
+ }
+ } else {
+ qWarning() << "QML Debug Client: Unknown control message id" << op;
+ }
+ } else {
+ QHash<QString, QmlDebugClient *>::Iterator iter = d->plugins.find(name);
+ if (iter == d->plugins.end()) {
+ qWarning() << "QML Debug Client: Message received for missing plugin" << name;
+ } else {
+ QmlDebugClient *client = *iter;
+ QByteArray message;
+ while (!pack.atEnd()) {
+ pack >> message;
+ client->messageReceived(message);
+ }
+ }
+ }
+ }
+}
+
+QmlDebugConnection::QmlDebugConnection(QObject *parent)
+ : QObject(parent), d_ptr(new QmlDebugConnectionPrivate)
+{
+}
+
+QmlDebugConnection::~QmlDebugConnection()
+{
+ socketDisconnected();
+}
+
+bool QmlDebugConnection::isConnected() const
+{
+ Q_D(const QmlDebugConnection);
+ // gotHello can only be set if the connection is open.
+ return d->gotHello;
+}
+
+bool QmlDebugConnection::isConnecting() const
+{
+ Q_D(const QmlDebugConnection);
+ return !d->gotHello && d->device;
+}
+
+void QmlDebugConnection::close()
+{
+ Q_D(QmlDebugConnection);
+ if (d->device && d->device->isOpen())
+ d->device->close(); // will trigger disconnected() at some point.
+}
+
+QmlDebugClient *QmlDebugConnection::client(const QString &name) const
+{
+ Q_D(const QmlDebugConnection);
+ return d->plugins.value(name, 0);
+}
+
+bool QmlDebugConnection::addClient(const QString &name, QmlDebugClient *client)
+{
+ Q_D(QmlDebugConnection);
+ if (d->plugins.contains(name))
+ return false;
+ d->plugins.insert(name, client);
+ d->advertisePlugins();
+ return true;
+}
+
+bool QmlDebugConnection::removeClient(const QString &name)
+{
+ Q_D(QmlDebugConnection);
+ if (!d->plugins.contains(name))
+ return false;
+ d->plugins.remove(name);
+ d->advertisePlugins();
+ return true;
+}
+
+float QmlDebugConnection::serviceVersion(const QString &serviceName) const
+{
+ Q_D(const QmlDebugConnection);
+ return d->serverPlugins.value(serviceName, -1);
+}
+
+bool QmlDebugConnection::sendMessage(const QString &name, const QByteArray &message)
+{
+ Q_D(QmlDebugConnection);
+ if (!d->gotHello || !d->serverPlugins.contains(name))
+ return false;
+
+ QPacket pack(d->currentDataStreamVersion);
+ pack << name << message;
+ d->protocol->send(pack.data());
+ d->flush();
+ return true;
+}
+
+int QmlDebugConnection::minimumDataStreamVersion()
+{
+ return QDataStream::Qt_4_7;
+}
+
+void QmlDebugConnectionPrivate::flush()
+{
+ if (QAbstractSocket *socket = qobject_cast<QAbstractSocket *>(device))
+ socket->flush();
+ else if (QLocalSocket *socket = qobject_cast<QLocalSocket *>(device))
+ socket->flush();
+}
+
+void QmlDebugConnection::connectToHost(const QString &hostName, quint16 port)
+{
+ Q_D(QmlDebugConnection);
+ socketDisconnected();
+ QTcpSocket *socket = new QTcpSocket(this);
+ socket->setProxy(QNetworkProxy::NoProxy);
+ d->device = socket;
+ d->protocol = new QPacketProtocol(socket, this);
+ QObject::connect(d->protocol, &QPacketProtocol::readyRead,
+ this, &QmlDebugConnection::protocolReadyRead);
+ connect(socket, &QAbstractSocket::stateChanged,
+ this, [this](QAbstractSocket::SocketState state) {
+ emit logStateChange(socketStateToString(state));
+ });
+
+ connect(socket, static_cast<void (QTcpSocket::*)(QAbstractSocket::SocketError)>
+ (&QAbstractSocket::error), this, [this](QAbstractSocket::SocketError error) {
+ emit logError(socketErrorToString(error));
+ socketDisconnected();
+ });
+ connect(socket, &QAbstractSocket::connected, this, &QmlDebugConnection::socketConnected);
+ connect(socket, &QAbstractSocket::disconnected, this, &QmlDebugConnection::socketDisconnected);
+ socket->connectToHost(hostName.isEmpty() ? QString("localhost") : hostName, port);
+}
+
+void QmlDebugConnection::startLocalServer(const QString &fileName)
+{
+ Q_D(QmlDebugConnection);
+ if (d->gotHello)
+ close();
+ if (d->server)
+ d->server->deleteLater();
+ d->server = new QLocalServer(this);
+ // QueuedConnection so that waitForNewConnection() returns true.
+ connect(d->server, &QLocalServer::newConnection,
+ this, &QmlDebugConnection::newConnection, Qt::QueuedConnection);
+ if (!d->server->listen(fileName))
+ emit connectionFailed();
+}
+
+void QmlDebugConnection::newConnection()
+{
+ Q_D(QmlDebugConnection);
+ delete d->device;
+ QLocalSocket *socket = d->server->nextPendingConnection();
+ d->server->close();
+ d->device = socket;
+ delete d->protocol;
+ d->protocol = new QPacketProtocol(socket, this);
+ QObject::connect(d->protocol, &QPacketProtocol::readyRead,
+ this, &QmlDebugConnection::protocolReadyRead);
+
+ connect(socket, &QLocalSocket::disconnected, this, &QmlDebugConnection::socketDisconnected);
+
+ connect(socket, static_cast<void (QLocalSocket::*)(QLocalSocket::LocalSocketError)>
+ (&QLocalSocket::error), this, [this](QLocalSocket::LocalSocketError error) {
+ emit logError(socketErrorToString(static_cast<QAbstractSocket::SocketError>(error)));
+ socketDisconnected();
+ });
+
+ connect(socket, &QLocalSocket::stateChanged,
+ this, [this](QLocalSocket::LocalSocketState state) {
+ logStateChange(socketStateToString(static_cast<QAbstractSocket::SocketState>(state)));
+ });
+
+ socketConnected();
+}
+
+int QmlDebugConnection::currentDataStreamVersion() const
+{
+ Q_D(const QmlDebugConnection);
+ return d->currentDataStreamVersion;
+}
+
+void QmlDebugConnection::setMaximumDataStreamVersion(int maximumVersion)
+{
+ Q_D(QmlDebugConnection);
+ d->maximumDataStreamVersion = maximumVersion;
+}
+
+QAbstractSocket::SocketState QmlDebugConnection::socketState() const
+{
+ Q_D(const QmlDebugConnection);
+ if (QAbstractSocket *socket = qobject_cast<QAbstractSocket *>(d->device))
+ return socket->state();
+ else if (QLocalSocket *socket = qobject_cast<QLocalSocket *>(d->device))
+ return static_cast<QAbstractSocket::SocketState>(socket->state());
+ else
+ return QAbstractSocket::UnconnectedState;
+}
+
+} // namespace QmlDebug
diff --git a/src/libs/qmldebug/qmldebugconnection.h b/src/libs/qmldebug/qmldebugconnection.h
new file mode 100644
index 0000000000..d217291751
--- /dev/null
+++ b/src/libs/qmldebug/qmldebugconnection.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include "qmldebug_global.h"
+
+#include <QObject>
+#include <QUrl>
+#include <QAbstractSocket>
+
+namespace QmlDebug {
+
+class QmlDebugClient;
+class QmlDebugConnectionPrivate;
+class QMLDEBUG_EXPORT QmlDebugConnection : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QmlDebugConnection)
+ Q_DECLARE_PRIVATE(QmlDebugConnection)
+public:
+ QmlDebugConnection(QObject * = 0);
+ ~QmlDebugConnection();
+
+ void connectToHost(const QString &hostName, quint16 port);
+ void startLocalServer(const QString &fileName);
+ QAbstractSocket::SocketState socketState() const;
+
+ int currentDataStreamVersion() const;
+ void setMaximumDataStreamVersion(int maximumVersion);
+
+ bool isConnected() const;
+ bool isConnecting() const;
+ void close();
+
+ QmlDebugClient *client(const QString &name) const;
+ bool addClient(const QString &name, QmlDebugClient *client);
+ bool removeClient(const QString &name);
+
+ float serviceVersion(const QString &serviceName) const;
+ bool sendMessage(const QString &name, const QByteArray &message);
+
+ static int minimumDataStreamVersion();
+
+signals:
+ void connected();
+ void disconnected();
+ void connectionFailed();
+
+ void logError(const QString &error);
+ void logStateChange(const QString &state);
+
+private:
+ void newConnection();
+ void socketConnected();
+ void socketDisconnected();
+ void protocolReadyRead();
+
+ QScopedPointer<QmlDebugConnectionPrivate> d_ptr;
+};
+
+} // namespace QmlDebug
diff --git a/src/libs/qmldebug/qmltoolsclient.cpp b/src/libs/qmldebug/qmltoolsclient.cpp
index e882f0733b..1f22e36b74 100644
--- a/src/libs/qmldebug/qmltoolsclient.cpp
+++ b/src/libs/qmldebug/qmltoolsclient.cpp
@@ -24,6 +24,7 @@
****************************************************************************/
#include "qmltoolsclient.h"
+#include "qmldebugconnection.h"
#include <qmldebug/qpacketprotocol.h>
#include <QStringList>