br_pgsql/
config.rs

1use json::JsonValue;
2use std::time::Duration;
3
4#[derive(Clone, Debug)]
5pub struct Config {
6    /// 调试
7    pub debug: bool,
8    /// 账号
9    pub username: String,
10    /// 密码
11    pub userpass: String,
12    /// 数据库名称
13    pub database: String,
14    /// 请求地址
15    pub hostname: String,
16    /// 请求端口
17    pub hostport: i32,
18    /// 字符集
19    pub charset: String,
20    /// 连接池最大连接数
21    pub pool_max: u32,
22}
23
24/// 连接池约束配置(参考 mysql 的 PoolConstraints)
25#[derive(Clone, Debug)]
26pub struct PoolConstraints {
27    /// 最小连接数
28    pub min: usize,
29    /// 最大连接数
30    pub max: usize,
31}
32
33impl PoolConstraints {
34    /// 创建新的连接池约束
35    /// 
36    /// # 参数
37    /// * `min` - 最小连接数(0-1000)
38    /// * `max` - 最大连接数(1-1000,必须 >= min)
39    /// 
40    /// # 返回
41    /// 如果参数有效返回 Ok,否则返回 Err
42    pub fn new(min: usize, max: usize) -> Result<Self, String> {
43        if min > 1000 {
44            return Err("最小连接数不能超过 1000".into());
45        }
46        if max > 1000 {
47            return Err("最大连接数不能超过 1000".into());
48        }
49        if max < min {
50            return Err("最大连接数必须大于等于最小连接数".into());
51        }
52        if max == 0 {
53            return Err("最大连接数必须大于 0".into());
54        }
55        Ok(Self { min, max })
56    }
57}
58
59impl Default for PoolConstraints {
60    fn default() -> Self {
61        Self { min: 0, max: 10 }
62    }
63}
64
65/// 连接池选项配置(参考 mysql 的 PoolOpts)
66#[derive(Clone, Debug)]
67pub struct PoolOpts {
68    /// 连接池约束
69    pub constraints: PoolConstraints,
70    /// 是否在归还连接时重置连接
71    pub reset_connection: bool,
72    /// 连接超时时间
73    pub connect_timeout: Duration,
74    /// 读取超时时间
75    pub read_timeout: Duration,
76    /// 写入超时时间
77    pub write_timeout: Duration,
78    /// TCP keepalive 时间
79    pub tcp_keepalive: Duration,
80}
81
82impl Default for PoolOpts {
83    fn default() -> Self {
84        Self {
85            constraints: PoolConstraints::default(),
86            reset_connection: true,
87            connect_timeout: Duration::from_secs(5),
88            read_timeout: Duration::from_secs(15),
89            write_timeout: Duration::from_secs(20),
90            tcp_keepalive: Duration::from_secs(5),
91        }
92    }
93}
94
95impl PoolOpts {
96
97    /// 设置连接池约束
98    pub fn with_constraints(mut self, constraints: PoolConstraints) -> Self {
99        self.constraints = constraints;
100        self
101    }
102
103    /// 设置是否重置连接
104    pub fn with_reset_connection(mut self, reset: bool) -> Self {
105        self.reset_connection = reset;
106        self
107    }
108
109    /// 设置连接超时
110    pub fn with_connect_timeout(mut self, timeout: Duration) -> Self {
111        self.connect_timeout = timeout;
112        self
113    }
114
115    /// 设置读取超时
116    pub fn with_read_timeout(mut self, timeout: Duration) -> Self {
117        self.read_timeout = timeout;
118        self
119    }
120
121    /// 设置写入超时
122    pub fn with_write_timeout(mut self, timeout: Duration) -> Self {
123        self.write_timeout = timeout;
124        self
125    }
126
127    /// 设置 TCP keepalive
128    pub fn with_tcp_keepalive(mut self, keepalive: Duration) -> Self {
129        self.tcp_keepalive = keepalive;
130        self
131    }
132}
133
134impl Config {
135    pub fn new(config: &JsonValue) -> Result<Config, String> {
136        let hostname = config["hostname"].as_str()
137            .ok_or("hostname 配置缺失")?
138            .to_string();
139        
140        if hostname.is_empty() {
141            return Err("hostname 不能为空".into());
142        }
143        
144        let hostport = config["hostport"].as_i32()
145            .filter(|&p| p > 0 && p <= 65535)
146            .ok_or("hostport 必须是 1-65535 之间的整数")?;
147        
148        let username = config["username"].as_str()
149            .unwrap_or("postgres")
150            .to_string();
151        
152        if username.is_empty() {
153            return Err("username 不能为空".into());
154        }
155        
156        let database = config["database"].as_str()
157            .unwrap_or("postgres")
158            .to_string();
159        
160        if database.is_empty() {
161            return Err("database 不能为空".into());
162        }
163        
164        Ok(Self {
165            debug: config["debug"].as_bool().unwrap_or(false),
166            username,
167            userpass: config["userpass"].as_str().unwrap_or("111111").to_string(),
168            database,
169            hostname,
170            hostport,
171            charset: config["charset"].as_str().unwrap_or("utf8mb4").to_string(),
172            pool_max: config["pool_max"].as_u32()
173                .filter(|&p| p > 0 && p <= 1000)
174                .unwrap_or(5),
175        })
176    }
177    
178    pub fn url(&self) -> String {
179        format!("{}:{}", self.hostname, self.hostport)
180    }
181}