1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7pub struct ProbeConfig {
8 #[serde(default)]
9 pub probe: ProbeSettings,
10
11 #[serde(default)]
12 pub network: NetworkSettings,
13
14 #[serde(default)]
15 pub controller: ControllerSettings,
16
17 #[serde(default)]
18 pub storage: StorageSettings,
19
20 #[serde(default)]
21 pub metrics: MetricsSettings,
22
23 #[serde(default)]
24 pub logging: LoggingSettings,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct ProbeSettings {
29 #[serde(default = "default_log_level")]
31 pub log_level: String,
32}
33
34impl Default for ProbeSettings {
35 fn default() -> Self {
36 Self {
37 log_level: default_log_level(),
38 }
39 }
40}
41
42#[derive(Debug, Clone, Default, Serialize, Deserialize)]
43pub struct NetworkSettings {
44 #[serde(default)]
45 pub rxtxrpt: bool,
46
47 #[serde(default)]
50 pub status_socket: bool,
51}
52
53#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct ControllerSettings {
55 #[serde(default = "default_registration_servers")]
56 pub registration_servers: Vec<String>,
57
58 #[serde(default = "default_ssh_timeout")]
59 pub ssh_timeout: u64,
60
61 #[serde(default = "default_keepalive_interval")]
62 pub keepalive_interval: u64,
63}
64
65impl Default for ControllerSettings {
66 fn default() -> Self {
67 Self {
68 registration_servers: default_registration_servers(),
69 ssh_timeout: default_ssh_timeout(),
70 keepalive_interval: default_keepalive_interval(),
71 }
72 }
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct StorageSettings {
77 #[serde(default = "default_max_queue_size")]
79 pub max_queue_size: usize,
80
81 #[serde(default = "default_retention_days")]
82 pub retention_days: u32,
83}
84
85impl Default for StorageSettings {
86 fn default() -> Self {
87 Self {
88 max_queue_size: default_max_queue_size(),
89 retention_days: default_retention_days(),
90 }
91 }
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize)]
95pub struct MetricsSettings {
96 #[serde(default = "default_metrics_enabled")]
97 pub enabled: bool,
98
99 #[serde(default = "default_metrics_listen_addr")]
100 pub listen_addr: String,
101}
102
103impl Default for MetricsSettings {
104 fn default() -> Self {
105 Self {
106 enabled: default_metrics_enabled(),
107 listen_addr: default_metrics_listen_addr(),
108 }
109 }
110}
111
112#[derive(Debug, Clone, Serialize, Deserialize)]
113pub struct LoggingSettings {
114 #[serde(default = "default_log_format")]
115 pub format: String,
116
117 #[serde(default = "default_log_output")]
118 pub output: String,
119
120 #[serde(default = "default_max_file_size_mb")]
121 pub max_file_size_mb: u64,
122
123 #[serde(default = "default_max_files")]
124 pub max_files: u32,
125}
126
127impl Default for LoggingSettings {
128 fn default() -> Self {
129 Self {
130 format: default_log_format(),
131 output: default_log_output(),
132 max_file_size_mb: default_max_file_size_mb(),
133 max_files: default_max_files(),
134 }
135 }
136}
137
138fn default_log_level() -> String {
140 "info".to_string()
141}
142fn default_registration_servers() -> Vec<String> {
143 vec![
144 "reg03.atlas.ripe.net:443".to_string(),
146 "193.0.19.246:443".to_string(),
147 "[2001:67c:2e8:11::c100:13f6]:443".to_string(),
148 "reg04.atlas.ripe.net:443".to_string(),
150 "193.0.19.247:443".to_string(),
151 "[2001:67c:2e8:11::c100:13f7]:443".to_string(),
152 ]
153}
154fn default_ssh_timeout() -> u64 {
155 30
156}
157fn default_keepalive_interval() -> u64 {
158 60
159}
160fn default_max_queue_size() -> usize {
161 10000
162}
163fn default_retention_days() -> u32 {
164 30
165}
166fn default_metrics_enabled() -> bool {
167 true
168}
169fn default_metrics_listen_addr() -> String {
170 "127.0.0.1:9695".to_string()
171}
172fn default_log_format() -> String {
173 "json".to_string()
174}
175fn default_log_output() -> String {
176 "stdout".to_string()
177}
178fn default_max_file_size_mb() -> u64 {
179 10
180}
181fn default_max_files() -> u32 {
182 5
183}
184
185impl ProbeConfig {
186 pub fn from_file(path: &std::path::Path) -> Result<Self, crate::Error> {
188 let content = std::fs::read_to_string(path)
189 .map_err(|e| crate::Error::Config(format!("Failed to read config: {}", e)))?;
190
191 let config: ProbeConfig = toml::from_str(&content)
192 .map_err(|e| crate::Error::Config(format!("Failed to parse config: {}", e)))?;
193
194 Ok(config)
195 }
196
197 pub fn to_file(&self, path: &std::path::Path) -> Result<(), crate::Error> {
199 let content = toml::to_string_pretty(self)
200 .map_err(|e| crate::Error::Config(format!("Failed to serialize config: {}", e)))?;
201
202 std::fs::write(path, content)
203 .map_err(|e| crate::Error::Config(format!("Failed to write config: {}", e)))?;
204
205 Ok(())
206 }
207}
208
209#[cfg(test)]
210mod tests {
211 use super::*;
212
213 #[test]
214 fn test_default_config() {
215 let config = ProbeConfig::default();
216 assert_eq!(config.probe.log_level, "info");
217 assert!(!config.network.rxtxrpt);
218 }
219
220 #[test]
221 fn test_config_serde() {
222 let config = ProbeConfig::default();
223 let toml_str = toml::to_string(&config).unwrap();
224 let parsed: ProbeConfig = toml::from_str(&toml_str).unwrap();
225 assert_eq!(parsed.probe.log_level, "info");
226 }
227}