#include #include #include #include #include #include #include #include using namespace std; string load_file(const string& path) { ifstream f(path); stringstream buffer; buffer << f.rdbuf(); return buffer.str(); } bool is_service_active(string_view service_name) { const string cmd = format("systemctl is-active --quiet {}", service_name); return system(cmd.c_str()) == 0; } bool is_service_enabled(string_view service_name) { const string cmd = format("systemctl is-enabled --quiet {}", service_name); return system(cmd.c_str()) == 0; } void toggle_service(string_view serviceName){ string_view toggle = is_service_active(serviceName) ? "stop" : "start"; const string cmd = format("systemctl {} {}", toggle, serviceName); system(cmd.c_str()); } string_view get_button_class(bool isActive) { return isActive ? "active-button" : "inactive-button"; } optional get_body_name(const string& body) { const auto pos = body.find('='); if (pos == std::string::npos) return {}; const string key = body.substr(0, pos); string value = body.substr(pos + 1); if (key != "name") return {}; return value; } string create_htmx_button(string_view endpoint, string_view serviceName, string_view text) { return format( "\ \ {} \ \ ", endpoint, serviceName, text); } string create_htmx_table_row(string_view serviceName){ const bool isRunning = is_service_active(serviceName); const bool isEnabled = is_service_active(serviceName); const auto running = isRunning ? "Running" : "Stopped"; const auto enabled = isEnabled ? "Enabled" : "Disabled"; // create status indicators string html = format( "\ {}\ {}\ {}", serviceName, get_button_class(isRunning), running, get_button_class(isEnabled), enabled); // create buttons html += create_htmx_button("/toggle-service", serviceName, isRunning ? "Stop" : "Start"); html += create_htmx_button("/enable-service", serviceName, isEnabled ? "Disable" : "Enable"); html += create_htmx_button("/restart-service", serviceName, "Restart"); return html; } const array& get_service_names() { static const array arr = { "cups.service" }; return arr; } int main() { crow::SimpleApp app; CROW_ROUTE(app, "/")([] { return crow::response(load_file("templates/index.html")); }); CROW_ROUTE(app, "/static/")([](const std::string& file) { return crow::response(load_file("static/" + file)); }); CROW_ROUTE(app, "/status")([] { auto names = get_service_names(); // define the table header string html = "\ \ \ \ "; // display each service as an entry for (auto& serviceName : names) { html += create_htmx_table_row(serviceName); } html += "
ServiceStatusState
"; return crow::response{html}; }); CROW_ROUTE(app, "/toggle-service").methods(crow::HTTPMethod::Post)([](const crow::request& req) { auto body = get_body_name(req.body); if (!body.has_value()) return crow::response(400); const string& serviceName = body.value(); toggle_service(serviceName); const string html = create_htmx_table_row(serviceName); return crow::response{html}; }); app.port(8080).multithreaded().run(); }