use std::collections::HashMap;
use std::path::Path;
use serde::Deserialize;
pub trait IntoMysqlName {
fn into_name(self) -> String;
}
pub trait IntoRedisName {
fn into_name(self) -> String;
}
impl IntoMysqlName for String {
fn into_name(self) -> String {
self
}
}
impl IntoMysqlName for &str {
fn into_name(self) -> String {
self.to_string()
}
}
impl IntoRedisName for String {
fn into_name(self) -> String {
self
}
}
impl IntoRedisName for &str {
fn into_name(self) -> String {
self.to_string()
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct MysqlConfig {
pub host: String,
#[serde(default = "default_mysql_port")]
pub port: u16,
#[serde(alias = "username")]
pub user: String,
pub password: String,
#[serde(default)]
pub database: String,
#[serde(default = "default_max_connections")]
pub max_connections: u32,
#[serde(default = "default_ssl_mode")]
pub ssl_mode: String,
}
fn default_mysql_port() -> u16 {
3306
}
fn default_max_connections() -> u32 {
5
}
fn default_ssl_mode() -> String {
"preferred".to_string()
}
#[derive(Debug, Clone, Deserialize)]
pub struct RedisConfig {
pub url: String,
}
#[derive(Debug, Clone, Default, Deserialize)]
pub struct Config {
#[serde(default)]
pub mysql: HashMap<String, MysqlConfig>,
#[serde(default)]
pub redis: HashMap<String, RedisConfig>,
}
impl Config {
pub fn load<P: AsRef<Path>>(path: P) -> anyhow::Result<Self> {
let path = path.as_ref();
let text = std::fs::read_to_string(path)
.map_err(|e| anyhow::anyhow!("读取配置文件 {} 失败: {}", path.display(), e))?;
let cfg: Config = toml::from_str(&text)
.map_err(|e| anyhow::anyhow!("解析配置文件 {} 失败: {}", path.display(), e))?;
Ok(cfg)
}
pub fn mysql(&self, name: &str) -> Option<&MysqlConfig> {
self.mysql.get(name)
}
pub fn redis(&self, name: &str) -> Option<&RedisConfig> {
self.redis.get(name)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_multiple_named_connections() {
let toml = r#"
[mysql.default]
host = "h1"
port = 3306
user = "u1"
password = "p1"
database = "db1"
max_connections = 1
ssl_mode = "preferred"
[mysql.order_db]
host = "h2"
username = "u2"
password = "p2"
[redis.session]
url = "redis://127.0.0.1:6379"
"#;
let cfg: Config = toml::from_str(toml).unwrap();
let d = cfg.mysql("default").unwrap();
assert_eq!(d.host, "h1");
assert_eq!(d.port, 3306);
let b = cfg.mysql("order_db").unwrap();
assert_eq!(b.user, "u2"); assert_eq!(b.port, 3306);
assert_eq!(b.max_connections, 5);
assert_eq!(b.ssl_mode, "preferred");
assert!(b.database.is_empty());
assert_eq!(cfg.redis("session").unwrap().url, "redis://127.0.0.1:6379");
}
}