v2.0.0
Loading...
Searching...
No Matches
rt_cmd_client.cpp
Go to the documentation of this file.
1//=============================================================================================================
36
37//=============================================================================================================
38// INCLUDES
39//=============================================================================================================
40
41#include "rt_cmd_client.h"
42
43//=============================================================================================================
44// QT INCLUDES
45//=============================================================================================================
46
47#include <QDateTime>
48#include <QThread>
49
50#include <iostream>
51
52constexpr bool USENEW = true;
53
54//=============================================================================================================
55// USED NAMESPACES
56//=============================================================================================================
57
58using namespace COMLIB;
59
60//=============================================================================================================
61// DEFINE MEMBER METHODS
62//=============================================================================================================
63
65: QTcpSocket(parent)
66{
67 QObject::connect(&m_commandManager, &CommandManager::triggered, this,
69}
70
71//=============================================================================================================
72
73QString RtCmdClient::sendCLICommand(const QString &p_sCommand)
74{
75 QString t_sCommand = QString("%1\n").arg(p_sCommand);
76 QString p_sReply;
77
78 if (this->state() == QAbstractSocket::ConnectedState)
79 {
80 this->write(t_sCommand.toUtf8().constData(), t_sCommand.size());
81 this->waitForBytesWritten();
82
83 //thats not the most elegant way
84 this->waitForReadyRead(1000);
85 QByteArray t_qByteArrayRaw;
86 // TODO(cpieloth): We need a break condition e.g. last byte == \0 or \n
87 // Large responses can be split to more than one packet which could be a problem on big network latencies.
88 while (this->bytesAvailable() > 0 && this->canReadLine())
89 t_qByteArrayRaw += this->readAll();
90
91 p_sReply = QString(t_qByteArrayRaw);
92 }
93 return p_sReply;
94}
95
96//=============================================================================================================
97
99{
100 const QString t_sCommand = QString("{\"commands\":{%1}}\n").arg(p_command.toStringReadySend());
101
102 QString t_sReply;
103
104 if (this->state() == QAbstractSocket::ConnectedState)
105 {
106 // Send request
107 if constexpr (USENEW)
108 {
109 QByteArray block;
110 QDataStream out(&block, QIODevice::WriteOnly);
111 out.setVersion(QDataStream::Qt_5_1);
112
113 out << static_cast<quint16>(0);
114 out << t_sCommand;
115 out.device()->seek(0);
116 out << static_cast<quint16>(static_cast<unsigned long>(block.size()) - sizeof(quint16));
117
118 this->write(block);
119 this->waitForBytesWritten();
120
121 // Receive response
122 QDataStream in(this);
123 in.setVersion(QDataStream::Qt_5_1);
124
125 quint16 blockSize = 0;
126
127 bool respComplete = false;
128
129 do
130 {
131 this->waitForReadyRead(100);
132
133 if (blockSize == 0)
134 {
135 if (this->bytesAvailable() >= static_cast<int>(sizeof(quint16)))
136 in >> blockSize;
137 }
138 else if(this->bytesAvailable() >= blockSize)
139 {
140 in >> t_sReply;
141 respComplete = true;
142 }
143 } while (!respComplete && blockSize < 65000);//Sanity Check -> allowed maximal blocksize is 65.000
144 }
145 else
146 {
147 this->write(t_sCommand.toUtf8().constData(), t_sCommand.size());
148 this->waitForBytesWritten();
149
150 // Receive response
151 bool respComplete = false;
152 QByteArray t_qByteArrayRaw;
153 do
154 {
155 if (this->waitForReadyRead(100))
156 {
157 t_qByteArrayRaw += this->readAll();
158 // We need a break condition,
159 // because we do not have a stop character and do not know how many bytes to receive.
160 respComplete = t_qByteArrayRaw.count('{')
161 == t_qByteArrayRaw.count('}');
162 }
163 qDebug() << "Response: " << t_qByteArrayRaw.size() << " bytes";
164 } while (!respComplete);
165 t_sReply = QString(t_qByteArrayRaw);
166 }
167 }
168 else
169 {
170 qWarning() << "Request was not send, because client is not connected!";
171 }
172
173 m_qMutex.lock();
174 m_sAvailableData = t_sReply;
175 m_qMutex.unlock();
176
177 emit response(t_sReply);
178}
179
180//=============================================================================================================
181
183{
184 //Send
185 m_commandManager["getbufsize"].send();
186
187 //Receive
188 m_qMutex.lock();
189 QByteArray t_sJsonCommands = m_sAvailableData.toUtf8();
190 m_qMutex.unlock();
191
192 //Parse
193 QJsonParseError error;
194 QJsonDocument t_jsonDocumentOrigin = QJsonDocument::fromJson(t_sJsonCommands, &error);
195
196 if (error.error == QJsonParseError::NoError)
197 {
198// qDebug() << t_jsonDocumentOrigin;//"Received Commands" << m_commandManager.commandMap().keys();
199
200 //Switch to command object
201 if(t_jsonDocumentOrigin.isObject() && t_jsonDocumentOrigin.object().value(QString("bufsize")) != QJsonValue::Undefined)
202 {
203 qint32 size = (qint32)t_jsonDocumentOrigin.object().value(QString("bufsize")).toDouble();
204 return size;
205 }
206 }
207
208 qCritical() << "Unable to parse JSON response: " << error.errorString();
209 return -1;
210}
211
212//=============================================================================================================
213
215{
216 //No commands are present -> thats why help has to be send using a self created command
217 const QString help("help");
218 const QString description("");
219 const Command cmdHelp(help, description);
220 this->sendCommandJSON(cmdHelp);
221
222 //Clear Commands
223 m_commandManager.clear();
224
225 //Receive
226 m_qMutex.lock();
227 QByteArray t_sJsonCommands = m_sAvailableData.toUtf8();
228 m_qMutex.unlock();
229
230 //Parse
231 QJsonParseError error;
232 QJsonDocument t_jsonDocumentOrigin = QJsonDocument::fromJson(
233 t_sJsonCommands, &error);
234
235 if (error.error == QJsonParseError::NoError)
236 m_commandManager.insert(t_jsonDocumentOrigin);
237 else
238 qCritical() << "Unable to parse JSON response: " << error.errorString();
239}
240
241//=============================================================================================================
242
243qint32 RtCmdClient::requestConnectors(QMap<qint32, QString> &p_qMapConnectors)
244{
245 //Send
246 m_commandManager["conlist"].send();
247
248 //Receive
249 m_qMutex.lock();
250 QByteArray t_sJsonConnectors = m_sAvailableData.toUtf8();
251 m_qMutex.unlock();
252
253 //Parse
254 QJsonParseError error;
255 QJsonDocument t_jsonDocumentOrigin = QJsonDocument::fromJson(
256 t_sJsonConnectors, &error);
257
258 QJsonObject t_jsonObjectConnectors;
259
260 //Switch to command object
261 if(t_jsonDocumentOrigin.isObject() && t_jsonDocumentOrigin.object().value(QString("connectors")) != QJsonValue::Undefined)
262 t_jsonObjectConnectors = t_jsonDocumentOrigin.object().value(QString("connectors")).toObject();
263
264 //inits
265 qint32 p_iActiveId = -1;
266 p_qMapConnectors.clear();
267
268 //insert connectors
269 QJsonObject::Iterator it;
270 for(it = t_jsonObjectConnectors.begin(); it != t_jsonObjectConnectors.end(); ++it)
271 {
272 QString t_qConnectorName = it.key();
273
274 qint32 id = it.value().toObject().value(QString("id")).toDouble();
275
276 if(!p_qMapConnectors.contains(id))
277 p_qMapConnectors.insert(id, t_qConnectorName);
278 else
279 qWarning("Warning: CommandMap contains command %s already. Insertion skipped.\n", it.key().toUtf8().constData());
280
281 //if connector is active indicate it
282 if(it.value().toObject().value(QString("active")).toBool())
283 p_iActiveId = id;
284 }
285
286 return p_iActiveId;
287}
288
290
291//void RtCmdClient::requestMeasInfo(qint32 p_id)
292//{
293// QString t_sCommand = QString("measinfo %1").arg(p_id);
294// this->sendCommand(t_sCommand);
295//}
296
298
299//void RtCmdClient::requestMeasInfo(const QString &p_Alias)
300//{
301// QString t_sCommand = QString("measinfo %1").arg(p_Alias);
302// this->sendCommand(t_sCommand);
303//}
304
306
307//void RtCmdClient::requestMeas(qint32 p_id)
308//{
309// QString t_sCommand = QString("start %1").arg(p_id);
310// this->sendCommand(t_sCommand);
311//}
312
314
315//void RtCmdClient::requestMeas(QString p_Alias)
316//{
317// QString t_sCommand = QString("start %1").arg(p_Alias);
318// this->sendCommand(t_sCommand);
319//}
320
322
323//void RtCmdClient::stopAll()
324//{
325// QString t_sCommand = QString("stop-all");
326// this->sendCommand(t_sCommand);
327//}
328
329//=============================================================================================================
330
331bool RtCmdClient::waitForDataAvailable(qint32 msecs) const
332{
333 if (m_sAvailableData.size() > 0)
334 return true;
335
336 qint64 t_msecsStart = QDateTime::currentMSecsSinceEpoch();
337
338 while (msecs == -1
339 || (qint64) msecs
340 < QDateTime::currentMSecsSinceEpoch() - t_msecsStart)
341 {
342 QThread::msleep(5);
343 if (m_sAvailableData.size() > 0)
344 return true;
345 }
346 return false;
347}
348
349//=============================================================================================================
350
352{
353 return m_commandManager[key];
354}
355
356//=============================================================================================================
357
358const Command RtCmdClient::operator[](const QString &key) const
359{
360 return m_commandManager[key];
361}
constexpr bool USENEW
Real-time client/server communication (commands, raw data streaming).
Command & operator[](const QString &key)
void sendCommandJSON(const Command &p_command)
qint32 requestConnectors(QMap< qint32, QString > &p_qMapConnectors)
RtCmdClient(QObject *parent=nullptr)
void response(QString p_sResponse)
QString sendCLICommand(const QString &p_sCommand)
bool waitForDataAvailable(qint32 msecs=30000) const
Named command with typed parameters for real-time server control.
Definition command.h:78
QString toStringReadySend() const
Definition command.cpp:237
void triggered(Command p_command)