use config::{Config, Environment, File};
use serde::{Deserialize, de::DeserializeOwned};
use std::{collections::HashMap, fmt::Debug, path::PathBuf};
use tracing::error;
use validator::Validate;
#[derive(Debug, Clone)]
pub struct NamedConfig<T> {
configs: HashMap<String, T>,
}
impl<T> NamedConfig<T>
where
T: DeserializeOwned + Validate + Clone + Send + Sync + Default + 'static,
{
pub fn get(&self, name: &str) -> T {
self.configs.get(name).cloned().unwrap_or_default()
}
}
pub fn build_config() -> Config {
let config_root = std::env::var("UNI_CONFIG_ROOT")
.map(PathBuf::from)
.unwrap_or(PathBuf::from("./config"));
let env = std::env::var("UNI_ENV").unwrap_or("dev".to_owned());
match Config::builder()
.add_source(File::from(config_root.join("default")).required(false))
.add_source(File::from(config_root.join(env)).required(false))
.add_source(
Environment::with_prefix("UNI")
.separator("__")
.list_separator(","),
)
.build()
{
Ok(c) => c,
Err(e) => {
error!("加载配置失败:{e}");
panic!("加载配置失败");
}
}
}
pub fn load_named_config<T>(config: &Config, section: &str) -> NamedConfig<T>
where
T: DeserializeOwned + Validate + Clone + Default,
{
let configs = match config.get::<HashMap<String, T>>(section) {
Ok(c) => c,
Err(e) => {
error!("加载命名配置'{section}'失败:{e}");
panic!("加载命名配置失败");
}
};
for (key, cfg) in &configs {
if let Err(e) = cfg.validate() {
error!("[{section}.{key}]命名配置验证失败:{e}");
panic!("命名配置验证失败");
}
}
NamedConfig { configs }
}
pub fn load_named_setting(
config: &config::Config,
section: &str,
) -> HashMap<String, HashMap<String, String>> {
let mut result = HashMap::new();
let input = config
.get::<HashMap<String, config::Value>>(section)
.unwrap_or(HashMap::new());
for (section, value) in input {
let map = match value.try_deserialize::<HashMap<String, String>>() {
Ok(c) => c,
Err(e) => {
error!("加载命名配置'{section}'失败:{e}");
panic!("加载命名配置失败");
}
};
result.insert(section, map);
}
result
}
#[derive(Debug, Deserialize, Validate, Clone)]
#[serde(default)]
pub struct SubscribeConfig {
pub hotspot: bool,
pub interval: u64,
pub low: usize,
pub high: usize,
pub retain: u64,
#[validate(range(min = 2, max = 120))]
pub latest: i64,
#[validate(range(min = 7))]
pub sems: usize,
pub bufs: usize,
}
impl Default for SubscribeConfig {
fn default() -> Self {
Self {
hotspot: false,
interval: 30 * 60,
low: 200,
high: 20000,
retain: 2 * 24 * 60 * 60,
latest: 30,
sems: 100,
bufs: 1024,
}
}
}
#[derive(Debug, Deserialize, Validate, Clone)]
#[serde(default)]
pub struct SendConfig {
pub hotspot: bool,
pub interval: u64,
pub retain: u64,
#[validate(range(min = 7))]
pub sems: usize,
pub bufs: usize,
}
impl Default for SendConfig {
fn default() -> Self {
Self {
hotspot: false,
interval: 5,
retain: 30,
sems: 100,
bufs: 1024,
}
}
}