1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct Config {
8 pub sync_interval_secs: u64,
10
11 pub clock_jump_threshold_secs: i64,
13
14 pub ntp_servers: Vec<String>,
16
17 pub max_retries: usize,
19
20 pub socket_timeout_secs: u64,
22}
23
24impl Default for Config {
25 fn default() -> Self {
26 Self {
27 sync_interval_secs: 600,
28 clock_jump_threshold_secs: 5,
29 ntp_servers: vec![
30 "ntp.ntsc.ac.cn".to_string(),
31 "time1.ntsc.ac.cn".to_string(),
32 "time2.ntsc.ac.cn".to_string(),
33 ],
34 max_retries: 3,
35 socket_timeout_secs: 5,
36 }
37 }
38}
39
40impl Config {
41 pub fn new() -> Self {
43 Self::default()
44 }
45
46 pub fn with_sync_interval(mut self, secs: u64) -> Self {
48 self.sync_interval_secs = secs;
49 self
50 }
51
52 pub fn with_jump_threshold(mut self, secs: i64) -> Self {
54 self.clock_jump_threshold_secs = secs;
55 self
56 }
57
58 pub fn with_ntp_servers(mut self, servers: Vec<String>) -> Self {
60 self.ntp_servers = servers;
61 self
62 }
63
64 pub fn with_max_retries(mut self, retries: usize) -> Self {
66 self.max_retries = retries;
67 self
68 }
69
70 pub fn with_socket_timeout(mut self, secs: u64) -> Self {
72 self.socket_timeout_secs = secs;
73 self
74 }
75
76 pub fn validate(&self) -> Result<(), String> {
78 if self.sync_interval_secs == 0 {
79 return Err("同步间隔必须 > 0".to_string());
80 }
81 if self.clock_jump_threshold_secs < 0 {
82 return Err("时钟跳跃阈值必须 >= 0".to_string());
83 }
84 if self.ntp_servers.is_empty() {
85 return Err("NTP 服务器列表不能为空".to_string());
86 }
87 if self.max_retries == 0 {
88 return Err("最大重试次数必须 > 0".to_string());
89 }
90 if self.socket_timeout_secs == 0 {
91 return Err("套接字超时必须 > 0".to_string());
92 }
93 Ok(())
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100
101 #[test]
102 fn test_default_config() {
103 let config = Config::default();
104 assert_eq!(config.sync_interval_secs, 600);
105 assert_eq!(config.clock_jump_threshold_secs, 5);
106 assert_eq!(config.max_retries, 3);
107 assert_eq!(config.socket_timeout_secs, 5);
108 }
109
110 #[test]
111 fn test_builder_pattern() {
112 let config = Config::new()
113 .with_sync_interval(300)
114 .with_jump_threshold(3)
115 .with_max_retries(5);
116
117 assert_eq!(config.sync_interval_secs, 300);
118 assert_eq!(config.clock_jump_threshold_secs, 3);
119 assert_eq!(config.max_retries, 5);
120 }
121
122 #[test]
123 fn test_config_validation() {
124 let config = Config::default();
125 assert!(config.validate().is_ok());
126
127 let invalid = Config {
128 sync_interval_secs: 0,
129 ..Default::default()
130 };
131 assert!(invalid.validate().is_err());
132 }
133}