1use std::env;
28
29#[derive(Debug, Clone)]
31pub struct AppConfig {
32 pub host: String,
34 pub port: u16,
36 pub database_url: String,
38 pub db_max_connections: u32,
40 pub db_min_connections: u32,
42 pub db_connect_timeout: u64,
44 pub db_idle_timeout: u64,
46 pub db_max_lifetime: u64,
48}
49
50impl AppConfig {
51 pub fn from_env() -> anyhow::Result<Self> {
58 let host = env::var("APP_HOST").unwrap_or_else(|_| "0.0.0.0".to_string());
59 let port = env::var("APP_PORT")
60 .unwrap_or_else(|_| "3000".to_string())
61 .parse::<u16>()?;
62 let database_url =
63 env::var("DATABASE_URL").map_err(|_| anyhow::anyhow!("DATABASE_URL must be set"))?;
64
65 let db_max_connections = env::var("DB_MAX_CONNECTIONS")
66 .unwrap_or_else(|_| "100".to_string())
67 .parse::<u32>()?;
68 let db_min_connections = env::var("DB_MIN_CONNECTIONS")
69 .unwrap_or_else(|_| "5".to_string())
70 .parse::<u32>()?;
71 let db_connect_timeout = env::var("DB_CONNECT_TIMEOUT")
72 .unwrap_or_else(|_| "8".to_string())
73 .parse::<u64>()?;
74 let db_idle_timeout = env::var("DB_IDLE_TIMEOUT")
75 .unwrap_or_else(|_| "600".to_string())
76 .parse::<u64>()?;
77 let db_max_lifetime = env::var("DB_MAX_LIFETIME")
78 .unwrap_or_else(|_| "1800".to_string())
79 .parse::<u64>()?;
80
81 Ok(Self {
82 host,
83 port,
84 database_url,
85 db_max_connections,
86 db_min_connections,
87 db_connect_timeout,
88 db_idle_timeout,
89 db_max_lifetime,
90 })
91 }
92
93 pub fn bind_address(&self) -> String {
95 format!("{}:{}", self.host, self.port)
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102
103 fn default_config() -> AppConfig {
104 AppConfig {
105 host: "127.0.0.1".to_string(),
106 port: 8080,
107 database_url: "postgres://localhost/test".to_string(),
108 db_max_connections: 100,
109 db_min_connections: 5,
110 db_connect_timeout: 8,
111 db_idle_timeout: 600,
112 db_max_lifetime: 1800,
113 }
114 }
115
116 #[test]
117 fn test_bind_address() {
118 let config = default_config();
119 assert_eq!(config.bind_address(), "127.0.0.1:8080");
120 }
121
122 #[test]
123 fn test_bind_address_default_format() {
124 let mut config = default_config();
125 config.host = "0.0.0.0".to_string();
126 config.port = 3000;
127 assert_eq!(config.bind_address(), "0.0.0.0:3000");
128 }
129
130 #[test]
131 fn test_config_clone() {
132 let config = default_config();
133 let cloned = config.clone();
134 assert_eq!(config.host, cloned.host);
135 assert_eq!(config.port, cloned.port);
136 assert_eq!(config.database_url, cloned.database_url);
137 assert_eq!(config.db_max_connections, cloned.db_max_connections);
138 }
139}