1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct ServerConfig {
8 pub id: String,
10 pub name: String,
12 pub host: String,
14 pub port: u16,
16 pub ssl: bool,
18 pub ssl_verify: bool,
20 pub username: Option<String>,
22 pub password: Option<String>,
24 pub connections: u16,
26 pub priority: u8,
28 pub enabled: bool,
30 pub retention: u32,
32 pub pipelining: u8,
34 pub optional: bool,
36 #[serde(default)]
38 pub compress: bool,
39 #[serde(default)]
42 pub ramp_up_delay_ms: u32,
43 #[serde(default = "default_recv_buffer_size")]
45 pub recv_buffer_size: u32,
46 #[serde(default)]
48 pub proxy_url: Option<String>,
49}
50
51fn default_recv_buffer_size() -> u32 {
53 2 * 1024 * 1024
54}
55
56impl Default for ServerConfig {
57 fn default() -> Self {
58 Self {
59 id: uuid::Uuid::new_v4().to_string(),
60 name: String::new(),
61 host: String::new(),
62 port: 563,
63 ssl: true,
64 ssl_verify: true,
65 username: None,
66 password: None,
67 connections: 8,
68 priority: 0,
69 enabled: true,
70 retention: 0,
71 pipelining: 1,
72 optional: false,
73 compress: false,
74 ramp_up_delay_ms: 250,
75 recv_buffer_size: default_recv_buffer_size(),
76 proxy_url: None,
77 }
78 }
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize)]
85pub struct ListActiveEntry {
86 pub name: String,
88 pub high: u64,
90 pub low: u64,
92 pub status: String,
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct Article {
99 pub message_id: String,
101 pub segment_number: u32,
103 pub bytes: u64,
105 pub downloaded: bool,
107 pub data_begin: Option<u64>,
109 pub data_size: Option<u64>,
111 pub crc32: Option<u32>,
113 pub tried_servers: Vec<String>,
115 pub tries: u32,
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[test]
124 fn test_article_serde_roundtrip() {
125 let article = Article {
126 message_id: "abc123@example.com".to_string(),
127 segment_number: 1,
128 bytes: 500_000,
129 downloaded: false,
130 data_begin: Some(0),
131 data_size: Some(499_000),
132 crc32: Some(0xDEADBEEF),
133 tried_servers: vec!["server1".to_string()],
134 tries: 2,
135 };
136
137 let json = serde_json::to_string(&article).unwrap();
138 let deserialized: Article = serde_json::from_str(&json).unwrap();
139
140 assert_eq!(deserialized.message_id, "abc123@example.com");
141 assert_eq!(deserialized.segment_number, 1);
142 assert_eq!(deserialized.bytes, 500_000);
143 assert!(!deserialized.downloaded);
144 assert_eq!(deserialized.data_begin, Some(0));
145 assert_eq!(deserialized.data_size, Some(499_000));
146 assert_eq!(deserialized.crc32, Some(0xDEADBEEF));
147 assert_eq!(deserialized.tried_servers, vec!["server1"]);
148 assert_eq!(deserialized.tries, 2);
149 }
150
151 #[test]
152 fn test_server_config_serde_roundtrip() {
153 let config = ServerConfig {
154 id: "srv1".to_string(),
155 name: "My Server".to_string(),
156 host: "news.example.com".to_string(),
157 port: 563,
158 ssl: true,
159 ssl_verify: true,
160 username: Some("user".to_string()),
161 password: Some("pass".to_string()),
162 connections: 8,
163 priority: 0,
164 enabled: true,
165 retention: 3000,
166 pipelining: 1,
167 optional: false,
168 compress: true,
169 ramp_up_delay_ms: 500,
170 recv_buffer_size: 2 * 1024 * 1024,
171 proxy_url: Some("socks5://proxy:1080".to_string()),
172 };
173
174 let toml_str = toml::to_string(&config).unwrap();
175 let deserialized: ServerConfig = toml::from_str(&toml_str).unwrap();
176
177 assert_eq!(deserialized.id, "srv1");
178 assert_eq!(deserialized.host, "news.example.com");
179 assert_eq!(deserialized.port, 563);
180 assert!(deserialized.ssl);
181 assert_eq!(deserialized.connections, 8);
182 assert_eq!(deserialized.retention, 3000);
183 assert!(deserialized.compress);
184 assert_eq!(
185 deserialized.proxy_url,
186 Some("socks5://proxy:1080".to_string())
187 );
188 }
189
190 #[test]
191 fn test_server_config_defaults() {
192 let config = ServerConfig::default();
193 assert!(!config.id.is_empty());
195 assert!(uuid::Uuid::parse_str(&config.id).is_ok());
196 assert_eq!(config.port, 563);
197 assert!(config.ssl);
198 assert!(config.ssl_verify);
199 assert_eq!(config.connections, 8);
200 assert_eq!(config.priority, 0);
201 assert!(config.enabled);
202 assert_eq!(config.retention, 0);
203 assert_eq!(config.pipelining, 1);
204 assert!(!config.optional);
205 assert!(!config.compress);
206 assert_eq!(config.ramp_up_delay_ms, 250);
207 assert!(config.proxy_url.is_none());
208 }
209
210 #[test]
211 fn test_list_active_entry_serde() {
212 let entry = ListActiveEntry {
213 name: "alt.binaries.test".to_string(),
214 high: 1_000_000,
215 low: 1,
216 status: "y".to_string(),
217 };
218
219 let json = serde_json::to_string(&entry).unwrap();
220 let deserialized: ListActiveEntry = serde_json::from_str(&json).unwrap();
221
222 assert_eq!(deserialized.name, "alt.binaries.test");
223 assert_eq!(deserialized.high, 1_000_000);
224 assert_eq!(deserialized.low, 1);
225 assert_eq!(deserialized.status, "y");
226 }
227}