use super::ConfigError; use serde::{Deserialize, Deserializer}; use std::collections::HashMap; use std::fs; use std::path::PathBuf; use tracing::metadata::LevelFilter; use xdg::BaseDirectories; #[derive(serde_derive::Deserialize, Default)] pub struct ConfigFile { #[serde(deserialize_with = "parse_log_level")] pub log_level: Option, pub start_servers: Option, #[serde(flatten)] pub servers: HashMap, } #[derive(serde_derive::Deserialize)] pub struct ServerDefinition { pub interface: Option, #[serde(deserialize_with = "parse_log_level")] pub log_level: Option, pub address: Option, pub port: Option, } fn parse_log_level<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, { let possible_string: Option<&str> = Deserialize::deserialize(deserializer)?; if let Some(s) = possible_string { Ok(Some(s.parse().map_err(|e| { serde::de::Error::custom(format!("Couldn't parse log level '{}': {}", s, e)) })?)) } else { Ok(None) } } impl ConfigFile { pub fn read(mut config_file_path: Option) -> Result { if config_file_path.is_none() { let base_dirs = BaseDirectories::with_prefix("socks5")?; let proposed_path = base_dirs.get_config_home(); if let Ok(attributes) = fs::metadata(proposed_path.clone()) { if attributes.is_file() { config_file_path = Some(proposed_path); } } } match config_file_path { None => Ok(ConfigFile::default()), Some(path) => { let content = fs::read(path)?; Ok(toml::from_slice(&content)?) } } } }