148 строки
		
	
	
		
			3.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			148 строки
		
	
	
		
			3.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "cliconsole.h"
 | |
| 
 | |
| CLIConsole::CLIConsole(CLIHandler &cliHandler, std::string socketPath)
 | |
| {
 | |
| 	this->handler = &cliHandler;
 | |
| 	this->socketPath = socketPath;
 | |
| }
 | |
| 
 | |
| std::pair<bool, std::string> 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<bool, std::string> 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";
 | |
| }
 |