Skip to main content

br_db/
config.rs

1use json::{object, JsonValue};
2use serde::{Deserialize, Serialize};
3use std::collections::BTreeMap;
4use std::fs;
5use std::path::PathBuf;
6
7#[derive(Clone, Debug, Deserialize, Serialize)]
8pub struct Config {
9    pub default: String,
10    pub connections: BTreeMap<String, Connection>,
11}
12
13impl Default for Config {
14    fn default() -> Self {
15        Self::new()
16    }
17}
18
19impl Config {
20    pub fn new() -> Config {
21        let mut connections = BTreeMap::new();
22        connections.insert("sqlite".to_string(), Connection::new("sqlite"));
23        connections.insert("mysql".to_string(), Connection::new("mysql"));
24        connections.insert("pgsql".to_string(), Connection::new("pgsql"));
25        connections.insert("mssql".to_string(), Connection::new("mssql"));
26        Self {
27            default: "sqlite".to_string(),
28            connections,
29        }
30    }
31    pub fn from(data: JsonValue) -> Config {
32        let default = data["default"].to_string();
33        let mut connections = BTreeMap::new();
34        for (key, value) in data["connections"].entries() {
35            let connection = Connection::from(value.clone()).clone();
36            connections.insert(key.to_string(), connection.clone());
37        }
38
39        Self {
40            default,
41            connections,
42        }
43    }
44    pub fn create(config_file: PathBuf, pkg_name: bool) -> Config {
45        #[derive(Clone, Debug, Deserialize, Serialize)]
46        pub struct ConfigPkg {
47            pub br_db: Config,
48        }
49        impl ConfigPkg {
50            pub fn new() -> ConfigPkg {
51                let mut connections = BTreeMap::new();
52                connections.insert("sqlite".to_string(), Connection::new("sqlite"));
53                connections.insert("mysql".to_string(), Connection::new("mysql"));
54                connections.insert("pgsql".to_string(), Connection::new("pgsql"));
55                connections.insert("mssql".to_string(), Connection::new("mssql"));
56                Self {
57                    br_db: Config {
58                        default: "sqlite".to_string(),
59                        connections,
60                    },
61                }
62            }
63        }
64        match fs::read_to_string(config_file.clone()) {
65            Ok(e) => {
66                if pkg_name {
67                    toml::from_str::<ConfigPkg>(&e)
68                        .map(|c| c.br_db)
69                        .unwrap_or_else(|_| Config::new())
70                } else {
71                    toml::from_str::<Config>(&e).unwrap_or_else(|_| Config::new())
72                }
73            }
74            Err(_) => {
75                if pkg_name {
76                    let data = ConfigPkg::new();
77                    if let Some(parent) = config_file.parent() {
78                        let _ = fs::create_dir_all(parent);
79                    }
80                    if let Ok(toml) = toml::to_string(&data) {
81                        if let Some(path) = config_file.to_str() {
82                            let _ = fs::write(path, toml);
83                        }
84                    }
85                    data.br_db
86                } else {
87                    let data = Config::new();
88                    if let Some(parent) = config_file.parent() {
89                        let _ = fs::create_dir_all(parent);
90                    }
91                    if let Ok(toml) = toml::to_string(&data) {
92                        if let Some(path) = config_file.to_str() {
93                            let _ = fs::write(path, toml);
94                        }
95                    }
96                    data
97                }
98            }
99        }
100    }
101    /// 设置新地连接配置
102    pub fn set_connection(&mut self, name: &str, connection: JsonValue) {
103        let connection = Connection::from(connection);
104        self.connections.insert(name.to_string(), connection);
105    }
106    /// 设置当前运行配置
107    pub fn set_default(&mut self, name: &str) {
108        self.default = name.to_string();
109    }
110}
111/// 数据库模式
112#[derive(Clone, Debug, Deserialize, Serialize)]
113pub enum Mode {
114    Mysql,
115    Mssql,
116    Sqlite,
117    Pgsql,
118    None,
119}
120
121impl Mode {
122    pub fn str(&mut self) -> String {
123        match self {
124            Mode::Mysql => "mysql",
125            Mode::Sqlite => "sqlite",
126            Mode::Mssql => "mssql",
127            Mode::Pgsql => "pgsql",
128            Mode::None => "",
129        }
130        .to_string()
131    }
132    pub fn from(name: &str) -> Self {
133        match name.to_lowercase().as_str() {
134            "mysql" => Mode::Mysql,
135            "sqlite" => Mode::Sqlite,
136            "mssql" => Mode::Mssql,
137            "pgsql" => Mode::Pgsql,
138            _ => Mode::None,
139        }
140    }
141}
142
143/// 数据库连接池配置
144#[derive(Clone, Debug, Deserialize, Serialize)]
145pub struct PoolConfig {
146    pub min_connections: u32,
147    pub max_connections: u32,
148    pub connect_timeout_secs: u64,
149    pub read_timeout_secs: u64,
150    pub write_timeout_secs: u64,
151    pub keepalive_ms: u64,
152}
153
154impl Default for PoolConfig {
155    fn default() -> Self {
156        Self {
157            min_connections: 0,
158            max_connections: 400,
159            connect_timeout_secs: 5,
160            read_timeout_secs: 15,
161            write_timeout_secs: 20,
162            keepalive_ms: 5000,
163        }
164    }
165}
166
167impl PoolConfig {
168    pub fn from(data: &JsonValue) -> Self {
169        Self {
170            min_connections: data["min_connections"].as_u32().unwrap_or(0),
171            max_connections: data["max_connections"].as_u32().unwrap_or(400),
172            connect_timeout_secs: data["connect_timeout_secs"].as_u64().unwrap_or(5),
173            read_timeout_secs: data["read_timeout_secs"].as_u64().unwrap_or(15),
174            write_timeout_secs: data["write_timeout_secs"].as_u64().unwrap_or(20),
175            keepalive_ms: data["keepalive_ms"].as_u64().unwrap_or(5000),
176        }
177    }
178}
179
180/// 数据库连接
181#[derive(Clone, Debug, Deserialize, Serialize)]
182pub struct Connection {
183    pub mode: Mode,
184    pub hostname: String,
185    pub hostport: String,
186    pub database: String,
187    pub username: String,
188    pub userpass: String,
189    pub params: Vec<String>,
190    pub charset: Charset,
191    pub prefix: String,
192    pub debug: bool,
193    #[serde(default)]
194    pub pool: PoolConfig,
195}
196
197impl Default for Connection {
198    fn default() -> Self {
199        Self::new("sqlite")
200    }
201}
202
203impl Connection {
204    pub fn new(mode: &str) -> Connection {
205        let mut that = Self {
206            mode: Mode::from(mode),
207            hostname: "".to_string(),
208            hostport: "".to_string(),
209            database: "".to_string(),
210            username: "".to_string(),
211            userpass: "".to_string(),
212            params: vec![],
213            charset: Charset::Utf8mb4,
214            prefix: "".to_string(),
215            debug: false,
216            pool: PoolConfig::default(),
217        };
218        match Mode::from(mode) {
219            Mode::Mysql => {
220                that.hostname = "127.0.0.1".to_string();
221                that.hostport = "3306".to_string();
222                that.database = "test".to_string();
223                that.username = "test".to_string();
224                that.userpass = "test".to_string();
225            }
226            Mode::Mssql => {}
227            Mode::Sqlite => {
228                that.database = "db/app.db".to_string();
229            }
230            Mode::Pgsql => {
231                that.hostname = "127.0.0.1".to_string();
232                that.hostport = "5432".to_string();
233                that.username = "test".to_string();
234                that.userpass = "test".to_string();
235            }
236            Mode::None => {}
237        }
238
239        that
240    }
241    pub fn json(&mut self) -> JsonValue {
242        object! {
243            mode: self.mode.str(),
244            hostname: self.hostname.clone(),
245            hostport: self.hostport.clone(),
246            database: self.database.clone(),
247            username: self.username.clone(),
248            userpass:self.userpass.clone(),
249            params: self.params.clone(),
250            charset: self.charset.str(),
251            prefix: self.prefix.clone(),
252            debug: self.debug
253        }
254    }
255    pub fn from(data: JsonValue) -> Connection {
256        Self {
257            mode: Mode::from(data["mode"].as_str().unwrap_or("none")),
258            hostname: data["hostname"].to_string(),
259            hostport: data["hostport"].to_string(),
260            database: data["database"].to_string(),
261            username: data["username"].to_string(),
262            userpass: data["userpass"].to_string(),
263            params: data["params"].members().map(|x| x.to_string()).collect(),
264            charset: Charset::from(data["charset"].as_str().unwrap_or("utf8mb4")),
265            prefix: data["prefix"].as_str().unwrap_or("").to_string(),
266            debug: data["debug"].to_string().parse::<bool>().unwrap_or(false),
267            pool: PoolConfig::from(&data["pool"]),
268        }
269    }
270    pub fn get_dsn(self) -> String {
271        match self.mode {
272            Mode::Mysql => {
273                format!(
274                    "mysql://{}:{}@{}:{}/{}",
275                    self.username, self.userpass, self.hostname, self.hostport, self.database
276                )
277            }
278            Mode::Sqlite => {
279                let db_path = self.database.as_str();
280                let path_buf = PathBuf::from(db_path);
281                if !path_buf.is_file() {
282                    if let Some(file_name) = path_buf.file_name() {
283                        if let Some(file_name_str) = file_name.to_str() {
284                            let dir_path = db_path.trim_end_matches(file_name_str);
285                            let _ = fs::create_dir_all(dir_path);
286                        }
287                    }
288                }
289                path_buf.to_str().unwrap_or(db_path).to_string()
290            }
291            Mode::Mssql => format!(
292                "sqlsrv://{}:{}@{}:{}/{}",
293                self.username, self.userpass, self.hostname, self.hostport, self.database
294            ),
295            Mode::Pgsql => format!(
296                "host={} user={} password={} dbname={}",
297                self.hostname, self.username, self.userpass, self.database
298            ),
299            Mode::None => "".to_string(),
300        }
301    }
302}
303
304#[derive(Clone, Debug, Deserialize, Serialize)]
305pub enum Charset {
306    Utf8mb4,
307    Utf8,
308    None,
309}
310
311impl Charset {
312    pub fn from(str: &str) -> Charset {
313        match str.to_lowercase().as_str() {
314            "utf8" => Charset::Utf8,
315            "utf8mb4" => Charset::Utf8mb4,
316            _ => Charset::None,
317        }
318    }
319    pub fn str(&self) -> String {
320        match self {
321            Charset::Utf8 => "utf8",
322            Charset::Utf8mb4 => "utf8mb4",
323            Charset::None => "",
324        }
325        .to_string()
326    }
327}