use anyhow::Result; use serde::Deserialize; use std::env; use std::fs::File; use std::path::Path; /// The default config file const DEFAULT_CONFIG_YAML: &str = include_str!("../config.yml"); /// config.yml 中 mirror 段的结构 #[allow(dead_code)] #[derive(Debug, Deserialize, Clone, Default)] pub struct MirrorYamlConfig { #[serde(default)] pub npm_registry: String, #[serde(default)] pub pypi_index_url: String, } #[allow(dead_code)] #[derive(Debug, Deserialize, Clone)] pub struct AppConfig { pub server: ServerConfig, pub log: LogConfig, #[serde(default)] pub mirror: MirrorYamlConfig, } #[allow(dead_code)] #[derive(Debug, Deserialize, Clone)] pub struct ServerConfig { /// The port to listen on for incoming connections pub port: u16, } #[allow(dead_code)] #[derive(Debug, Deserialize, Clone)] pub struct LogConfig { /// The log level to use pub level: String, /// The path to the log file pub path: String, /// The number of log files to retain (default: 20) #[serde(default = "default_retain_days")] pub retain_days: u32, } /// Default log files to retain fn default_retain_days() -> u32 { 5 } #[allow(dead_code)] impl AppConfig { /// Load the config file from the following sources: /// 1. /app/config.yml /// 2. config.yml /// 3. BOT_SERVER_CONFIG environment variable /// /// Environment variables can override config values: /// - MCP_PROXY_PORT: Override server port /// - MCP_PROXY_LOG_DIR: Override log directory path /// - MCP_PROXY_LOG_LEVEL: Override log level pub fn load_config() -> Result { let mut config = match ( File::open("/app/config.yml"), File::open("config.yml"), env::var("BOT_SERVER_CONFIG"), ) { (Ok(file), _, _) => serde_yaml::from_reader(file), (_, Ok(file), _) => serde_yaml::from_reader(file), (_, _, Ok(file_path)) => serde_yaml::from_reader(File::open(file_path)?), _ => { // 如果都没有,则使用默认配置 serde_yaml::from_str::(DEFAULT_CONFIG_YAML) } }?; // 环境变量覆盖配置(优先级最高) if let Ok(port) = env::var("MCP_PROXY_PORT") && let Ok(port_num) = port.parse::() { config.server.port = port_num; } if let Ok(log_dir) = env::var("MCP_PROXY_LOG_DIR") { config.log.path = log_dir; } if let Ok(log_level) = env::var("MCP_PROXY_LOG_LEVEL") { config.log.level = log_level; } Ok(config) } pub fn log_path_init(&self) -> Result<()> { let log_path = &self.log.path; // 获取日志文件的父目录 if let Some(parent) = Path::new(log_path).parent() && !parent.exists() { std::fs::create_dir_all(parent)?; } Ok(()) } }