use std::path::{Path, PathBuf};
use serde::{Deserialize, Serialize};
use crate::error::{CsafError, Result};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppConfig {
#[serde(default = "default_listen_addr")]
pub listen_addr: String,
#[serde(default = "default_listen_port")]
pub listen_port: u16,
#[serde(default = "default_data_dir")]
pub data_dir: PathBuf,
pub tls_cert: Option<PathBuf>,
pub tls_key: Option<PathBuf>,
}
impl Default for AppConfig {
fn default() -> Self {
Self {
listen_addr: default_listen_addr(),
listen_port: default_listen_port(),
data_dir: default_data_dir(),
tls_cert: None,
tls_key: None,
}
}
}
impl AppConfig {
pub fn load(path: &Path) -> Result<Self> {
if path.exists() {
let content =
std::fs::read_to_string(path).map_err(|e| CsafError::Config(e.to_string()))?;
toml::from_str(&content).map_err(|e| CsafError::Config(e.to_string()))
} else {
Ok(Self::default())
}
}
#[must_use]
pub fn redb_path(&self) -> PathBuf {
self.data_dir.join("csaf.redb")
}
#[must_use]
pub fn sqlite_path(&self) -> PathBuf {
self.data_dir.join("csaf.sqlite")
}
#[must_use]
pub fn listen_address(&self) -> String {
format!("{}:{}", self.listen_addr, self.listen_port)
}
}
fn default_listen_addr() -> String {
"127.0.0.1".to_owned()
}
const fn default_listen_port() -> u16 {
8443
}
fn default_data_dir() -> PathBuf {
PathBuf::from("./data")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let config = AppConfig::default();
assert_eq!(config.listen_addr, "127.0.0.1");
assert_eq!(config.listen_port, 8443);
assert_eq!(config.listen_address(), "127.0.0.1:8443");
assert_eq!(config.redb_path(), PathBuf::from("./data/csaf.redb"));
assert_eq!(config.sqlite_path(), PathBuf::from("./data/csaf.sqlite"));
}
#[test]
fn test_load_missing_file_uses_defaults() {
let config =
AppConfig::load(Path::new("/nonexistent/config.toml")).expect("should return defaults");
assert_eq!(config.listen_port, 8443);
}
}