qmlhandler.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. #include <QGuiApplication>
  2. #include <csignal>
  3. #include <cstdio>
  4. #include <cstdlib>
  5. #include <iostream>
  6. #include <poll.h>
  7. #include <sys/prctl.h>
  8. #include <sys/wait.h>
  9. #include <thread>
  10. #include <unistd.h>
  11. #include "qmlhandler.h"
  12. #include <boost/asio.hpp>
  13. #include <iostream>
  14. #include <json/json.h>
  15. using boost::asio::buffer;
  16. using namespace std;
  17. int inpipefd[2];
  18. int outpipefd[2];
  19. char buf[1025];
  20. QUrl sendFileUrl = QUrl("");
  21. bool programActive = true;
  22. QMLHandler::QMLHandler(QObject *parent) : QObject(parent) {}
  23. void QMLHandler::onExit() {
  24. write(outpipefd[1], "disconnect\n", strlen("disconnect\n"));
  25. }
  26. // This method gets a string and tries to read it as Json
  27. // If it fails to do so, return and do nothing, else handle the content
  28. void QMLHandler::handleJSON(string buffer) {
  29. Json::Value root;
  30. Json::CharReaderBuilder builder;
  31. Json::CharReader *reader = builder.newCharReader();
  32. string jsonError;
  33. // Try to parse the string as Json and store the result of the pasring in a
  34. // boolean
  35. bool parsingSuccessful = reader->parse(
  36. buffer.c_str(), buffer.c_str() + buffer.size(), &root, &jsonError);
  37. // If the string is not correct Json, return
  38. if (!parsingSuccessful) {
  39. return;
  40. }
  41. const Json::Value command = root["command"];
  42. string cmd = command.asString();
  43. if (cmd.compare("status")) {
  44. emit footerSetStatus(root["response"].asString().c_str());
  45. }
  46. else if (cmd.compare("close")) {
  47. programActive = false;
  48. }
  49. else if (cmd.compare("listdata")) {
  50. emit receivingClearFileList();
  51. // Get the array of file Names
  52. auto fileNames = root["names"];
  53. for (int i = 0; i < fileNames.size(); i++) {
  54. emit receivingListFile(
  55. QString::fromStdString(fileNames[i].asString().c_str()));
  56. }
  57. }
  58. else if (cmd.compare("version")) {
  59. // TODO: Change hardcoded login details to input values
  60. write(outpipefd[1], "user\n", strlen("user\n"));
  61. write(outpipefd[1], "pass\n", strlen("pass\n"));
  62. }
  63. }
  64. // This method is a loop which runs in a seperate thread.
  65. // If will read the Input Pipe, which containts the string that get printed
  66. // on stdout by the CLI/Server, and calls handleJSON with the read content
  67. // one it reads a newline.
  68. void QMLHandler::readPipeLoop() {
  69. unsigned int readOffset = 0;
  70. unsigned int pollCount = 0;
  71. struct pollfd inPipeStatus;
  72. inPipeStatus.fd = inpipefd[0];
  73. inPipeStatus.events = POLLIN;
  74. while (programActive) {
  75. poll(&inPipeStatus, 1, 100);
  76. if (inPipeStatus.revents & POLLIN) {
  77. readOffset += read(inpipefd[0], buf + readOffset, 1);
  78. if (buf[readOffset - 1] == '\n') {
  79. pollCount = 10;
  80. } else {
  81. pollCount = 0;
  82. }
  83. pollCount = 0;
  84. } else {
  85. pollCount++;
  86. }
  87. if (pollCount > 9 && readOffset > 0) {
  88. buf[strnlen(buf, 1024)] = 0;
  89. string receivedData = buf;
  90. emit log(QString::fromStdString(receivedData));
  91. qInfo() << QString::fromStdString(receivedData);
  92. handleJSON(receivedData);
  93. memset(buf, 0, 1024);
  94. pollCount = 0;
  95. readOffset = 0;
  96. }
  97. // Fixme
  98. if (readOffset >= 1024) {
  99. qInfo() << "Fixme: QMLHandler::readPipeLoop() readOffset too high!!!";
  100. readOffset = 0;
  101. pollCount = 0;
  102. memset(buf, 0, 1025);
  103. }
  104. }
  105. }
  106. // ### QML Handlers ###
  107. // Sending
  108. void QMLHandler::onSendingSelectFileButton(QUrl url) {
  109. sendFileUrl = url.toLocalFile();
  110. emit log("File Selected: " + sendFileUrl.toString());
  111. emit sendingSetFileUrlText("Selected File: " + sendFileUrl.toString());
  112. emit sendingEnableSendButton();
  113. }
  114. void QMLHandler::onSendingSendFileButton() {
  115. QString command = "put " + sendFileUrl.toString() + "\n";
  116. write(outpipefd[1], command.toUtf8().constData(),
  117. strlen(command.toUtf8().constData()));
  118. }
  119. void QMLHandler::onSendingClearSelectionButton() {
  120. sendFileUrl = QUrl("");
  121. emit log("Cleared Selection");
  122. emit sendingSetFileUrlText("Selected File: None");
  123. emit sendingDisableSendButton();
  124. }
  125. // Receiving
  126. void QMLHandler::onReceivingListFilesButton() {
  127. write(outpipefd[1], "list\n", strlen("list\n"));
  128. }
  129. void QMLHandler::onReceivingGetFileButton(QString fileName) {
  130. QString command = "get " + fileName + "\n";
  131. write(outpipefd[1], command.toUtf8().constData(),
  132. strlen(command.toUtf8().constData()));
  133. }
  134. // Messages
  135. void QMLHandler::onMessagesSendButton(QString msg) { emit message(msg); }
  136. // Settings
  137. void QMLHandler::onSettingsSwitchServerButton() {
  138. emit settingsOpenSwitchServerPopup();
  139. }
  140. // Ip Popup
  141. void QMLHandler::onIpPopupEnterIp(QString ip) {
  142. pid_t pid = 0;
  143. pipe(inpipefd);
  144. pipe(outpipefd);
  145. pid = fork();
  146. if (pid == 0) {
  147. // Child
  148. dup2(outpipefd[0], STDIN_FILENO);
  149. dup2(inpipefd[1], STDOUT_FILENO);
  150. // dup2(inpipefd[1], STDERR_FILENO);
  151. // ask kernel to deliver SIGTERM in case the parent dies
  152. prctl(PR_SET_PDEATHSIG, SIGTERM);
  153. // Set the path to the CLI - pass argument h (help) for now
  154. // TODO: Change hardcoded path
  155. execl("../../cli/build/ccats-cli", "ccats-cli", ip.toUtf8().constData(),
  156. "--machine", (char *)NULL);
  157. exit(1);
  158. }
  159. // TODO: Not hardcoded
  160. emit footerSetStatus("Connected to " + ip);
  161. close(outpipefd[0]);
  162. close(inpipefd[1]);
  163. std::thread(&QMLHandler::readPipeLoop, this).detach();
  164. }
  165. // Switch Popup
  166. void QMLHandler::onSwitchPopupEnterIp(QString ip) {
  167. qInfo() << "Switching to " << ip;
  168. }
  169. // Footer
  170. void QMLHandler::onFooterGetStatusButton() {
  171. write(outpipefd[1], "status\n", strlen("status\n"));
  172. }