Skip to main content

oxide_framework_core/
config.rs

1use serde::Deserialize;
2use std::path::Path;
3
4#[derive(Debug, Clone, Deserialize)]
5pub struct AppConfig {
6    #[serde(default = "default_host")]
7    pub host: String,
8    #[serde(default = "default_port")]
9    pub port: u16,
10    #[serde(default)]
11    pub app_name: String,
12}
13
14fn default_host() -> String {
15    "127.0.0.1".to_string()
16}
17
18fn default_port() -> u16 {
19    3000
20}
21
22impl Default for AppConfig {
23    fn default() -> Self {
24        Self {
25            host: default_host(),
26            port: default_port(),
27            app_name: String::from("oxide-app"),
28        }
29    }
30}
31
32impl AppConfig {
33    /// Load config from a YAML file, then overlay any matching environment
34    /// variables. Missing file is not an error — defaults are used instead.
35    pub fn load(path: Option<&str>) -> Self {
36        let mut cfg = match path {
37            Some(p) if Path::new(p).exists() => {
38                let contents = std::fs::read_to_string(p)
39                    .unwrap_or_else(|e| panic!("failed to read config file {p}: {e}"));
40                serde_yaml::from_str(&contents)
41                    .unwrap_or_else(|e| panic!("failed to parse config file {p}: {e}"))
42            }
43            _ => Self::default(),
44        };
45
46        // Environment variable overrides (OXIDE_ prefix)
47        if let Ok(v) = std::env::var("OXIDE_HOST") {
48            cfg.host = v;
49        }
50        if let Ok(v) = std::env::var("OXIDE_PORT") {
51            if let Ok(port) = v.parse::<u16>() {
52                cfg.port = port;
53            }
54        }
55        if let Ok(v) = std::env::var("OXIDE_APP_NAME") {
56            cfg.app_name = v;
57        }
58
59        cfg
60    }
61}
62