use std::time::Instant;
use tracing::{debug, warn};
#[derive(Debug, Clone)]
pub struct GlobalTimer {
pub base_timestamp: i64,
pub base_instant: Instant,
pub last_sync_at: Instant,
}
impl GlobalTimer {
pub fn new(initial_timestamp: i64) -> Self {
let base_instant = Instant::now();
debug!("初始化全局计时器,时间戳: {}", initial_timestamp);
Self {
base_timestamp: initial_timestamp,
base_instant,
last_sync_at: base_instant,
}
}
pub fn get_current_timestamp(&self) -> i64 {
let elapsed_secs = self.base_instant.elapsed().as_secs() as i64;
self.base_timestamp + elapsed_secs
}
pub fn detect_clock_jump(&self, new_ntp_timestamp: i64, threshold: i64) -> bool {
let current_estimate = self.get_current_timestamp();
let drift = (new_ntp_timestamp - current_estimate).abs();
if drift > threshold {
warn!(
drift_secs = drift,
threshold_secs = threshold,
"检测到系统时钟跳跃"
);
true
} else {
debug!(drift_secs = drift, "系统时钟漂移在正常范围内");
false
}
}
pub fn update_timestamp(&mut self, new_timestamp: i64, is_jump: bool) {
self.base_timestamp = new_timestamp;
self.base_instant = Instant::now();
self.last_sync_at = self.base_instant;
if is_jump {
warn!("检测到系统时钟跳跃,重新初始化计时器");
} else {
debug!("基准时间戳已更新(漂移纠正)");
}
}
pub fn should_sync(&self, sync_interval: u64) -> bool {
self.last_sync_at.elapsed().as_secs() >= sync_interval
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::thread;
#[test]
fn test_timer_creation() {
let timer = GlobalTimer::new(1000);
assert_eq!(timer.base_timestamp, 1000);
}
#[test]
fn test_get_current_timestamp() {
let timer = GlobalTimer::new(1000);
thread::sleep(std::time::Duration::from_millis(100));
let ts = timer.get_current_timestamp();
assert!(ts >= 1000);
}
#[test]
fn test_detect_clock_jump() {
let timer = GlobalTimer::new(1000);
assert!(!timer.detect_clock_jump(1001, 5));
assert!(timer.detect_clock_jump(1010, 5));
}
#[test]
fn test_update_timestamp() {
let mut timer = GlobalTimer::new(1000);
timer.update_timestamp(2000, true);
assert_eq!(timer.base_timestamp, 2000);
}
#[test]
fn test_should_sync() {
let timer = GlobalTimer::new(1000);
assert!(!timer.should_sync(10));
thread::sleep(std::time::Duration::from_secs(1));
assert!(timer.should_sync(0));
}
}