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