1use serde::Deserialize;
6
7pub static CONFIG: once_cell::sync::OnceCell<BabyriteConfig> = once_cell::sync::OnceCell::new();
9
10#[derive(Deserialize, Debug)]
12pub struct EnvConfig {
13 pub discord_api_token: String,
15 #[serde(default)]
17 #[serde(deserialize_with = "crate::config::empty_string_as_none")]
18 pub config_file_path: Option<String>,
19}
20
21impl EnvConfig {
22 pub fn get() -> &'static EnvConfig {
26 static ENV_CONFIG: std::sync::OnceLock<EnvConfig> = std::sync::OnceLock::new();
27 ENV_CONFIG
28 .get_or_init(|| envy::from_env().expect("Failed to load environment configuration."))
29 }
30}
31
32#[derive(Deserialize, Debug, Default)]
36pub struct BabyriteConfig {
37 #[serde(default)]
39 pub json_logging: bool,
40}
41
42#[derive(thiserror::Error, Debug)]
44pub enum BabyriteConfigError {
45 #[error("Failed to read configuration file.")]
47 Read,
48 #[error("Failed to parse configuration file.")]
50 Parse,
51 #[error("Failed to set configuration file.")]
53 Set,
54}
55
56impl BabyriteConfig {
57 pub fn init() -> anyhow::Result<(), BabyriteConfigError> {
62 let envs = EnvConfig::get();
63 match &envs.config_file_path {
64 Some(p) => {
65 let buffer = &std::fs::read_to_string(p).map_err(|_| BabyriteConfigError::Read)?;
66 let config: BabyriteConfig =
67 toml::from_str(buffer).map_err(|_| BabyriteConfigError::Parse)?;
68 Ok(CONFIG.set(config).map_err(|_| BabyriteConfigError::Parse)?)
69 }
70 None => Ok(CONFIG
71 .set(BabyriteConfig::default())
72 .map_err(|_| BabyriteConfigError::Set)?),
73 }
74 }
75
76 pub fn get() -> &'static BabyriteConfig {
82 CONFIG.get().expect("Failed to get configuration.")
83 }
84}
85
86pub fn empty_string_as_none<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
88where
89 D: serde::Deserializer<'de>,
90{
91 let opt = Option::<String>::deserialize(deserializer)?;
92 Ok(opt.filter(|s| !s.is_empty()))
93}