// app_config.hpp #pragma once #include #include #include #include #include #include #include #include #include "logger.hpp" using json = nlohmann::json; using ordered_json = nlohmann::ordered_json; // ------------------- 摄像头结构体 ------------------- struct Camera { std::string device; std::string name; int width, height, fps; bool enabled; }; // ------------------- MQTT Topic ------------------- struct VehicleMQTTTopics { std::string heartbeat_up; std::string video_down; std::string video_down_ack; std::string substream_down; std::string substream_down_ack; std::string reset_down; std::string reset_down_ack; void fill_with_veh_id(const std::string &vehId) { heartbeat_up = "adcpcmcc/v1/vehmedia/" + vehId + "/heartbeat/up"; video_down = "adcpcmcc/v1/vehmedia/" + vehId + "/video/down"; video_down_ack = "adcpcmcc/v1/vehmedia/" + vehId + "/video/down/ack"; substream_down = "adcpcmcc/v1/vehmedia/" + vehId + "/substream/down"; substream_down_ack = "adcpcmcc/v1/vehmedia/" + vehId + "/substream/down/ack"; reset_down = "adcpcmcc/v1/vehmedia/" + vehId + "/reset/down"; reset_down_ack = "adcpcmcc/v1/vehmedia/" + vehId + "/reset/down/ack"; } }; // ------------------- MQTT 配置 ------------------- struct MQTTConfig { std::string vehicle_id; std::string server_ip; int server_port; bool need_username_pwd; std::string client_id; std::string username; std::string password; int keep_alive; VehicleMQTTTopics topics; }; // ------------------- 总配置 ------------------- struct AppConfig { std::vector cameras; MQTTConfig mqtt; static AppConfig load_from_file(const std::string &filepath) { AppConfig cfg; std::ifstream ifs(filepath); if (!ifs.is_open()) { LOG_ERROR("[Config] Failed to open config file: " + filepath); throw std::runtime_error("Failed to open config file: " + filepath); } json j; ifs >> j; // 读取摄像头 if (j.contains("cameras")) { for (auto &c : j["cameras"]) { Camera cam; cam.device = c.value("device", ""); cam.name = c.value("name", ""); cam.width = c.value("width", 1280); cam.height = c.value("height", 720); cam.fps = c.value("fps", 30); cam.enabled = c.value("enabled", false); cfg.cameras.push_back(cam); LOG_INFO("[Config] Loaded camera: " + cam.name + " (" + cam.device + "), enabled=" + std::to_string(cam.enabled)); } } // 读取 MQTT if (!j.contains("mqtt_server")) { LOG_ERROR("[Config] Missing 'mqtt_server' section"); throw std::runtime_error("Config file missing 'mqtt_server'"); } auto &m = j["mqtt_server"]; cfg.mqtt.vehicle_id = std::to_string(m.value("veh_id", 0)); cfg.mqtt.server_ip = m.value("address", ""); cfg.mqtt.server_port = m.value("port", 1883); cfg.mqtt.need_username_pwd = m.value("need_username_pwd", true); cfg.mqtt.client_id = m.value("client_id", ""); cfg.mqtt.username = m.value("username", ""); cfg.mqtt.password = m.value("password", ""); cfg.mqtt.keep_alive = m.value("mqtt_heart_threshold", 2000); cfg.mqtt.topics.fill_with_veh_id(cfg.mqtt.vehicle_id); LOG_INFO("[Config] Loaded MQTT server: " + cfg.mqtt.server_ip + ":" + std::to_string(cfg.mqtt.server_port)); LOG_INFO("[Config] MQTT client ID: " + cfg.mqtt.client_id); LOG_INFO("[Config] MQTT Topics: " + cfg.mqtt.topics.heartbeat_up + ", " + cfg.mqtt.topics.video_down + ", " + cfg.mqtt.topics.video_down_ack); return cfg; } }; // ------------------- 辅助函数 ------------------- inline std::string get_executable_dir() { char result[PATH_MAX] = {0}; ssize_t count = readlink("/proc/self/exe", result, PATH_MAX); if (count == -1) { LOG_ERROR("[Config] Failed to read /proc/self/exe"); throw std::runtime_error("Failed to read /proc/self/exe"); } std::string full_path(result, count); auto pos = full_path.find_last_of('/'); if (pos == std::string::npos) { LOG_ERROR("[Config] Failed to find executable directory"); throw std::runtime_error("Failed to find executable directory"); } return full_path.substr(0, pos); } inline std::string get_executable_dir_file_path(const std::string &filename) { std::string dir = get_executable_dir(); if (dir.back() != '/') dir += '/'; return dir + filename; } // 全局配置变量 extern AppConfig g_app_config;