#include #include #include #include #include #include #include #include #include #include #include "qmlhandler.h" #include #include #include using boost::asio::buffer; using namespace std; int inpipefd[2]; int outpipefd[2]; char buf[1025]; QUrl sendFileUrl = QUrl(""); bool programActive = true; QMLHandler::QMLHandler(QObject *parent) : QObject(parent) {} void QMLHandler::onExit() { write(outpipefd[1], "disconnect\n", strlen("disconnect\n")); } // This method gets a string and tries to read it as Json // If it fails to do so, return and do nothing, else handle the content void QMLHandler::handleJSON(string buffer) { Json::Value root; Json::CharReaderBuilder builder; Json::CharReader *reader = builder.newCharReader(); string jsonError; // Try to parse the string as Json and store the result of the pasring in a // boolean bool parsingSuccessful = reader->parse( buffer.c_str(), buffer.c_str() + buffer.size(), &root, &jsonError); // If the string is not correct Json, return if (!parsingSuccessful) { return; } const Json::Value command = root["command"]; string cmd = command.asString(); if (cmd == "status") { emit footerSetStatus(root["response"].asString().c_str()); } else if (cmd == "close") { programActive = false; } else if (cmd == "list") { emit receivingClearFileList(); // Get the array of file Names auto fileNames = root["names"]; for (int i = 0; i < fileNames.size(); i++) { emit receivingListFile( QString::fromStdString(fileNames[i].asString().c_str())); } } } // This method is a loop which runs in a seperate thread. // If will read the Input Pipe, which containts the string that get printed // on stdout by the CLI/Server, and calls handleJSON with the read content // one it reads a newline. void QMLHandler::readPipeLoop() { unsigned int readOffset = 0; unsigned int pollCount = 0; struct pollfd inPipeStatus; inPipeStatus.fd = inpipefd[0]; inPipeStatus.events = POLLIN; while (programActive) { poll(&inPipeStatus, 1, 100); if (inPipeStatus.revents & POLLIN) { readOffset += read(inpipefd[0], buf + readOffset, 1); pollCount = 0; } else { pollCount++; } if (pollCount > 9 && buf[0]) { buf[1024] = 0; buf[strlen(buf)] = 0; string cleanBuffer = buf + strcspn(buf, "\n") + 1; string receivedData = cleanBuffer.substr(0, cleanBuffer.size() - 1); emit log(QString::fromStdString(receivedData)); qInfo() << QString::fromStdString(receivedData); handleJSON(receivedData); memset(buf, 0, 1024); pollCount = 0; readOffset = 0; } } } // ### QML Handlers ### // Sending void QMLHandler::onSendingSelectFileButton(QUrl url) { sendFileUrl = url.toLocalFile(); emit log("File Selected: " + sendFileUrl.toString()); emit sendingSetFileUrlText("Selected File: " + sendFileUrl.toString()); emit sendingEnableSendButton(); } void QMLHandler::onSendingSendFileButton() { QString command = "put " + sendFileUrl.toString() + "\n"; write(outpipefd[1], command.toUtf8().constData(), strlen(command.toUtf8().constData())); } void QMLHandler::onSendingClearSelectionButton() { sendFileUrl = QUrl(""); emit log("Cleared Selection"); emit sendingSetFileUrlText("Selected File: None"); emit sendingDisableSendButton(); } // Receiving void QMLHandler::onReceivingListFilesButton() { write(outpipefd[1], "list\n", strlen("list\n")); } void QMLHandler::onReceivingGetFileButton(QString fileName) { QString command = "get " + fileName + "\n"; write(outpipefd[1], command.toUtf8().constData(), strlen(command.toUtf8().constData())); } // Messages void QMLHandler::onMessagesSendButton(QString msg) { emit message(msg); } // Settings void QMLHandler::onSettingsSwitchServerButton() { emit settingsOpenSwitchServerPopup(); } // Ip Popup void QMLHandler::onIpPopupEnterIp(QString ip) { pid_t pid = 0; pipe(inpipefd); pipe(outpipefd); pid = fork(); if (pid == 0) { // Child dup2(outpipefd[0], STDIN_FILENO); dup2(inpipefd[1], STDOUT_FILENO); // dup2(inpipefd[1], STDERR_FILENO); // ask kernel to deliver SIGTERM in case the parent dies prctl(PR_SET_PDEATHSIG, SIGTERM); // Set the path to the CLI - pass argument h (help) for now // TODO: Change hardcoded path execl("../../cli/build/ccats-cli", "ccats-cli", ip.toUtf8().constData(), "--machine", (char *)NULL); exit(1); } // TODO: Not hardcoded emit footerSetStatus("Connected to " + ip); close(outpipefd[0]); close(inpipefd[1]); std::thread(&QMLHandler::readPipeLoop, this).detach(); } // Switch Popup void QMLHandler::onSwitchPopupEnterIp(QString ip) { qInfo() << "Switching to " << ip; } // Footer void QMLHandler::onFooterGetStatusButton() { write(outpipefd[1], "status\n", strlen("status\n")); }