FlatBufferClient.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. #include "FlatBufferClient.h"
  2. // qt
  3. #include <QTcpSocket>
  4. #include <QHostAddress>
  5. #include <QTimer>
  6. #include <QRgb>
  7. FlatBufferClient::FlatBufferClient(QTcpSocket* socket, int timeout, QObject *parent)
  8. : QObject(parent)
  9. , _log(Logger::getInstance("FLATBUFSERVER"))
  10. , _socket(socket)
  11. , _clientAddress("@"+socket->peerAddress().toString())
  12. , _timeoutTimer(new QTimer(this))
  13. , _timeout(timeout * 1000)
  14. , _priority()
  15. {
  16. // timer setup
  17. _timeoutTimer->setSingleShot(true);
  18. _timeoutTimer->setInterval(_timeout);
  19. connect(_timeoutTimer, &QTimer::timeout, this, &FlatBufferClient::forceClose);
  20. // connect socket signals
  21. connect(_socket, &QTcpSocket::readyRead, this, &FlatBufferClient::readyRead);
  22. connect(_socket, &QTcpSocket::disconnected, this, &FlatBufferClient::disconnected);
  23. }
  24. void FlatBufferClient::readyRead()
  25. {
  26. _timeoutTimer->start();
  27. _receiveBuffer += _socket->readAll();
  28. // check if we can read a header
  29. while(_receiveBuffer.size() >= 4)
  30. {
  31. uint32_t messageSize =
  32. ((_receiveBuffer[0]<<24) & 0xFF000000) |
  33. ((_receiveBuffer[1]<<16) & 0x00FF0000) |
  34. ((_receiveBuffer[2]<< 8) & 0x0000FF00) |
  35. ((_receiveBuffer[3] ) & 0x000000FF);
  36. // check if we can read a complete message
  37. if((uint32_t) _receiveBuffer.size() < messageSize + 4) return;
  38. // extract message only and remove header + msg from buffer :: QByteArray::remove() does not return the removed data
  39. const QByteArray msg = _receiveBuffer.mid(4, messageSize);
  40. _receiveBuffer.remove(0, messageSize + 4);
  41. const auto* msgData = reinterpret_cast<const uint8_t*>(msg.constData());
  42. flatbuffers::Verifier verifier(msgData, messageSize);
  43. if (hyperionnet::VerifyRequestBuffer(verifier))
  44. {
  45. auto message = hyperionnet::GetRequest(msgData);
  46. handleMessage(message);
  47. continue;
  48. }
  49. sendErrorReply("Unable to parse message");
  50. }
  51. }
  52. void FlatBufferClient::forceClose()
  53. {
  54. _socket->close();
  55. }
  56. void FlatBufferClient::disconnected()
  57. {
  58. Debug(_log, "Socket Closed");
  59. _socket->deleteLater();
  60. if (_priority != 0 && _priority >= 100 && _priority < 200)
  61. emit clearGlobalInput(_priority);
  62. emit clientDisconnected();
  63. }
  64. void FlatBufferClient::handleMessage(const hyperionnet::Request * req)
  65. {
  66. const void* reqPtr;
  67. if ((reqPtr = req->command_as_Color()) != nullptr) {
  68. handleColorCommand(static_cast<const hyperionnet::Color*>(reqPtr));
  69. } else if ((reqPtr = req->command_as_Image()) != nullptr) {
  70. handleImageCommand(static_cast<const hyperionnet::Image*>(reqPtr));
  71. } else if ((reqPtr = req->command_as_Clear()) != nullptr) {
  72. handleClearCommand(static_cast<const hyperionnet::Clear*>(reqPtr));
  73. } else if ((reqPtr = req->command_as_Register()) != nullptr) {
  74. handleRegisterCommand(static_cast<const hyperionnet::Register*>(reqPtr));
  75. } else {
  76. sendErrorReply("Received invalid packet.");
  77. }
  78. }
  79. void FlatBufferClient::handleColorCommand(const hyperionnet::Color *colorReq)
  80. {
  81. // extract parameters
  82. const int32_t rgbData = colorReq->data();
  83. std::vector<ColorRgb> color{ ColorRgb{ uint8_t(qRed(rgbData)), uint8_t(qGreen(rgbData)), uint8_t(qBlue(rgbData)) } };
  84. // set output
  85. emit setGlobalInputColor(_priority, color, colorReq->duration());
  86. // send reply
  87. sendSuccessReply();
  88. }
  89. void FlatBufferClient::registationRequired(int priority)
  90. {
  91. if (_priority == priority)
  92. {
  93. auto reply = hyperionnet::CreateReplyDirect(_builder, nullptr, -1, -1);
  94. _builder.Finish(reply);
  95. // send reply
  96. sendMessage();
  97. _builder.Clear();
  98. }
  99. }
  100. void FlatBufferClient::handleRegisterCommand(const hyperionnet::Register *regReq)
  101. {
  102. if (regReq->priority() < 100 || regReq->priority() >= 200)
  103. {
  104. Error(_log, "Register request from client %s contains invalid priority %d. Valid priority for Flatbuffer connections is between 100 and 199.", QSTRING_CSTR(_clientAddress), regReq->priority());
  105. sendErrorReply("The priority " + std::to_string(regReq->priority()) + " is not in the priority range between 100 and 199.");
  106. return;
  107. }
  108. _priority = regReq->priority();
  109. emit registerGlobalInput(_priority, hyperion::COMP_FLATBUFSERVER, regReq->origin()->c_str()+_clientAddress);
  110. auto reply = hyperionnet::CreateReplyDirect(_builder, nullptr, -1, (_priority ? _priority : -1));
  111. _builder.Finish(reply);
  112. // send reply
  113. sendMessage();
  114. _builder.Clear();
  115. }
  116. void FlatBufferClient::handleImageCommand(const hyperionnet::Image *image)
  117. {
  118. // extract parameters
  119. int duration = image->duration();
  120. const void* reqPtr;
  121. if ((reqPtr = image->data_as_RawImage()) != nullptr)
  122. {
  123. const auto *img = static_cast<const hyperionnet::RawImage*>(reqPtr);
  124. const auto & imageData = img->data();
  125. const int width = img->width();
  126. const int height = img->height();
  127. if (width <= 0 || height <= 0)
  128. {
  129. sendErrorReply("Size of image data does not match with the width and height");
  130. return;
  131. }
  132. // check consistency of the size of the received data
  133. int channelCount = (int)imageData->size()/(width*height);
  134. if (channelCount != 3 && channelCount != 4)
  135. {
  136. sendErrorReply("Size of image data does not match with the width and height");
  137. return;
  138. }
  139. // create ImageRgb
  140. Image<ColorRgb> imageRGB(width, height);
  141. if (channelCount == 3)
  142. {
  143. memmove(imageRGB.memptr(), imageData->data(), imageData->size());
  144. }
  145. if (channelCount == 4)
  146. {
  147. for (int source=0, destination=0; source < width * height * static_cast<int>(sizeof(ColorRgb)); source+=sizeof(ColorRgb), destination+=sizeof(ColorRgba))
  148. {
  149. memmove((uint8_t*)imageRGB.memptr() + source, imageData->data() + destination, sizeof(ColorRgb));
  150. }
  151. }
  152. emit setGlobalInputImage(_priority, imageRGB, duration);
  153. emit setBufferImage("FlatBuffer", imageRGB);
  154. }
  155. // send reply
  156. sendSuccessReply();
  157. }
  158. void FlatBufferClient::handleClearCommand(const hyperionnet::Clear *clear)
  159. {
  160. // extract parameters
  161. const int priority = clear->priority();
  162. // Check if we are clearing ourselves.
  163. if (priority == _priority) {
  164. _priority = -1;
  165. }
  166. emit clearGlobalInput(priority);
  167. sendSuccessReply();
  168. }
  169. void FlatBufferClient::handleNotImplemented()
  170. {
  171. sendErrorReply("Command not implemented");
  172. }
  173. void FlatBufferClient::sendMessage()
  174. {
  175. auto size = _builder.GetSize();
  176. const uint8_t* buffer = _builder.GetBufferPointer();
  177. uint8_t sizeData[] = {uint8_t(size >> 24), uint8_t(size >> 16), uint8_t(size >> 8), uint8_t(size)};
  178. _socket->write((const char *) sizeData, sizeof(sizeData));
  179. _socket->write((const char *)buffer, size);
  180. _socket->flush();
  181. }
  182. void FlatBufferClient::sendSuccessReply()
  183. {
  184. auto reply = hyperionnet::CreateReplyDirect(_builder);
  185. _builder.Finish(reply);
  186. // send reply
  187. sendMessage();
  188. _builder.Clear();
  189. }
  190. void FlatBufferClient::sendErrorReply(const std::string &error)
  191. {
  192. // create reply
  193. auto reply = hyperionnet::CreateReplyDirect(_builder, error.c_str());
  194. _builder.Finish(reply);
  195. // send reply
  196. sendMessage();
  197. _builder.Clear();
  198. }