rust_template_foundation/
config.rs1use serde::de::DeserializeOwned;
8use std::path::{Path, PathBuf};
9use thiserror::Error;
10
11#[derive(Debug, Error)]
14pub enum ConfigFileError {
15 #[error(
16 "Failed to read configuration file at {path:?} during startup: {source}"
17 )]
18 FileRead {
19 path: PathBuf,
20 #[source]
21 source: std::io::Error,
22 },
23
24 #[error("Failed to parse configuration file at {path:?}: {source}")]
25 Parse {
26 path: PathBuf,
27 #[source]
28 source: toml::de::Error,
29 },
30}
31
32pub fn xdg_config_dir(app_name: &str) -> Option<PathBuf> {
37 std::env::var_os("XDG_CONFIG_HOME")
38 .map(PathBuf::from)
39 .or_else(|| home::home_dir().map(|h| h.join(".config")))
40 .map(|d| d.join(app_name))
41}
42
43pub fn find_config_file(
58 app_name: &str,
59 explicit_path: Option<&Path>,
60) -> Option<PathBuf> {
61 if let Some(p) = explicit_path {
62 return Some(p.to_path_buf());
63 }
64
65 xdg_config_dir(app_name)
66 .map(|d| d.join("config.toml"))
67 .filter(|p| p.exists())
68}
69
70pub fn load_toml<T: DeserializeOwned>(
73 path: &Path,
74) -> Result<T, ConfigFileError> {
75 let contents = std::fs::read_to_string(path).map_err(|source| {
76 ConfigFileError::FileRead {
77 path: path.to_path_buf(),
78 source,
79 }
80 })?;
81
82 toml::from_str(&contents).map_err(|source| ConfigFileError::Parse {
83 path: path.to_path_buf(),
84 source,
85 })
86}
87
88#[derive(Debug, serde::Deserialize, Default)]
99pub struct CommonConfigFile {
100 pub log_level: Option<String>,
101 pub log_format: Option<String>,
102}
103
104#[cfg(feature = "server")]
108pub fn credential_secret_path() -> Option<PathBuf> {
109 let dir = std::env::var("CREDENTIALS_DIRECTORY").ok()?;
110 let path = PathBuf::from(dir).join("oidc-client-secret");
111 path.exists().then_some(path)
112}
113
114pub fn resolve_log_settings(
119 cli_level: Option<String>,
120 cli_format: Option<String>,
121 file: &CommonConfigFile,
122) -> Result<(crate::logging::LogLevel, crate::logging::LogFormat), String> {
123 let level_str = cli_level
124 .or_else(|| file.log_level.clone())
125 .unwrap_or_else(|| "info".to_string());
126
127 let level = level_str
128 .parse::<crate::logging::LogLevel>()
129 .map_err(|e| e.to_string())?;
130
131 let format_str = cli_format
132 .or_else(|| file.log_format.clone())
133 .unwrap_or_else(|| "text".to_string());
134
135 let format = format_str
136 .parse::<crate::logging::LogFormat>()
137 .map_err(|e| e.to_string())?;
138
139 Ok((level, format))
140}