/* * CommandParser.cpp * * Copyright (C) 2008 Matthias Schiffer * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #include "CommandParser.h" #include "Requests/CoreStatusRequest.h" #include "Requests/DaemonListRequest.h" #include "Requests/DaemonStatusRequest.h" #include #include #include #include #include #include namespace Mad { namespace Client { const CommandParser::Command CommandParser::commands[] = { {{"help", "?", 0}, "help [command]", "Displays usage information about commands", "Displays usage information about a command. If no command is given, a list of all available commands is displayed.", &CommandParser::helpCommand}, {{"list_hosts", "hosts", 0}, "list_hosts", "Lists the currently active hosts", "Lists the currently active hosts", &CommandParser::listHostsCommand}, {{"status", "st", 0}, "status [host]", "Displays status information", "Displays host status information. If no host is given, server status information is displayed.", &CommandParser::statusCommand}, {{"exit", "quit", 0}, "exit", "Closes the connection and quits the client", "Closes the connection and quits the client.", &CommandParser::exitCommand}, {{0}, 0, 0, 0, 0} }; const CommandParser::Command* CommandParser::findCommand(const std::string& command) { for(int i = 0; commands[i].commands[0] != 0; ++i) { for(int j = 0; commands[i].commands[j] != 0; ++j) { if(command == commands[i].commands[j]) { return &commands[i]; } } } return 0; } void CommandParser::printUsage(const std::string& command) { const CommandParser::Command *cmd = findCommand(command); if(cmd) std::cerr << "Usage: " << cmd->cmdline << std::endl << std::endl; } void CommandParser::printHostStatus(const Net::Packets::HostStatusPacket &packet) { if(packet.getUptime()) { unsigned long days = packet.getUptime()/86400; unsigned long hours = (packet.getUptime()%86400)/3600; unsigned long minutes = (packet.getUptime()%3600)/60; std::printf("\tUptime:\t\t"); if(days) std::printf("%lu days ", days); std::printf("%lu:%02lu", hours, minutes); if(packet.getIdleTime()) std::printf(" (load average: %.1f%%)", 100.0f-(packet.getIdleTime()*100.0f/packet.getUptime())); std::printf("\n\n"); } if(packet.getTotalMem() && packet.getFreeMem()) { const std::string units[] = { "kB", "MB", "GB", "TB", "" }; unsigned unit = 0; float totalMem = packet.getTotalMem(), usedMem = packet.getTotalMem()-packet.getFreeMem(); while(totalMem >= 1024 && !units[unit+1].empty()) { ++unit; totalMem /= 1024; usedMem /= 1024; } std::printf("\tMemory usage:\t%.*f/%.*f %s", (usedMem < 10) ? 2 : 1, usedMem, (totalMem < 10) ? 2 : 1, totalMem, units[unit].c_str()); std::printf(" (%.1f%%)\n", usedMem*100.0f/totalMem); if(packet.getTotalSwap() && packet.getFreeSwap()) { unit = 0; totalMem = packet.getTotalSwap(); usedMem = packet.getTotalSwap()-packet.getFreeSwap(); while(totalMem >= 1024 && !units[unit+1].empty()) { ++unit; totalMem /= 1024; usedMem /= 1024; } std::printf("\tSwap usage:\t%.*f/%.*f %s", (usedMem < 10) ? 2 : 1, usedMem, (totalMem < 10) ? 2 : 1, totalMem, units[unit].c_str()); std::printf(" (%.1f%%)\n", usedMem*100.0f/totalMem); } std::printf("\n"); } } void CommandParser::helpCommand(const std::vector &args) { if(args.size() == 1) { std::cout << "Available commands:" << std::endl << std::endl; for(int i = 0; commands[i].commands[0] != 0; ++i) { std::cout << commands[i].commands[0]; for(int j = 1; commands[i].commands[j] != 0; ++j) std::cout << ", " << commands[i].commands[j]; std::cout << std::endl << "\t" << commands[i].desc << std::endl; } } else if(args.size() == 2) { const Command* command = findCommand(args[1]); if(command) { std::cout << "Usage: " << command->cmdline << std::endl << std::endl; std::cout << command->longdesc << std::endl << std::endl; } else std::cerr << args[0] << ": Command '" << args[1] << "' doesn't exist." << std::endl << std::endl; } else { std::cerr << args[0] << ": Too many arguments." << std::endl; printUsage("help"); } } void CommandParser::listHostsCommand(const std::vector&) { activeRequests++; Requests::DaemonListRequest::send(connection, sigc::mem_fun(this, &CommandParser::daemonListRequestFinished)); } void CommandParser::statusCommand(const std::vector &args) { if(args.size() == 1) Requests::CoreStatusRequest::send(connection, sigc::mem_fun(this, &CommandParser::coreStatusRequestFinished)); else if(args.size() == 2) Requests::DaemonStatusRequest::send(connection, sigc::mem_fun(this, &CommandParser::daemonStatusRequestFinished), sigc::mem_fun(this, &CommandParser::errorCallback), args[1]); else { std::cerr << args[0] << ": Too many arguments." << std::endl; printUsage("status"); return; } activeRequests++; } void CommandParser::exitCommand(const std::vector&) { activeRequests++; disconnect = true; Common::Requests::DisconnectRequest::send(connection, sigc::mem_fun(this, &CommandParser::requestFinished)); } void CommandParser::coreStatusRequestFinished(const Net::Packets::HostStatusPacket &packet) { std::cout << "Server status:" << std::endl; printHostStatus(packet); requestFinished(); } void CommandParser::daemonListRequestFinished(const Net::Packets::NameListPacket &packet) { const std::vector& hosts = packet.getNameList(); if(hosts.empty()) { std::cout << "There aren't any active hosts." << std::endl << std::endl; } else { std::cout << "Active hosts:" << std::endl; for(std::vector::const_iterator host = hosts.begin(); host != hosts.end(); ++host) std::cout << "\t" << *host << std::endl; std::cout << std::endl; } requestFinished(); } void CommandParser::daemonStatusRequestFinished(const Net::Packets::HostStatusPacket &packet) { std::cout << "Host status:" << std::endl; printHostStatus(packet); requestFinished(); } void CommandParser::errorCallback(const Common::Exception &exception) { std::cerr << "An error occurred during your request." << std::endl; std::cerr << "Error code: " << exception.getErrorCode() << std::endl << std::endl; requestFinished(); } bool CommandParser::split(const std::string &str, std::vector &ret) { std::string temp; bool quoteSingle = false, quoteDouble = false, escape = false; size_t beg = 0; for(size_t cur = 0; cur < str.length(); ++cur) { if(!escape) { if(str[cur] == ' ' && !quoteSingle && !quoteDouble) { if(cur == beg && temp.empty()) { ++beg; } else { temp += str.substr(beg, cur-beg); ret.push_back(temp); temp.clear(); beg = cur+1; } continue; } if(str[cur] == '"' && !quoteSingle) { temp += str.substr(beg, cur-beg); beg = cur+1; quoteDouble = !quoteDouble; continue; } if(str[cur] == '\'' && !quoteDouble) { temp += str.substr(beg, cur-beg); beg = cur+1; quoteSingle = !quoteSingle; continue; } if(str[cur] == '\\') { escape = true; continue; } } if(escape && ((!quoteSingle && !quoteDouble) || (quoteSingle && str[cur] == '\'') || (quoteDouble && (str[cur] == '"' || str[cur] == '\\')))) { temp += str.substr(beg, cur-beg-1); beg = cur; } escape = false; } temp += str.substr(beg, std::string::npos); ret.push_back(temp); return true; } bool CommandParser::parse(const std::string &cmd) { std::vector splitCmd; split(cmd, splitCmd); if(splitCmd.empty()) return true; const Command* command = findCommand(splitCmd[0]); if(command) (this->*command->funcPtr)(splitCmd); else std::cerr << "Unknown command '" << splitCmd[0] << "'." << std::endl << std::endl; return true; } } }