// 文件名: src/web/web_server.cc #include "web_server.h" #include #include #include "config/config_manager.h" #include "spdlog/spdlog.h" WebServer::WebServer(SystemMonitor::SystemMonitor& monitor, DeviceManager& deviceManager, LiveDataCache& liveDataCache, AlarmService& alarm_service, uint16_t port) : crow::Crow(), m_monitor(monitor), m_device_manager(deviceManager), m_live_data_cache(liveDataCache), m_alarm_service(alarm_service), m_port(port) { auto& cors = this->get_middleware(); cors.global() .origin("*") .headers("Content-Type", "Authorization") .methods("GET"_method, "POST"_method, "OPTIONS"_method); this->loglevel(crow::LogLevel::Warning); setup_routes(); } WebServer::~WebServer() { stop(); } void WebServer::start() { if (m_thread.joinable()) { spdlog::warn("Web server is already running."); return; } m_thread = std::thread([this]() { spdlog::info("Starting Web server on port {}", m_port); this->bindaddr("0.0.0.0").port(m_port).run(); spdlog::info("Web server has stopped."); }); } void WebServer::stop() { crow::Crow::stop(); if (m_thread.joinable()) { m_thread.join(); } } void WebServer::setup_routes() { CROW_ROUTE((*this), "/api/system/id").methods("GET"_method)([this] { auto deviceID = ConfigManager::getInstance().getDeviceID(); crow::json::wvalue response; response["deviceID"] = deviceID; return response; }); CROW_ROUTE((*this), "/api/system/status").methods("GET"_method)([this] { auto cpu_util = m_monitor.getCpuUtilization(); auto mem_info = m_monitor.getMemoryInfo(); crow::json::wvalue response; response["cpu_usage_percentage"] = cpu_util.totalUsagePercentage; response["memory_total_kb"] = mem_info.total_kb; response["memory_free_kb"] = mem_info.available_kb; response["memory_usage_percentage"] = (mem_info.total_kb > 0) ? (1.0 - static_cast(mem_info.available_kb) / mem_info.total_kb) * 100.0 : 0.0; return response; }); CROW_ROUTE((*this), "/api/devices").methods("GET"_method)([this] { auto devices_info = m_device_manager.get_all_device_info(); std::vector devices_json; for (const auto& info : devices_info) { crow::json::wvalue device_obj; device_obj["id"] = info.id; device_obj["type"] = info.type; device_obj["is_running"] = info.is_running; crow::json::wvalue details_obj; for (const auto& pair : info.connection_details) { details_obj[pair.first] = pair.second; } device_obj["connection_details"] = std::move(details_obj); devices_json.push_back(std::move(device_obj)); } return crow::json::wvalue(devices_json); }); CROW_ROUTE((*this), "/api/data/latest").methods("GET"_method)([this] { auto latest_data_map = m_live_data_cache.get_all_data(); crow::json::wvalue response; for (const auto& pair : latest_data_map) { response[pair.first] = crow::json::load(pair.second); } return response; }); CROW_ROUTE((*this), "/api/alarms/active").methods("GET"_method)([this] { try { auto json_string = m_alarm_service.getActiveAlarmsJson().dump(); auto res = crow::response(200, json_string); res.set_header("Content-Type", "application/json"); return res; } catch (const std::exception& e) { spdlog::error("Error processing /api/alarms/active: {}", e.what()); crow::json::wvalue error_resp; error_resp["error"] = "Failed to retrieve active alarms."; auto res = crow::response(500, error_resp.dump()); res.set_header("Content-Type", "application/json"); return res; } }); CROW_ROUTE((*this), "/api/alarms/history") .methods("GET"_method)([this](const crow::request& req) { int limit = 100; if (req.url_params.get("limit")) { try { limit = std::stoi(req.url_params.get("limit")); } catch (const std::exception&) { /* ignore invalid */ } } if (limit <= 0) limit = 100; try { auto json_string = m_alarm_service.getAlarmHistoryJson(limit).dump(); auto res = crow::response(200, json_string); res.set_header("Content-Type", "application/json"); return res; } catch (const std::exception& e) { spdlog::error("Error processing /api/alarms/history: {}", e.what()); crow::json::wvalue error_resp; error_resp["error"] = "Failed to retrieve alarm history."; auto res = crow::response(500, error_resp.dump()); res.set_header("Content-Type", "application/json"); return res; } }); }