use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
pub sync_interval_secs: u64,
pub clock_jump_threshold_secs: i64,
pub ntp_servers: Vec<String>,
pub max_retries: usize,
pub socket_timeout_secs: u64,
}
impl Default for Config {
fn default() -> Self {
Self {
sync_interval_secs: 600,
clock_jump_threshold_secs: 5,
ntp_servers: vec![
"ntp.ntsc.ac.cn".to_string(),
"time1.ntsc.ac.cn".to_string(),
"time2.ntsc.ac.cn".to_string(),
],
max_retries: 3,
socket_timeout_secs: 5,
}
}
}
impl Config {
pub fn new() -> Self {
Self::default()
}
pub fn with_sync_interval(mut self, secs: u64) -> Self {
self.sync_interval_secs = secs;
self
}
pub fn with_jump_threshold(mut self, secs: i64) -> Self {
self.clock_jump_threshold_secs = secs;
self
}
pub fn with_ntp_servers(mut self, servers: Vec<String>) -> Self {
self.ntp_servers = servers;
self
}
pub fn with_max_retries(mut self, retries: usize) -> Self {
self.max_retries = retries;
self
}
pub fn with_socket_timeout(mut self, secs: u64) -> Self {
self.socket_timeout_secs = secs;
self
}
pub fn validate(&self) -> Result<(), String> {
if self.sync_interval_secs == 0 {
return Err("同步间隔必须 > 0".to_string());
}
if self.clock_jump_threshold_secs < 0 {
return Err("时钟跳跃阈值必须 >= 0".to_string());
}
if self.ntp_servers.is_empty() {
return Err("NTP 服务器列表不能为空".to_string());
}
if self.max_retries == 0 {
return Err("最大重试次数必须 > 0".to_string());
}
if self.socket_timeout_secs == 0 {
return Err("套接字超时必须 > 0".to_string());
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let config = Config::default();
assert_eq!(config.sync_interval_secs, 600);
assert_eq!(config.clock_jump_threshold_secs, 5);
assert_eq!(config.max_retries, 3);
assert_eq!(config.socket_timeout_secs, 5);
}
#[test]
fn test_builder_pattern() {
let config = Config::new()
.with_sync_interval(300)
.with_jump_threshold(3)
.with_max_retries(5);
assert_eq!(config.sync_interval_secs, 300);
assert_eq!(config.clock_jump_threshold_secs, 3);
assert_eq!(config.max_retries, 5);
}
#[test]
fn test_config_validation() {
let config = Config::default();
assert!(config.validate().is_ok());
let invalid = Config {
sync_interval_secs: 0,
..Default::default()
};
assert!(invalid.validate().is_err());
}
}