1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtDeclarative module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "private/qdeclarativedebugclient_p.h"
43
44#include "private/qpacketprotocol_p.h"
45
46#include <QtCore/qdebug.h>
47#include <QtCore/qstringlist.h>
48
49#include <private/qobject_p.h>
50
51QT_BEGIN_NAMESPACE
52
53const int protocolVersion = 1;
54const QString serverId = QLatin1String("QDeclarativeDebugServer");
55const QString clientId = QLatin1String("QDeclarativeDebugClient");
56
57class QDeclarativeDebugClientPrivate : public QObjectPrivate
58{
59 Q_DECLARE_PUBLIC(QDeclarativeDebugClient)
60public:
61 QDeclarativeDebugClientPrivate();
62
63 QString name;
64 QDeclarativeDebugConnection *connection;
65};
66
67class QDeclarativeDebugConnectionPrivate : public QObject
68{
69 Q_OBJECT
70public:
71 QDeclarativeDebugConnectionPrivate(QDeclarativeDebugConnection *c);
72 QDeclarativeDebugConnection *q;
73 QPacketProtocol *protocol;
74
75 bool gotHello;
76 QStringList serverPlugins;
77 QHash<QString, QDeclarativeDebugClient *> plugins;
78
79 void advertisePlugins();
80
81public Q_SLOTS:
82 void connected();
83 void readyRead();
84};
85
86QDeclarativeDebugConnectionPrivate::QDeclarativeDebugConnectionPrivate(QDeclarativeDebugConnection *c)
87: QObject(c), q(c), protocol(0), gotHello(false)
88{
89 protocol = new QPacketProtocol(q, this);
90 QObject::connect(c, SIGNAL(connected()), this, SLOT(connected()));
91 QObject::connect(protocol, SIGNAL(readyRead()), this, SLOT(readyRead()));
92}
93
94void QDeclarativeDebugConnectionPrivate::advertisePlugins()
95{
96 if (!q->isConnected())
97 return;
98
99 QPacket pack;
100 pack << serverId << 1 << plugins.keys();
101 protocol->send(pack);
102 q->flush();
103}
104
105void QDeclarativeDebugConnectionPrivate::connected()
106{
107 QPacket pack;
108 pack << serverId << 0 << protocolVersion << plugins.keys();
109 protocol->send(pack);
110 q->flush();
111}
112
113void QDeclarativeDebugConnectionPrivate::readyRead()
114{
115 if (!gotHello) {
116 QPacket pack = protocol->read();
117 QString name;
118
119 pack >> name;
120
121 bool validHello = false;
122 if (name == clientId) {
123 int op = -1;
124 pack >> op;
125 if (op == 0) {
126 int version = -1;
127 pack >> version;
128 if (version == protocolVersion) {
129 pack >> serverPlugins;
130 validHello = true;
131 }
132 }
133 }
134
135 if (!validHello) {
136 qWarning("QDeclarativeDebugConnection: Invalid hello message");
137 QObject::disconnect(protocol, SIGNAL(readyRead()), this, SLOT(readyRead()));
138 return;
139 }
140
141 gotHello = true;
142
143 QHash<QString, QDeclarativeDebugClient *>::Iterator iter = plugins.begin();
144 for (; iter != plugins.end(); ++iter) {
145 QDeclarativeDebugClient::Status newStatus = QDeclarativeDebugClient::Unavailable;
146 if (serverPlugins.contains(iter.key()))
147 newStatus = QDeclarativeDebugClient::Enabled;
148 iter.value()->statusChanged(newStatus);
149 }
150 }
151
152 while (protocol->packetsAvailable()) {
153 QPacket pack = protocol->read();
154 QString name;
155 pack >> name;
156
157 if (name == clientId) {
158 int op = -1;
159 pack >> op;
160
161 if (op == 1) {
162 // Service Discovery
163 QStringList oldServerPlugins = serverPlugins;
164 pack >> serverPlugins;
165
166 QHash<QString, QDeclarativeDebugClient *>::Iterator iter = plugins.begin();
167 for (; iter != plugins.end(); ++iter) {
168 const QString pluginName = iter.key();
169 QDeclarativeDebugClient::Status newStatus = QDeclarativeDebugClient::Unavailable;
170 if (serverPlugins.contains(pluginName))
171 newStatus = QDeclarativeDebugClient::Enabled;
172
173 if (oldServerPlugins.contains(pluginName)
174 != serverPlugins.contains(pluginName)) {
175 iter.value()->statusChanged(newStatus);
176 }
177 }
178 } else {
179 qWarning() << "QDeclarativeDebugConnection: Unknown control message id" << op;
180 }
181 } else {
182 QByteArray message;
183 pack >> message;
184
185 QHash<QString, QDeclarativeDebugClient *>::Iterator iter =
186 plugins.find(name);
187 if (iter == plugins.end()) {
188 qWarning() << "QDeclarativeDebugConnection: Message received for missing plugin" << name;
189 } else {
190 (*iter)->messageReceived(message);
191 }
192 }
193 }
194}
195
196QDeclarativeDebugConnection::QDeclarativeDebugConnection(QObject *parent)
197: QTcpSocket(parent), d(new QDeclarativeDebugConnectionPrivate(this))
198{
199}
200
201QDeclarativeDebugConnection::~QDeclarativeDebugConnection()
202{
203 QHash<QString, QDeclarativeDebugClient*>::iterator iter = d->plugins.begin();
204 for (; iter != d->plugins.end(); ++iter) {
205 iter.value()->d_func()->connection = 0;
206 iter.value()->statusChanged(QDeclarativeDebugClient::NotConnected);
207 }
208}
209
210bool QDeclarativeDebugConnection::isConnected() const
211{
212 return state() == ConnectedState;
213}
214
215QDeclarativeDebugClientPrivate::QDeclarativeDebugClientPrivate()
216: connection(0)
217{
218}
219
220QDeclarativeDebugClient::QDeclarativeDebugClient(const QString &name,
221 QDeclarativeDebugConnection *parent)
222: QObject(*(new QDeclarativeDebugClientPrivate), parent)
223{
224 Q_D(QDeclarativeDebugClient);
225 d->name = name;
226 d->connection = parent;
227
228 if (!d->connection)
229 return;
230
231 if (d->connection->d->plugins.contains(name)) {
232 qWarning() << "QDeclarativeDebugClient: Conflicting plugin name" << name;
233 d->connection = 0;
234 } else {
235 d->connection->d->plugins.insert(name, this);
236 d->connection->d->advertisePlugins();
237 }
238}
239
240QDeclarativeDebugClient::~QDeclarativeDebugClient()
241{
242 Q_D(const QDeclarativeDebugClient);
243 if (d->connection && d->connection->d) {
244 d->connection->d->plugins.remove(d->name);
245 d->connection->d->advertisePlugins();
246 }
247}
248
249QString QDeclarativeDebugClient::name() const
250{
251 Q_D(const QDeclarativeDebugClient);
252 return d->name;
253}
254
255QDeclarativeDebugClient::Status QDeclarativeDebugClient::status() const
256{
257 Q_D(const QDeclarativeDebugClient);
258 if (!d->connection
259 || !d->connection->isConnected()
260 || !d->connection->d->gotHello)
261 return NotConnected;
262
263 if (d->connection->d->serverPlugins.contains(d->name))
264 return Enabled;
265
266 return Unavailable;
267}
268
269void QDeclarativeDebugClient::sendMessage(const QByteArray &message)
270{
271 Q_D(QDeclarativeDebugClient);
272
273 if (status() != Enabled)
274 return;
275
276 QPacket pack;
277 pack << d->name << message;
278 d->connection->d->protocol->send(pack);
279 d->connection->d->q->flush();
280}
281
282void QDeclarativeDebugClient::statusChanged(Status)
283{
284}
285
286void QDeclarativeDebugClient::messageReceived(const QByteArray &)
287{
288}
289
290QT_END_NAMESPACE
291
292#include <qdeclarativedebugclient.moc>
293