1use crate::config::Config;
2use crate::error::TimerError;
3use crate::ntp;
4use crate::timer::GlobalTimer;
5use lazy_static::lazy_static;
6use std::sync::{Arc, Mutex};
7use std::time::Duration;
8use tracing::{debug, info, warn};
9
10lazy_static! {
11 static ref GLOBAL_TIMER: Arc<Mutex<Option<GlobalTimer>>> = Arc::new(Mutex::new(None));
12 static ref CONFIG: Arc<Mutex<Option<Arc<Config>>>> = Arc::new(Mutex::new(None));
13}
14
15pub struct TimerManager;
17
18impl TimerManager {
19 pub async fn init_global_timer(config: Arc<Config>) -> Result<(), TimerError> {
24 config.validate().map_err(TimerError::ConfigError)?;
25
26 let mut config_guard = CONFIG
27 .lock()
28 .map_err(|e| TimerError::LockError(e.to_string()))?;
29
30 if config_guard.is_none() {
31 *config_guard = Some(Arc::clone(&config));
32 }
33 drop(config_guard);
34
35 let mut timer_guard = GLOBAL_TIMER
36 .lock()
37 .map_err(|e| TimerError::LockError(e.to_string()))?;
38
39 if timer_guard.is_none() {
40 let base_timestamp = ntp::get_ntp_timestamp(&config)?;
41 let timer = GlobalTimer::new(base_timestamp);
42 *timer_guard = Some(timer);
43 drop(timer_guard);
44
45 TimerManager::spawn_background_sync();
46 }
47
48 Ok(())
49 }
50
51 pub fn get_timestamp() -> Result<i64, TimerError> {
56 let timer_guard = GLOBAL_TIMER
57 .lock()
58 .map_err(|e| TimerError::LockError(e.to_string()))?;
59
60 match timer_guard.as_ref() {
61 Some(timer) => Ok(timer.get_current_timestamp()),
62 None => Err(TimerError::NotInitialized),
63 }
64 }
65
66 pub async fn manual_sync() -> Result<i64, TimerError> {
68 let config_opt = {
69 let config_guard = CONFIG
70 .lock()
71 .map_err(|e| TimerError::LockError(e.to_string()))?;
72 config_guard.as_ref().map(Arc::clone)
73 };
74
75 let config = config_opt.ok_or(TimerError::NotInitialized)?;
76
77 let new_ntp_timestamp = ntp::get_ntp_timestamp(&config)?;
78
79 let mut timer_guard = GLOBAL_TIMER
80 .lock()
81 .map_err(|e| TimerError::LockError(e.to_string()))?;
82
83 match timer_guard.as_mut() {
84 Some(timer) => {
85 if timer.detect_clock_jump(new_ntp_timestamp, config.clock_jump_threshold_secs) {
86 timer.update_timestamp(new_ntp_timestamp, true);
87 } else {
88 timer.update_timestamp(new_ntp_timestamp, false);
89 }
90
91 let timestamp = timer.get_current_timestamp();
92 info!(timestamp, "NTP 同步完成");
93 Ok(timestamp)
94 }
95 None => Err(TimerError::NotInitialized),
96 }
97 }
98
99 fn spawn_background_sync() {
101 tokio::spawn(async {
102 loop {
103 let sync_interval = {
104 let config_guard = CONFIG.lock().ok();
105 config_guard.and_then(|g| g.as_ref().map(|c| c.sync_interval_secs))
106 };
107
108 if let Some(interval) = sync_interval {
109 tokio::time::sleep(Duration::from_secs(interval)).await;
110
111 match TimerManager::manual_sync().await {
112 Ok(_) => {
113 debug!("后台同步完成");
114 }
115 Err(e) => {
116 warn!("后台同步失败,继续使用本地计时器: {}", e);
117 }
118 }
119 } else {
120 tokio::time::sleep(Duration::from_secs(1)).await;
121 }
122 }
123 });
124 }
125
126 #[cfg(test)]
128 pub fn reset() {
129 if let Ok(mut timer_guard) = GLOBAL_TIMER.lock() {
130 *timer_guard = None;
131 }
132 if let Ok(mut config_guard) = CONFIG.lock() {
133 *config_guard = None;
134 }
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141
142 #[tokio::test]
143 async fn test_manual_sync_without_init() {
144 TimerManager::reset();
145 let result = TimerManager::manual_sync().await;
146 assert!(result.is_err());
147 }
148}