Skip to main content

tx_di_core/di/comp/
config.rs

1use std::any::TypeId;
2use std::fs;
3use std::path::{Path, PathBuf};
4use serde::de::DeserializeOwned;
5use toml::Value::Table;
6use crate::{BuildContext, CompInit, ComponentDescriptor, Scope};
7
8/// 全局配置文件
9pub struct AppAllConfig{
10    pub toml_value: toml::Value,
11}
12impl AppAllConfig {
13    pub fn new<P: Into<PathBuf>>(config_path: Option<P>) -> Self {
14        // 如果提供了配置文件路径,从配置文件加载组件
15        // 确定配置文件路径
16        let final_config_path = if let Some(path) = config_path {
17            path.into()
18        } else {
19            // 默认使用可执行文件所在目录的 config/config.toml
20            let exe_path = std::env::current_exe().unwrap_or_else(|e| {
21                eprintln!("[di] 警告:无法获取可执行文件路径: {}", e);
22                PathBuf::from(".")
23            });
24
25            let config_dir = exe_path.parent().unwrap_or_else(|| {
26                eprintln!("[di] 警告:无法获取可执行文件父目录");
27                Path::new(".")
28            }).join("config");
29
30            config_dir.join("config.toml")
31        };
32        let toml_value = Self::load_config(final_config_path.as_path());
33        AppAllConfig {
34            toml_value,
35        }
36    }
37    /// 加载配置文件(如果存在)
38    fn load_config(path: &Path) -> toml::Value {
39        let config = Table(toml::map::Map::new());
40        if !path.exists() {
41            eprintln!("[di] 配置文件不存在: {:?},将使用默认配置", path);
42            return config;
43        }
44
45        let content = match fs::read_to_string(path) {
46            Ok(c) => c,
47            Err(e) => {
48                eprintln!("[di] 警告:无法读取配置文件 '{:?}': {}", path, e);
49                return config;
50            }
51        };
52
53        // 解析 TOML
54        let config: toml::Value = match toml::from_str(&content) {
55            Ok(v) => v,
56            Err(e) => {
57                eprintln!("[di] 警告:配置文件 '{:?}' 解析失败: {}", path, e);
58                return config;
59            }
60        };
61        // 配置文件已加载,可以在这里将配置存储到上下文中
62        eprintln!("[di] 配置文件加载成功: {:?}", path);
63        config
64    }
65
66    pub fn get<T: DeserializeOwned>(&self, key: &str) -> Option<T> {
67        let value = self.get_value(key)?;
68        T::deserialize(value.clone()).ok()
69    }
70    pub fn get_or_default<T: DeserializeOwned>(&self, key: &str, default: T) -> T {
71        self.get(key).unwrap_or(default)
72    }
73
74    pub fn get_value(&self, key: &str) -> Option<&toml::Value> {
75        let keys: Vec<&str> = key.split('.').collect();
76        let mut current = &self.toml_value;
77        for k in keys {
78            current = current.get(k)?;
79        }
80        Some(current)
81    }
82}
83
84impl CompInit for AppAllConfig {}
85
86impl ComponentDescriptor for AppAllConfig {
87    const DEP_IDS: &'static [fn() -> TypeId] = &[];
88    const SCOPE: Scope = Scope::Singleton;
89
90    fn build(_ctx: &mut BuildContext) -> Self {
91        panic!("AppAllConfig should not be built via ComponentDescriptor::build. It is manually created in BuildContext::new().")
92    }
93}