Skip to main content

mcp_stdio_proxy/
config.rs

1use anyhow::Result;
2use serde::Deserialize;
3use std::env;
4use std::fs::File;
5use std::path::Path;
6
7/// The default config file
8const DEFAULT_CONFIG_YAML: &str = include_str!("../config.yml");
9
10/// config.yml 中 mirror 段的结构
11#[allow(dead_code)]
12#[derive(Debug, Deserialize, Clone, Default)]
13pub struct MirrorYamlConfig {
14    #[serde(default)]
15    pub npm_registry: String,
16    #[serde(default)]
17    pub pypi_index_url: String,
18}
19
20#[allow(dead_code)]
21#[derive(Debug, Deserialize, Clone)]
22pub struct AppConfig {
23    pub server: ServerConfig,
24    pub log: LogConfig,
25    #[serde(default)]
26    pub mirror: MirrorYamlConfig,
27}
28#[allow(dead_code)]
29#[derive(Debug, Deserialize, Clone)]
30pub struct ServerConfig {
31    /// The port to listen on for incoming connections
32    pub port: u16,
33}
34#[allow(dead_code)]
35#[derive(Debug, Deserialize, Clone)]
36pub struct LogConfig {
37    /// The log level to use
38    pub level: String,
39    /// The path to the log file
40    pub path: String,
41    /// The number of log files to retain (default: 20)
42    #[serde(default = "default_retain_days")]
43    pub retain_days: u32,
44}
45
46/// Default log files to retain
47#[allow(dead_code)]
48fn default_retain_days() -> u32 {
49    5
50}
51
52#[allow(dead_code)]
53impl AppConfig {
54    /// Load the config file from the following sources:
55    /// 1. /app/config.yml
56    /// 2. config.yml
57    /// 3. BOT_SERVER_CONFIG environment variable
58    ///
59    /// Environment variables can override config values:
60    /// - MCP_PROXY_PORT: Override server port
61    /// - MCP_PROXY_LOG_DIR: Override log directory path
62    /// - MCP_PROXY_LOG_LEVEL: Override log level
63    pub fn load_config() -> Result<Self> {
64        let mut config = match (
65            File::open("/app/config.yml"),
66            File::open("config.yml"),
67            env::var("BOT_SERVER_CONFIG"),
68        ) {
69            (Ok(file), _, _) => serde_yaml::from_reader(file),
70            (_, Ok(file), _) => serde_yaml::from_reader(file),
71            (_, _, Ok(file_path)) => serde_yaml::from_reader(File::open(file_path)?),
72            _ => {
73                // 如果都没有,则使用默认配置
74                serde_yaml::from_str::<AppConfig>(DEFAULT_CONFIG_YAML)
75            }
76        }?;
77
78        // 环境变量覆盖配置(优先级最高)
79        if let Ok(port) = env::var("MCP_PROXY_PORT")
80            && let Ok(port_num) = port.parse::<u16>()
81        {
82            config.server.port = port_num;
83        }
84
85        if let Ok(log_dir) = env::var("MCP_PROXY_LOG_DIR") {
86            config.log.path = log_dir;
87        }
88
89        if let Ok(log_level) = env::var("MCP_PROXY_LOG_LEVEL") {
90            config.log.level = log_level;
91        }
92
93        Ok(config)
94    }
95
96    pub fn log_path_init(&self) -> Result<()> {
97        let log_path = &self.log.path;
98
99        // 获取日志文件的父目录
100        if let Some(parent) = Path::new(log_path).parent()
101            && !parent.exists()
102        {
103            std::fs::create_dir_all(parent)?;
104        }
105        Ok(())
106    }
107}