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)]
38pub struct CorsConfig {
39 #[serde(default)]
40 pub enabled: bool,
41 #[serde(default)]
42 pub allowed_origins: Vec<String>,
43 #[serde(default)]
44 pub allowed_methods: Vec<String>,
45 #[serde(default)]
46 pub allowed_headers: Vec<String>,
47 #[serde(default)]
48 pub allow_credentials: bool,
49}
50
51#[derive(Debug, Clone, Default, Deserialize)]
53pub struct MiddlewareConfig {
54 #[serde(default)]
55 pub cors: CorsConfig,
56}
57
58pub trait Config: Send + Sync {
61 fn server(&self) -> &ServerConfig;
63 fn logger(&self) -> &LoggerConfig;
65 fn middleware(&self) -> &MiddlewareConfig;
67}
68
69#[derive(Debug, Clone, Default, Deserialize)]
71pub struct YamlConfig {
72 #[serde(default)]
73 pub server: ServerConfig,
74 #[serde(default)]
75 pub logger: LoggerConfig,
76 #[serde(default)]
77 pub middleware: MiddlewareConfig,
78}
79
80impl Config for YamlConfig {
81 fn server(&self) -> &ServerConfig {
82 &self.server
83 }
84
85 fn logger(&self) -> &LoggerConfig {
86 &self.logger
87 }
88
89 fn middleware(&self) -> &MiddlewareConfig {
90 &self.middleware
91 }
92}
93
94impl YamlConfig {
95 pub fn load() -> std::io::Result<Self> {
97 Self::load_env(Environment::get_env())
98 }
99
100 pub fn load_env(env: Environment) -> std::io::Result<Self> {
102 let path = format!("config/{}.yml", env.as_str());
103 let contents = std::fs::read_to_string(&path)?;
104 Self::from_yaml(&contents)
105 }
106
107 pub fn from_yaml(yaml: &str) -> std::io::Result<Self> {
109 serde_norway::from_str(yaml)
110 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))
111 }
112}
113
114pub fn load() -> Box<dyn Config> {
117 Box::new(YamlConfig::load().unwrap_or_default())
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123
124 #[test]
125 fn parses_logger_level() {
126 let config = YamlConfig::from_yaml("logger:\n level: debug\n").unwrap();
127 assert_eq!(config.logger().level, "debug");
128 assert_eq!(
129 config.logger().directives(),
130 doido_core::logger::directives_for_level("debug")
131 );
132 }
133
134 #[test]
135 fn explicit_directives_override_level() {
136 let yaml = "logger:\n level: info\n directives: warn,my_app=debug\n";
137 let config = YamlConfig::from_yaml(yaml).unwrap();
138 assert_eq!(config.logger().directives(), "warn,my_app=debug");
139 }
140
141 #[test]
142 fn defaults_to_info_when_logger_section_absent() {
143 let config = YamlConfig::from_yaml("server:\n bind: 0.0.0.0\n port: 3000\n").unwrap();
144 assert_eq!(config.logger().level, "info");
145 assert!(config.logger().sql);
146 assert!(config.logger().file.is_none());
147 assert_eq!(
148 config.logger().directives(),
149 doido_core::logger::DEFAULT_DIRECTIVES
150 );
151 }
152}