use crate::secret_validation::SecretFormat; use crate::utils::error::MultihookResult; use config::{Config, File}; use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::fs; use std::path::{Path, PathBuf}; #[derive(Serialize, Deserialize, Clone, Debug)] pub struct Settings { pub server: ServerSettings, pub hooks: Option, pub endpoints: HashMap, } #[derive(Serialize, Deserialize, Clone, Debug)] pub struct ServerSettings { pub address: Option, } #[derive(Serialize, Deserialize, Default, Clone, Debug)] pub struct Hooks { pub pre_action: Option, pub post_action: Option, pub err_action: Option, } #[derive(Serialize, Deserialize, Clone, Debug)] pub struct EndpointSettings { pub path: String, pub action: String, pub hooks: Option, #[serde(default)] pub allow_parallel: bool, #[serde(default)] pub run_detached: bool, pub secret: Option, } #[derive(Serialize, Deserialize, Clone, Debug)] pub struct SecretSettings { pub value: String, pub format: SecretFormat, } impl Default for Settings { fn default() -> Self { Self { endpoints: HashMap::new(), server: ServerSettings { address: None }, hooks: None, } } } pub fn get_settings() -> &'static Settings { lazy_static! { static ref SETTINGS: Settings = load_settings().expect("Failed to get settings"); } &*SETTINGS } fn load_settings() -> MultihookResult { let config_dir = dirs::config_dir() .map(|c| c.join("multihook")) .unwrap_or(PathBuf::from(".config")); if !Path::new(&config_dir).exists() { fs::create_dir(&config_dir)?; write_toml_pretty( &config_dir.clone().join("config.toml"), &Settings::default(), )?; } let settings = Config::builder() .add_source( glob::glob(&format!("{}/*.toml", config_dir.to_string_lossy())) .unwrap() .map(|path| File::from(path.unwrap())) .collect::>(), ) .add_source(config::Environment::with_prefix("MULTIHOOK")) .add_source(File::from(PathBuf::from(".multihook.toml")).required(false)) .build()?; let settings: Settings = settings.try_deserialize()?; Ok(settings) } fn write_toml_pretty(path: &PathBuf, value: &T) -> MultihookResult<()> { fs::write(path, toml::to_string_pretty(value)?)?; Ok(()) }