1use std::path::{Path, PathBuf};
7
8use serde::{Deserialize, Serialize};
9
10use crate::error::{CsafError, Result};
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct AppConfig {
18 #[serde(default = "default_listen_addr")]
20 pub listen_addr: String,
21
22 #[serde(default = "default_listen_port")]
24 pub listen_port: u16,
25
26 #[serde(default = "default_data_dir")]
28 pub data_dir: PathBuf,
29
30 pub tls_cert: Option<PathBuf>,
32
33 pub tls_key: Option<PathBuf>,
35}
36
37impl Default for AppConfig {
38 fn default() -> Self {
39 Self {
40 listen_addr: default_listen_addr(),
41 listen_port: default_listen_port(),
42 data_dir: default_data_dir(),
43 tls_cert: None,
44 tls_key: None,
45 }
46 }
47}
48
49impl AppConfig {
50 pub fn load(path: &Path) -> Result<Self> {
56 if path.exists() {
57 let content =
58 std::fs::read_to_string(path).map_err(|e| CsafError::Config(e.to_string()))?;
59 toml::from_str(&content).map_err(|e| CsafError::Config(e.to_string()))
60 } else {
61 Ok(Self::default())
62 }
63 }
64
65 #[must_use]
67 pub fn redb_path(&self) -> PathBuf {
68 self.data_dir.join("csaf.redb")
69 }
70
71 #[must_use]
73 pub fn sqlite_path(&self) -> PathBuf {
74 self.data_dir.join("csaf.sqlite")
75 }
76
77 #[must_use]
79 pub fn listen_address(&self) -> String {
80 format!("{}:{}", self.listen_addr, self.listen_port)
81 }
82}
83
84fn default_listen_addr() -> String {
85 "127.0.0.1".to_owned()
86}
87
88const fn default_listen_port() -> u16 {
89 8443
90}
91
92fn default_data_dir() -> PathBuf {
93 PathBuf::from("./data")
94}
95
96#[cfg(test)]
97mod tests {
98 use super::*;
99
100 #[test]
101 fn test_default_config() {
102 let config = AppConfig::default();
103 assert_eq!(config.listen_addr, "127.0.0.1");
104 assert_eq!(config.listen_port, 8443);
105 assert_eq!(config.listen_address(), "127.0.0.1:8443");
106 assert_eq!(config.redb_path(), PathBuf::from("./data/csaf.redb"));
107 assert_eq!(config.sqlite_path(), PathBuf::from("./data/csaf.sqlite"));
108 }
109
110 #[test]
111 fn test_load_missing_file_uses_defaults() {
112 let config =
113 AppConfig::load(Path::new("/nonexistent/config.toml")).expect("should return defaults");
114 assert_eq!(config.listen_port, 8443);
115 }
116}