1 /***************************************************************************
2 rktransmitter - description
3 -------------------
4 begin : Thu Nov 18 2010
5 copyright : (C) 2010, 2013 by Thomas Friedrichsmeier
6 email : thomas.friedrichsmeier@kdemail.net
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18 #include "rktransmitter.h"
19
20 #include "../debug.h"
21
serialize(const RBackendRequest & request,QDataStream & stream)22 void RKRBackendSerializer::serialize (const RBackendRequest &request, QDataStream &stream) {
23 RK_TRACE (RBACKEND);
24
25 stream << (qint16) request.id;
26 stream << (qint8) request.type;
27 stream << request.synchronous;
28 stream << request.done; // well, not really needed, but...
29 if (request.command) {
30 stream << true;
31 serializeProxy (*(request.command), stream);
32 } else {
33 stream << false;
34 }
35 if (request.output) {
36 RK_ASSERT (request.type == RBackendRequest::Output);
37 stream << true;
38 serializeOutput (*(request.output), stream);
39 } else {
40 stream << false;
41 }
42 stream << request.params;
43 }
44
unserialize(QDataStream & stream)45 RBackendRequest *RKRBackendSerializer::unserialize (QDataStream &stream) {
46 RK_TRACE (RBACKEND);
47
48 RBackendRequest *request = new RBackendRequest (false, RBackendRequest::OtherRequest); // will be overwritten
49 RBackendRequest::_id--;
50
51 bool dummyb;
52 qint8 dummy8;
53 qint16 dummy16;
54 stream >> dummy16;
55 request->id = dummy16;
56 stream >> dummy8;
57 request->type = (RBackendRequest::RCallbackType) dummy8;
58 stream >> request->synchronous;
59 stream >> dummyb;
60 request->done = dummyb;
61 stream >> dummyb;
62 if (dummyb) request->command = unserializeProxy (stream);
63 stream >> dummyb;
64 if (dummyb) request->output = unserializeOutput (stream);
65 stream >> request->params;
66
67 return request;
68 }
69
serializeOutput(const ROutputList & list,QDataStream & stream)70 void RKRBackendSerializer::serializeOutput (const ROutputList &list, QDataStream &stream) {
71 RK_TRACE (RBACKEND);
72
73 stream << (qint32) list.size ();
74 for (qint32 i = 0; i < list.size (); ++i) {
75 stream << (qint8) list[i]->type;
76 stream << list[i]->output;
77 }
78 }
79
unserializeOutput(QDataStream & stream)80 ROutputList* RKRBackendSerializer::unserializeOutput (QDataStream &stream) {
81 RK_TRACE (RBACKEND);
82
83 ROutputList *ret = new ROutputList ();
84 qint32 len;
85 stream >> len;
86 ret->reserve (len);
87
88 for (qint32 i = 0; i < len; ++i) {
89 ROutput* out = new ROutput;
90 qint8 dummy8;
91 stream >> dummy8;
92 out->type = (ROutput::ROutputType) dummy8;
93 stream >> out->output;
94 ret->append (out);
95 }
96
97 return ret;
98 }
99
serializeData(const RData & data,QDataStream & stream)100 void RKRBackendSerializer::serializeData (const RData &data, QDataStream &stream) {
101 RK_TRACE (RBACKEND);
102
103 RData::RDataType type = data.getDataType ();
104 stream << (qint8) type;
105 if (type == RData::IntVector) stream << data.intVector ();
106 else if (type == RData::StringVector) stream << data.stringVector ();
107 else if (type == RData::RealVector) stream << data.realVector ();
108 else if (type == RData::StructureVector) {
109 RData::RDataStorage list = data.structureVector ();
110 qint32 len = list.size ();
111 stream << len;
112 for (qint32 i = 0; i < list.size (); ++i) {
113 serializeData (*(list[i]), stream);
114 }
115 } else {
116 RK_ASSERT (type == RData::NoData);
117 }
118 }
119
unserializeData(QDataStream & stream)120 RData* RKRBackendSerializer::unserializeData (QDataStream &stream) {
121 RK_TRACE (RBACKEND);
122
123 RData* ret = new RData;
124 RData::RDataType type;
125 qint8 dummy8;
126 stream >> dummy8;
127 type = (RData::RDataType) dummy8;
128 if (type == RData::IntVector) {
129 RData::IntStorage data;
130 stream >> data;
131 ret->setData (data);
132 } else if (type == RData::StringVector) {
133 RData::StringStorage data;
134 stream >> data;
135 ret->setData (data);
136 } else if (type == RData::RealVector) {
137 RData::RealStorage data;
138 stream >> data;
139 ret->setData (data);
140 } else if (type == RData::StructureVector) {
141 RData::RDataStorage data;
142 qint32 len;
143 stream >> len;
144 data.reserve (len);
145 for (qint32 i = 0; i < len; ++i) {
146 data.append (unserializeData (stream));
147 }
148 ret->setData (data);
149 } else {
150 RK_ASSERT (type == RData::NoData);
151 }
152
153 return ret;
154 }
155
serializeProxy(const RCommandProxy & proxy,QDataStream & stream)156 void RKRBackendSerializer::serializeProxy (const RCommandProxy &proxy, QDataStream &stream) {
157 RK_TRACE (RBACKEND);
158
159 stream << proxy.command;
160 stream << (qint32) proxy.type;
161 stream << (qint32) proxy.id;
162 stream << (qint32) proxy.status;
163 stream << (qint32) proxy.has_been_run_up_to;
164
165 serializeData (proxy, stream);
166 }
167
unserializeProxy(QDataStream & stream)168 RCommandProxy* RKRBackendSerializer::unserializeProxy (QDataStream &stream) {
169 RK_TRACE (RBACKEND);
170
171 QString command;
172 stream >> command;
173 qint32 type;
174 stream >> type;
175 RCommandProxy* ret = new RCommandProxy (command, type);
176 qint32 dummy32;
177 stream >> dummy32;
178 ret->id = dummy32;
179 stream >> dummy32;
180 ret->status = dummy32;
181 stream >> dummy32;
182 ret->has_been_run_up_to = dummy32;
183
184 RData *data = unserializeData (stream);
185 ret->swallowData (*data);
186 delete (data);
187
188 return ret;
189 }
190
191
192 #include <QTimer>
193 #include <QLocalSocket>
194 RKAbstractTransmitter* RKAbstractTransmitter::_instance = 0;
RKAbstractTransmitter()195 RKAbstractTransmitter::RKAbstractTransmitter () : QThread () {
196 RK_TRACE (RBACKEND);
197
198 RK_ASSERT (_instance == 0); // NOTE: Although there are two instances of an abstract transmitter in an RKWard session, these live in different processes.
199 _instance = this;
200 connection = 0;
201
202 moveToThread (this);
203 }
204
~RKAbstractTransmitter()205 RKAbstractTransmitter::~RKAbstractTransmitter () {
206 RK_TRACE (RBACKEND);
207 }
208
transmitRequest(RBackendRequest * request)209 void RKAbstractTransmitter::transmitRequest (RBackendRequest *request) {
210 RK_TRACE (RBACKEND);
211 RK_ASSERT (connection);
212
213 if (!connection->isOpen ()) {
214 handleTransmissionError ("Connection not open while trying to write request. Last error was: " + connection->errorString ());
215 return;
216 }
217
218 RKRBackendSerializer::serialize (*request, streamer.outstream);
219 RK_DEBUG (RBACKEND, DL_DEBUG, "Transmitting request of length %d", streamer.outSize ());
220 streamer.writeOutBuffer ();
221 }
222
customEvent(QEvent * e)223 void RKAbstractTransmitter::customEvent (QEvent *e) {
224 RK_TRACE (RBACKEND);
225
226 if (((int) e->type ()) == ((int) RKRBackendEvent::RKWardEvent)) {
227 RKRBackendEvent *ev = static_cast<RKRBackendEvent*> (e);
228 writeRequest (ev->data ());
229 } else {
230 RK_ASSERT (false);
231 return;
232 }
233 }
234
fetchTransmission()235 void RKAbstractTransmitter::fetchTransmission () {
236 RK_TRACE (RBACKEND);
237
238 while (connection->bytesAvailable ()) {
239 if (!streamer.readInBuffer ()) break;
240
241 requestReceived (RKRBackendSerializer::unserialize (streamer.instream));
242 RK_ASSERT (streamer.instream.atEnd ()); // full transmission should have been read
243 }
244
245 if (!connection->isOpen ()) {
246 handleTransmissionError ("Connection closed unexepctedly. Last error was: " + connection->errorString ());
247 return;
248 }
249 }
250
setConnection(QLocalSocket * _connection)251 void RKAbstractTransmitter::setConnection (QLocalSocket *_connection) {
252 RK_TRACE (RBACKEND);
253 RK_ASSERT (!connection);
254
255 connection = _connection;
256 streamer.setIODevice (connection);
257 RK_ASSERT (connection->isOpen ());
258
259 connect (connection, &QLocalSocket::readyRead, this, &RKAbstractTransmitter::fetchTransmission);
260 connect (connection, &QLocalSocket::disconnected, this, &RKAbstractTransmitter::disconnected);
261
262 // In case something is pending already.
263 if (connection->bytesAvailable ()) QTimer::singleShot (0, this, SLOT (fetchTransmission()));
264 }
265
disconnected()266 void RKAbstractTransmitter::disconnected () {
267 RK_TRACE (RBACKEND);
268
269 handleTransmissionError ("Connection closed unexpectedly. Last error was: " + connection->errorString ());
270 }
271
272