Skip to main content

infraqueue_lib/
config.rs

1use std::env;
2use std::fs;
3use std::path::Path;
4
5/// Read an environment variable as u64 with a default fallback.
6/// Returns `default` if the var is missing or cannot be parsed.
7pub fn env_u64(name: &str, default: u64) -> u64 {
8    env::var(name)
9        .ok()
10        .and_then(|v| v.parse::<u64>().ok())
11        .unwrap_or(default)
12}
13
14/// Read an environment variable as u32 with a default fallback.
15/// Returns `default` if the var is missing or cannot be parsed.
16pub fn env_u32(name: &str, default: u32) -> u32 {
17    env::var(name)
18        .ok()
19        .and_then(|v| v.parse::<u32>().ok())
20        .unwrap_or(default)
21}
22
23/// Read an environment variable as f64 with a default fallback.
24/// Returns `default` if the var is missing or cannot be parsed.
25pub fn env_f64(name: &str, default: f64) -> f64 {
26    env::var(name)
27        .ok()
28        .and_then(|v| v.parse::<f64>().ok())
29        .unwrap_or(default)
30}
31
32/// Read a configuration value from either a direct environment variable `NAME`
33/// or from a file path specified via `NAME_FILE`. If both are set, `NAME` takes precedence.
34/// Returns `Some(value)` if found, otherwise `None`.
35pub fn env_var_or_file(name: &str) -> Option<String> {
36    if let Ok(v) = env::var(name) {
37        if !v.is_empty() {
38            return Some(v);
39        }
40    }
41    let file_key = format!("{}_FILE", name);
42    if let Ok(path) = env::var(&file_key) {
43        if !path.is_empty() {
44            let p = Path::new(&path);
45            if let Ok(bytes) = fs::read(p) {
46                let mut s = String::from_utf8_lossy(&bytes).to_string();
47                // Trim common trailing newlines
48                while s.ends_with('\n') || s.ends_with('\r') {
49                    s.pop();
50                }
51                if !s.is_empty() {
52                    return Some(s);
53                }
54            }
55        }
56    }
57    None
58}
59
60/// Same as `env_var_or_file`, but returns an error message when not found.
61pub fn env_var_or_file_required(name: &str) -> Result<String, String> {
62    env_var_or_file(name)
63        .ok_or_else(|| format!("{} is required (set {} or {}_FILE)", name, name, name))
64}