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 "reg-05.prod.atlas.ripe.net:443".to_string(),
148 "193.0.19.75:443".to_string(),
149 "[2001:67c:2e8:11::c100:134b]:443".to_string(),
150 "reg-06.prod.atlas.ripe.net:443".to_string(),
151 "193.0.19.76:443".to_string(),
152 "[2001:67c:2e8:11::c100:134c]:443".to_string(),
153 ]
154}
155fn default_ssh_timeout() -> u64 {
156 30
157}
158fn default_keepalive_interval() -> u64 {
159 60
160}
161fn default_max_queue_size() -> usize {
162 10000
163}
164fn default_retention_days() -> u32 {
165 30
166}
167fn default_metrics_enabled() -> bool {
168 true
169}
170fn default_metrics_listen_addr() -> String {
171 "127.0.0.1:9695".to_string()
172}
173fn default_log_format() -> String {
174 "json".to_string()
175}
176fn default_log_output() -> String {
177 "stdout".to_string()
178}
179fn default_max_file_size_mb() -> u64 {
180 10
181}
182fn default_max_files() -> u32 {
183 5
184}
185
186impl ProbeConfig {
187 pub fn from_file(path: &std::path::Path) -> Result<Self, crate::Error> {
189 let content = std::fs::read_to_string(path)
190 .map_err(|e| crate::Error::Config(format!("Failed to read config: {}", e)))?;
191
192 let config: ProbeConfig = toml::from_str(&content)
193 .map_err(|e| crate::Error::Config(format!("Failed to parse config: {}", e)))?;
194
195 Ok(config)
196 }
197
198 pub fn to_file(&self, path: &std::path::Path) -> Result<(), crate::Error> {
200 let content = toml::to_string_pretty(self)
201 .map_err(|e| crate::Error::Config(format!("Failed to serialize config: {}", e)))?;
202
203 std::fs::write(path, content)
204 .map_err(|e| crate::Error::Config(format!("Failed to write config: {}", e)))?;
205
206 Ok(())
207 }
208}
209
210#[cfg(test)]
211mod tests {
212 use super::*;
213
214 #[test]
215 fn test_default_config() {
216 let config = ProbeConfig::default();
217 assert_eq!(config.probe.log_level, "info");
218 assert!(!config.network.rxtxrpt);
219 }
220
221 #[test]
222 fn test_config_serde() {
223 let config = ProbeConfig::default();
224 let toml_str = toml::to_string(&config).unwrap();
225 let parsed: ProbeConfig = toml::from_str(&toml_str).unwrap();
226 assert_eq!(parsed.probe.log_level, "info");
227 }
228}