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 | |
51 | QT_BEGIN_NAMESPACE |
52 | |
53 | const int protocolVersion = 1; |
54 | const QString serverId = QLatin1String("QDeclarativeDebugServer" ); |
55 | const QString clientId = QLatin1String("QDeclarativeDebugClient" ); |
56 | |
57 | class QDeclarativeDebugClientPrivate : public QObjectPrivate |
58 | { |
59 | Q_DECLARE_PUBLIC(QDeclarativeDebugClient) |
60 | public: |
61 | QDeclarativeDebugClientPrivate(); |
62 | |
63 | QString name; |
64 | QDeclarativeDebugConnection *connection; |
65 | }; |
66 | |
67 | class QDeclarativeDebugConnectionPrivate : public QObject |
68 | { |
69 | Q_OBJECT |
70 | public: |
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 | |
81 | public Q_SLOTS: |
82 | void connected(); |
83 | void readyRead(); |
84 | }; |
85 | |
86 | QDeclarativeDebugConnectionPrivate::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 | |
94 | void 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 | |
105 | void QDeclarativeDebugConnectionPrivate::connected() |
106 | { |
107 | QPacket pack; |
108 | pack << serverId << 0 << protocolVersion << plugins.keys(); |
109 | protocol->send(pack); |
110 | q->flush(); |
111 | } |
112 | |
113 | void 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 | |
196 | QDeclarativeDebugConnection::QDeclarativeDebugConnection(QObject *parent) |
197 | : QTcpSocket(parent), d(new QDeclarativeDebugConnectionPrivate(this)) |
198 | { |
199 | } |
200 | |
201 | QDeclarativeDebugConnection::~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 | |
210 | bool QDeclarativeDebugConnection::isConnected() const |
211 | { |
212 | return state() == ConnectedState; |
213 | } |
214 | |
215 | QDeclarativeDebugClientPrivate::QDeclarativeDebugClientPrivate() |
216 | : connection(0) |
217 | { |
218 | } |
219 | |
220 | QDeclarativeDebugClient::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 | |
240 | QDeclarativeDebugClient::~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 | |
249 | QString QDeclarativeDebugClient::name() const |
250 | { |
251 | Q_D(const QDeclarativeDebugClient); |
252 | return d->name; |
253 | } |
254 | |
255 | QDeclarativeDebugClient::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 | |
269 | void 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 | |
282 | void QDeclarativeDebugClient::statusChanged(Status) |
283 | { |
284 | } |
285 | |
286 | void QDeclarativeDebugClient::messageReceived(const QByteArray &) |
287 | { |
288 | } |
289 | |
290 | QT_END_NAMESPACE |
291 | |
292 | #include <qdeclarativedebugclient.moc> |
293 | |