doido_controller/
config.rs1use doido_core::Environment;
8use serde::Deserialize;
9
10pub use doido_core::logger::LoggerConfig;
13
14#[derive(Debug, Clone, Deserialize)]
17pub struct ServerConfig {
18 pub bind: String,
19 pub port: u16,
20}
21
22impl Default for ServerConfig {
23 fn default() -> Self {
24 Self {
25 bind: "0.0.0.0".to_string(),
26 port: 3000,
27 }
28 }
29}
30
31#[derive(Debug, Clone, Default, Deserialize)]
35pub struct CorsConfig {
36 #[serde(default)]
37 pub enabled: bool,
38 #[serde(default)]
39 pub allowed_origins: Vec<String>,
40 #[serde(default)]
41 pub allowed_methods: Vec<String>,
42}
43
44#[derive(Debug, Clone, Default, Deserialize)]
46pub struct MiddlewareConfig {
47 #[serde(default)]
48 pub cors: CorsConfig,
49}
50
51pub trait Config: Send + Sync {
54 fn server(&self) -> &ServerConfig;
56 fn logger(&self) -> &LoggerConfig;
58 fn middleware(&self) -> &MiddlewareConfig;
60}
61
62#[derive(Debug, Clone, Default, Deserialize)]
64pub struct YamlConfig {
65 #[serde(default)]
66 pub server: ServerConfig,
67 #[serde(default)]
68 pub logger: LoggerConfig,
69 #[serde(default)]
70 pub middleware: MiddlewareConfig,
71}
72
73impl Config for YamlConfig {
74 fn server(&self) -> &ServerConfig {
75 &self.server
76 }
77
78 fn logger(&self) -> &LoggerConfig {
79 &self.logger
80 }
81
82 fn middleware(&self) -> &MiddlewareConfig {
83 &self.middleware
84 }
85}
86
87impl YamlConfig {
88 pub fn load() -> std::io::Result<Self> {
90 Self::load_env(Environment::get_env())
91 }
92
93 pub fn load_env(env: Environment) -> std::io::Result<Self> {
95 let path = format!("config/{}.yml", env.as_str());
96 let contents = std::fs::read_to_string(&path)?;
97 Self::from_yaml(&contents)
98 }
99
100 pub fn from_yaml(yaml: &str) -> std::io::Result<Self> {
102 serde_norway::from_str(yaml)
103 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))
104 }
105}
106
107pub fn load() -> Box<dyn Config> {
110 Box::new(YamlConfig::load().unwrap_or_default())
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 #[test]
118 fn parses_logger_level() {
119 let config = YamlConfig::from_yaml("logger:\n level: debug\n").unwrap();
120 assert_eq!(config.logger().level, "debug");
121 assert_eq!(
122 config.logger().directives(),
123 doido_core::logger::directives_for_level("debug")
124 );
125 }
126
127 #[test]
128 fn explicit_directives_override_level() {
129 let yaml = "logger:\n level: info\n directives: warn,my_app=debug\n";
130 let config = YamlConfig::from_yaml(yaml).unwrap();
131 assert_eq!(config.logger().directives(), "warn,my_app=debug");
132 }
133
134 #[test]
135 fn defaults_to_info_when_logger_section_absent() {
136 let config = YamlConfig::from_yaml("server:\n bind: 0.0.0.0\n port: 3000\n").unwrap();
137 assert_eq!(config.logger().level, "info");
138 assert!(config.logger().sql);
139 assert!(config.logger().file.is_none());
140 assert_eq!(
141 config.logger().directives(),
142 doido_core::logger::DEFAULT_DIRECTIVES
143 );
144 }
145}