diff options
author | Kai Koehne <kai.koehne@nokia.com> | 2010-09-22 19:03:57 (GMT) |
---|---|---|
committer | Kai Koehne <kai.koehne@nokia.com> | 2010-09-28 05:55:32 (GMT) |
commit | fd9771c29d401d88779ab7c5d7715c9ca41dd723 (patch) | |
tree | 0e96e0871e8914f5747bfc1a1314d76a78620b6d /src/declarative/debugger/qdeclarativedebugservice.cpp | |
parent | 7b796b4dcdebfba55c4754d241edb334217fc550 (diff) | |
download | Qt-fd9771c29d401d88779ab7c5d7715c9ca41dd723.zip Qt-fd9771c29d401d88779ab7c5d7715c9ca41dd723.tar.gz Qt-fd9771c29d401d88779ab7c5d7715c9ca41dd723.tar.bz2 |
Make QmlDebug protocol more robust
The protocol so far was client->server only. That is, there was no
sane way for a client to check whether a plugin on the server (service)
was available or not. E.g. calling Client::setEnabled(true) 'succeeded',
without a check whether there is actually a service to talk to.
The new protocol replaces this shortcoming by a service discovery
mechanism: Both client & service announce their available plugins at
handshake time, and later on if there are changes. The status is
reflected in Client::status() and Service::Status() , which are either
NotConnected - no network connection, or not registered properly
Unavailable - TCP/IP connection works, but no plugin with the same
name on the other side
Enabled - You can connect to plugin on other side
The status changes happen automatically (no setEnabled() anymore).
Furthermore a version ID was added to the handshake, so that we can
extend the protocol further in the future :)
Diffstat (limited to 'src/declarative/debugger/qdeclarativedebugservice.cpp')
-rw-r--r-- | src/declarative/debugger/qdeclarativedebugservice.cpp | 126 |
1 files changed, 99 insertions, 27 deletions
diff --git a/src/declarative/debugger/qdeclarativedebugservice.cpp b/src/declarative/debugger/qdeclarativedebugservice.cpp index 1f2bf4f..0fbc1e3 100644 --- a/src/declarative/debugger/qdeclarativedebugservice.cpp +++ b/src/declarative/debugger/qdeclarativedebugservice.cpp @@ -54,6 +54,30 @@ QT_BEGIN_NAMESPACE +/* + QDeclarativeDebug Protocol (Version 1): + + handshake: + 1. Client sends + "QDeclarativeDebugServer" 0 version pluginNames + version: an int representing the highest protocol version the client knows + pluginNames: plugins available on client side + 2. Server sends + "QDeclarativeDebugClient" 0 version pluginNames + version: an int representing the highest protocol version the client & server know + pluginNames: plugins available on server side. plugins both in the client and server message are enabled. + client plugin advertisement + 1. Client sends + "QDeclarativeDebugServer" 1 pluginNames + server plugin advertisement + 1. Server sends + "QDeclarativeDebugClient" 1 pluginNames + plugin communication: + Everything send with a header different to "QDeclarativeDebugServer" is sent to the appropriate plugin. + */ + +const int protocolVersion = 1; + class QDeclarativeDebugServerPrivate; class QDeclarativeDebugServer : public QObject { @@ -82,11 +106,13 @@ class QDeclarativeDebugServerPrivate : public QObjectPrivate public: QDeclarativeDebugServerPrivate(); + void advertisePlugins(); + int port; QTcpSocket *connection; QPacketProtocol *protocol; QHash<QString, QDeclarativeDebugService *> plugins; - QStringList enabledPlugins; + QStringList clientPlugins; QTcpServer *tcpServer; bool gotHello; }; @@ -106,6 +132,18 @@ QDeclarativeDebugServerPrivate::QDeclarativeDebugServerPrivate() { } +void QDeclarativeDebugServerPrivate::advertisePlugins() +{ + if (!connection + || connection->state() != QTcpSocket::ConnectedState + || !gotHello) + return; + + QPacket pack; + pack << QString(QLatin1String("QDeclarativeDebugClient")) << 1 << plugins.keys(); + protocol->send(pack); +} + void QDeclarativeDebugServer::listen() { Q_D(QDeclarativeDebugServer); @@ -202,9 +240,13 @@ void QDeclarativeDebugServer::readyRead() if (!d->gotHello) { QPacket hello = d->protocol->read(); - QString name; - hello >> name >> d->enabledPlugins; - if (name != QLatin1String("QDeclarativeDebugServer")) { + + QString name; + int op; + hello >> name >> op; + + if (name != QLatin1String("QDeclarativeDebugServer") + || op != 0) { qWarning("QDeclarativeDebugServer: Invalid hello message"); QObject::disconnect(d->protocol, SIGNAL(readyRead()), this, SLOT(readyRead())); d->protocol->deleteLater(); @@ -213,6 +255,23 @@ void QDeclarativeDebugServer::readyRead() d->connection = 0; return; } + + int version; + hello >> version >> d->clientPlugins; + + QHash<QString, QDeclarativeDebugService*>::Iterator iter = d->plugins.begin(); + for (; iter != d->plugins.end(); ++iter) { + QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::Unavailable; + if (d->clientPlugins.contains(iter.key())) + newStatus = QDeclarativeDebugService::Enabled; + iter.value()->statusChanged(newStatus); + } + + QPacket helloAnswer; + helloAnswer << QString(QLatin1String("QDeclarativeDebugClient")) << 0 << protocolVersion << d->plugins.keys(); + d->protocol->send(helloAnswer); + d->connection->flush(); + d->gotHello = true; qWarning("QDeclarativeDebugServer: Connection established"); } @@ -226,32 +285,29 @@ void QDeclarativeDebugServer::readyRead() pack >> name; if (name == debugServer) { - int op = -1; QString plugin; - pack >> op >> plugin; + int op = -1; + pack >> op; if (op == 1) { - // Enable - if (!d->enabledPlugins.contains(plugin)) { - d->enabledPlugins.append(plugin); - QHash<QString, QDeclarativeDebugService *>::Iterator iter = - d->plugins.find(plugin); - if (iter != d->plugins.end()) - (*iter)->enabledChanged(true); - } - - } else if (op == 2) { - // Disable - if (d->enabledPlugins.contains(plugin)) { - d->enabledPlugins.removeAll(plugin); - QHash<QString, QDeclarativeDebugService *>::Iterator iter = - d->plugins.find(plugin); - if (iter != d->plugins.end()) - (*iter)->enabledChanged(false); + // Service Discovery + QStringList oldClientPlugins = d->clientPlugins; + pack >> d->clientPlugins; + + QHash<QString, QDeclarativeDebugService*>::Iterator iter = d->plugins.begin(); + for (; iter != d->plugins.end(); ++iter) { + const QString pluginName = iter.key(); + QDeclarativeDebugService::Status newStatus = QDeclarativeDebugService::Unavailable; + if (d->clientPlugins.contains(pluginName)) + newStatus = QDeclarativeDebugService::Enabled; + + if (oldClientPlugins.contains(pluginName) + != d->clientPlugins.contains(pluginName)) { + iter.value()->statusChanged(newStatus); + } } } else { qWarning("QDeclarativeDebugServer: Invalid control message %d", op); } - } else { QByteArray message; pack >> message; @@ -287,6 +343,16 @@ QDeclarativeDebugService::QDeclarativeDebugService(const QString &name, QObject d->server = 0; } else { d->server->d_func()->plugins.insert(name, this); + d->server->d_func()->advertisePlugins(); + } +} + +QDeclarativeDebugService::~QDeclarativeDebugService() +{ + Q_D(const QDeclarativeDebugService); + if (d->server) { + d->server->d_func()->plugins.remove(d->name); + d->server->d_func()->advertisePlugins(); } } @@ -296,10 +362,16 @@ QString QDeclarativeDebugService::name() const return d->name; } -bool QDeclarativeDebugService::isEnabled() const +QDeclarativeDebugService::Status QDeclarativeDebugService::status() const { Q_D(const QDeclarativeDebugService); - return (d->server && d->server->d_func()->enabledPlugins.contains(d->name)); + if (!d->server + || !d->server->hasDebuggingClient()) + return NotConnected; + if (d->server->d_func()->clientPlugins.contains(d->name)) + return Enabled; + + return Unavailable; } namespace { @@ -422,7 +494,7 @@ void QDeclarativeDebugService::sendMessage(const QByteArray &message) d->server->d_func()->connection->flush(); } -void QDeclarativeDebugService::enabledChanged(bool) +void QDeclarativeDebugService::statusChanged(Status) { } |