mod general_config; mod providers; use std::hash::Hash; use std::{collections::HashMap, sync::OnceLock}; use std::fs; use std::path::Path; use clap::builder::Str; use serde::{ser, Deserialize}; use crate::services::beggars::Beggars; use crate::services::providers::Providers; use crate::errors::AutoDecryptError; use general_config::{Platform, TomlAppConfig}; #[derive(Debug, Deserialize)] pub(crate) struct AppConfig { pub(crate) port: u16, pub(crate) addresses: Vec, pub(crate) platform: Platform, pub(crate) ssh_known_host_file: String, pub(crate) user_confirmation_expiration: i64, pub(crate) db_file: String, pub(crate) crypto_key: String, pub(crate) beggars: HashMap, // We request to unlock owned services pub(crate) providers: HashMap, // We offer to unlock these services } impl Default for AppConfig { fn default() -> Self { AppConfig { port: 8080, addresses: vec!["*".to_string()], beggars: HashMap::new(), crypto_key: "default_key_change_me".to_string(), providers: HashMap::new(), user_confirmation_expiration: 60 * 60 * 24, // 24 hours platform: Platform::OMV, ssh_known_host_file: "".to_string(), db_file: "/var/auto-decrypt/db.sqlite".to_string(), } } } impl AppConfig { fn from_toml(toml_config: Option, base_config_dir: &Path) -> Self { let default = AppConfig::default(); if let Some(toml_config) = toml_config { return AppConfig { port: toml_config.port.unwrap_or(default.port), addresses: toml_config.addresses.unwrap_or(default.addresses), crypto_key: toml_config.crypto_key.unwrap_or(default.crypto_key), platform: toml_config.platform.unwrap_or(default.platform), user_confirmation_expiration: toml_config.user_confirmation_expiration.unwrap_or(default.user_confirmation_expiration), ssh_known_host_file: toml_config.ssh_known_host_file.unwrap_or(default.ssh_known_host_file), db_file: toml_config.db_file.unwrap_or(default.db_file), beggars: toml_config.beggars.unwrap_or(default.beggars), providers: toml_config.providers.and_then(|providers| Some(providers.into_iter().map(|(name, service)| (name, service.to_internal(base_config_dir).expect("Err")) ).collect::>()) ).unwrap_or(default.providers), }; } return default; } } impl AppConfig { pub fn load_from_file(path: &Path ) -> Result { if !path.is_dir(){ return Err(AutoDecryptError::ConfigurationError { comment: ("The provided configuration path is not a Folder!".to_string()) }) } let contents = fs::read_to_string(path.join("config.toml")) .unwrap_or_else(|err| { eprintln!("Failed to read config file: {err}. Using default configuration."); return String::new(); // Return empty string to fall back to default }); let basic_config = AppConfig::from_toml( toml::from_str::(&contents) .map_err(|err| { eprintln!("Failed to parse config file: {err}. Using default configuration."); err }) .ok() , path); return Ok(basic_config); } } pub static CONFIG: OnceLock = OnceLock::new(); pub fn init_config(file: &str) { let config = AppConfig::load_from_file(Path::new(file)) .expect("Failed to load configuration file"); CONFIG.set(config).expect("AppConfig can only be initialized once"); }