#include #include #include #include #include #include "json_settings.h" #include "htmx_helper.h" #include "systemd.h" #include "utils.hpp" #include "ShadowrunApi.hpp" using namespace std; 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; } int main() { crow::SimpleApp app; CROW_ROUTE(app, "/")([] { return crow::response(utils::loadFile("templates/index.html")); }); CROW_ROUTE(app, "/static/")([](const std::string& file) { return crow::response(utils::loadFile("static/" + file)); }); CROW_ROUTE(app, "/templates/")([](const std::string& file) { return crow::response(utils::loadFile("templates/" + file)); }); // Static file redirector CROW_ROUTE(app, "/redirect") ([](const crow::request& req) { auto file_param = req.url_params.get("file"); if (!file_param) { return crow::response(400, "Missing 'file' parameter"); } std::string filepath = "/templates/"; filepath += utils::urlDecode(file_param); // Optional: decode %20 etc. crow::response res; res.code = 204; res.add_header("HX-Redirect", filepath); return res; }); CROW_ROUTE(app, "/status")([] { auto table = create_service_table(); return crow::response{table.htmx()}; }); 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(); auto opt_settings = AppSettings::loadAppSettings(); HtmxTableRow row; if (opt_settings.has_value()) { auto& settings = opt_settings.value(); const auto& service_id = settings.getId(serviceName).value_or(serviceName); systemd::toggle_service(service_id); row = create_service_table_row(serviceName, service_id); } else { row = create_error_table_row(opt_settings.error()); } return crow::response{row.htmx()}; }); const uint16_t defaultPort = 3010; uint16_t httpPort = defaultPort; { auto opt_settings = AppSettings::loadAppSettings(); if (opt_settings.has_value()){ auto& settings = opt_settings.value(); httpPort = settings.httpPort.value_or(defaultPort); } else { CROW_LOG_ERROR << "failed to load settings : " << opt_settings.error(); } auto opt_isPortOpen = utils::isLocalPortOpen(httpPort); if (opt_isPortOpen.has_value()){ if (opt_isPortOpen.value()){ CROW_LOG_ERROR << "Local port : " << httpPort << " is already open"; } } else { CROW_LOG_ERROR << "failed to check if local port is open : " << opt_isPortOpen.error(); } } shadowrun::initApi(app); app.loglevel(crow::LogLevel::INFO); app.port(httpPort).multithreaded().run(); }