#include "cliconsole.h" CLIConsole::CLIConsole(CLIHandler &cliHandler, std::string socketPath) { this->handler = &cliHandler; this->socketPath = socketPath; } std::pair CLIConsole::send(std::string input) { ssize_t ret = sendto(this->sock, input.c_str(), input.size(), 0, (const sockaddr *)&this->server, sizeof(this->server)); if((size_t)ret != input.size()) { return {false, "sendto failed: " + std::to_string(ret) + " " + std::string(strerror(errno))}; } char buffer[1024] = {0}; ret = recvfrom(this->sock, buffer, sizeof(buffer) - 1, 0, NULL, NULL); if(ret == -1) { return {false, "recvfrom failed: " + std::string(strerror(errno))}; } bool success = false; std::string_view view = buffer; if(view[0] == '1') { success = true; } view.remove_prefix(1); std::string msg = std::string{view}; return {success, msg}; } void CLIConsole::attach() { if(attached) { std::cout << "Already attached" << std::endl; return; } if(socketPath.size() > sizeof(this->server.sun_path) - 1) { std::cout << "Socket path too long" << std::endl; return; } memset(&this->server, 0, sizeof(this->server)); this->server.sun_family = AF_UNIX; memcpy(&this->server.sun_path, socketPath.c_str(), socketPath.size()); this->server.sun_path[socketPath.size()] = 0; int s = socket(AF_UNIX, SOCK_DGRAM, 0); if(s == -1) { std::cout << "Failed to create socket" << strerror(errno) << std::endl; return; } this->sock = s; struct sockaddr_un client; client.sun_family = AF_UNIX; client.sun_path[0] = '\0'; int ret = bind(this->sock, (struct sockaddr *)&client, sizeof(client)); if(ret != 0) { std::cout << "bind() failed: " << strerror(errno) << std::endl; return; } auto result = this->send("attach"); if(result.first) { std::cout << "Attached successfully: " << result.second << std::endl; this->attached = true; } else { std::cout << "Attached unsuccessfully: " << result.second << std::endl; } } void CLIConsole::startInteractive() { std::cout << "qswiki CLI" << std::endl; std::cout << "not attached - use 'attach' to connect to running instance" << std::endl; while(true) { std::string input; std::cout << "> "; std::getline(std::cin, input); if(std::cin.bad() || std::cin.eof()) { std::cout << "Exiting" << std::endl; return; } if(input.empty()) { continue; } auto pair = CLIHandler::splitCommand(input); if(pair.first == "exit") { if(attached) { std::cout << "You are attached. Quit attached instance too (y) or only this one(n)" << std::endl; char response; std::cin >> response; if(response == 'y') { this->send("exit"); } } std::cout << "Exiting CLI" << std::endl; exit(EXIT_SUCCESS); } if(pair.first == "attach") { attach(); continue; } std::pair result; if(!attached) { result = handler->processCommand(pair.first, pair.second); } else { result = this->send(input); } if(!result.second.empty()) { std::cout << result.second << std::endl; } if(!result.first) { std::cout << "Command failed" << std::endl; } } std::cout << "\n"; }