dropshell/src/servers.cpp
2025-04-23 21:50:04 +12:00

195 lines
6.1 KiB
C++

#include "servers.hpp"
#include "server_env.hpp"
#include "service_runner.hpp"
#include "tableprint.hpp"
#include "interactive/interactive.hpp"
#include "utils/envmanager.hpp"
#include "utils/directories.hpp"
#include "services.hpp"
#include <iostream>
#include <fstream>
#include <iomanip>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
namespace fs = boost::filesystem;
namespace dropshell {
std::vector<ServerInfo> get_configured_servers() {
std::vector<ServerInfo> servers;
std::string servers_dir = get_local_config_servers_path();
if (servers_dir.empty()) {
std::cerr << "Error: Servers directory not found" << std::endl;
return servers;
}
if (!fs::exists(servers_dir)) {
std::cerr << "Error: Servers directory not found:" << servers_dir << std::endl;
return servers;
}
for (const auto& entry : fs::directory_iterator(servers_dir)) {
if (fs::is_directory(entry)) {
std::string server_name = entry.path().filename().string();
server_env env(server_name);
if (!env.is_valid()) {
std::cerr << "Error: Invalid server environment file: " << server_name << std::endl;
continue;
}
servers.push_back({
server_name,
env.get_SSH_HOST(),
env.get_SSH_USER(),
env.get_SSH_PORT()
});
}
}
return servers;
}
void interactive_mode() {
interactive::fullscreen_window iw("DropShell Servers");
iw.set_input_text_display("Loading all servers' status...");
auto servers = get_configured_servers();
std::vector<std::string> server_names;
for (const auto& server : servers) {
server_names.push_back(server.name);
}
list_servers();
while (true) {
std::string server_name = iw.set_input_multiple_choice("Select a server", server_names);
if (server_name.empty())
{
iw.close();
return;
}
while (!server_name.empty()) {
iw.clear_display();
show_server_details(server_name);
server_name = iw.set_input_multiple_choice("Select a server", server_names, server_name);
}
iw.clear_display();
list_servers();
}
}
void list_servers() {
auto servers = get_configured_servers();
tableprint tp("All DropShell Servers");
tp.add_row({"Name", "Address", "Health", "Ports"});
for (const auto& server : servers) {
std::vector<int> ports_used;
std::string serviceticks = "";
std::vector<ServiceInfo> services = get_server_services_info(server.name);
for (const auto& service : services) {
service_runner ss;
if (ss.init(server.name, service.service_name))
{
if (ss.is_healthy())
serviceticks += ":tick: ";
else
serviceticks += ":cross: ";
}
std::vector<int> ports = ss.get_ports();
ports_used.insert(ports_used.end(), ports.begin(), ports.end());
}
// convert ports_used to string
std::string ports_used_str = "";
bool first = true;
for (const auto& port : ports_used) {
if (!first) {
ports_used_str += ", ";
}
ports_used_str += std::to_string(port);
first = false;
}
tp.add_row({server.name, server.ssh_host, serviceticks, ports_used_str});
}
tp.print();
}
void show_server_details(const std::string& server_name) {
server_env 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();
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_address + " '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;
//---------------------
{
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::vector<ServiceInfo> services = get_server_services_info(server_name);
for (const auto& service : services) {
bool healthy = false;
std::vector<int> ports;
service_runner ss;
if (ss.init(server_name, service.service_name))
{
if (ss.is_healthy())
healthy=true;
ports = ss.get_ports();
}
bool first = true;
std::string ports_str = "";
for (const auto& port : ports) {
if (!first) {
ports_str += ", ";
}
ports_str += std::to_string(port);
first = false;
}
tp.add_row({healthy ? ":tick:" : ":cross:", service.service_name, ports_str});
} // end of for (const auto& service : services)
tp.print();
} // end of list services
} // end of show_server_details
} // namespace dropshell