#include "command_registry.hpp" #include "config.hpp" #include "utils/utils.hpp" #include "utils/directories.hpp" #include "shared_commands.hpp" #include "servers.hpp" #include "tableprint.hpp" #include "transwarp.hpp" #include #include #include #include #include #include "utils/assert.hpp" namespace dropshell { int list_handler(const CommandContext& ctx); void show_server_details(const std::string& server_name); void list_servers(); static std::vector list_name_list={"list","ls","info","-l"}; // Static registration struct ListCommandRegister { ListCommandRegister() { CommandRegistry::instance().register_command({ list_name_list, list_handler, std_autocomplete, false, // hidden true, // requires_config true, // requires_install 0, // min_args (after command) 2, // max_args (after command) "list [SERVER] [SERVICE]", "List server or service information and status", // heredoc R"( List details for servers and services controller by dropshell. list list all servers. list server list all services for the given server. list server service list the given service details on the given server. )" }); } } list_command_register; // ------------------------------------------------------------------------------------------------ // list command handler // ------------------------------------------------------------------------------------------------ int list_handler(const CommandContext& ctx) { if (ctx.args.size() == 0) { list_servers(); return 0; } if (ctx.args.size() == 1) { show_server_details(ctx.args[0]); return 0; } std::cout << "List handler called with " << ctx.args.size() << " args\n"; return 0; } // https://github.com/bloomen/transwarp?tab=readme-ov-file#range-functions void list_servers() { auto servers = get_configured_servers(); if (servers.empty()) { std::cout << "No servers found" << std::endl; std::cout << "Please run 'dropshell edit' to set up dropshell." << std::endl; std::cout << "Then run 'dropshell create-server' to create a server." << std::endl; return; } tableprint tp("All DropShell Servers"); tp.add_row({"Name", "User", "Address", "Health", "Ports"}); std::cout << "Checking "< status = service_runner::get_all_services_status(server.name); std::set ports_used; std::string serviceticks = ""; for (const auto& [service_name, service_status] : status) { ports_used.insert(service_status.ports.begin(), service_status.ports.end()); serviceticks += HealthStatus2String(service_status.health) + " "; } std::string ports_used_str = ""; for (const auto& port : ports_used) ports_used_str += std::to_string(port) + " "; tp.add_row({server.name, server.ssh_user, server.ssh_host, serviceticks, ports_used_str}); ++checked; // print out a tick character for each server checked. std::cout << checked << " ✓ " << std::flush; }); task->wait(); std::cout << std::endl << std::endl; tp.print(); } void show_server_details(const std::string& server_name) { server_env_manager env(server_name); if (!env.is_valid()) { std::cerr << "Error: Invalid server environment file: " << server_name << std::endl; return; } //--------------------- // Check if server is reachable via SSH std::string ssh_address = env.get_SSH_HOST(); std::string ssh_user = env.get_SSH_USER(); std::string ssh_port = env.get_SSH_PORT(); if (!ssh_address.empty()) { std::cout << std::endl << "Server Status:" << std::endl; std::cout << std::string(40, '-') << std::endl; // Try to connect to the server std::string cmd = "ssh -o ConnectTimeout=5 " + ssh_user + "@" + ssh_address + " -p " + ssh_port + " 'echo connected' 2>/dev/null"; int result = system(cmd.c_str()); if (result == 0) { std::cout << "Status: Online" << std::endl; // // Get uptime if possible // cmd = "ssh " + ssh_address + " 'uptime' 2>/dev/null"; // int rval = system(cmd.c_str()); // if (rval != 0) { // std::cout << "Error: Failed to get uptime" << std::endl; // } } else { std::cout << "Status: Offline" << std::endl; } } std::cout << std::endl; //--------------------- { std::cout << std::endl; tableprint tp("Server Configuration: " + server_name, true); tp.add_row({"Key", "Value"}); for (const auto& [key, value] : env.get_variables()) { tp.add_row({key, value}); } tp.print(); } //--------------------- // list services, and run healthcheck on each { tableprint tp("Services: " + server_name, false); tp.add_row({"Status", "Service", "Ports"}); std::map status = service_runner::get_all_services_status(server_name); std::set ports_used; std::string serviceticks = ""; for (const auto& [service_name, service_status] : status) { std::string healthy = HealthStatus2String(service_status.health); std::string ports_str = ""; for (const auto& port : service_status.ports) ports_str += std::to_string(port) + " "; tp.add_row({healthy, service_name, ports_str}); } // end of for (const auto& service : services) tp.print(); } // end of list services } // end of show_server_details } // namespace dropshell