wx_rust_common/clock.rs
1//! 可注入时钟抽象(WxClock)。
2//!
3//! 用途:token/ticket 过期判断的时间来源可注入——默认 [`SystemClock`]
4//! 与直接读 `SystemTime` 逐字节一致;测试注入 [`FakeClock`] 手动推进
5//! 时间即可验证过期翻转,零 sleep(计划 Task 8)。
6//!
7//! 单位约定:`now_ms` 返回 UNIX 纪元毫秒;config 侧过期存储为 UNIX 秒,
8//! 换算 `now_ms() / 1000`(默认路径与 `SystemTime::as_secs()` 相等)。
9//!
10//! 注入方式:实例级注入(如 `WxDefaultConfig::set_clock`),不做进程级
11//! 全局时钟——全局可变静态会波及所有配置实例并在测试并行时互相干扰。
12
13use std::fmt::Debug;
14use std::sync::Arc;
15use std::sync::atomic::{AtomicI64, Ordering};
16
17/// 时钟抽象(可注入)。
18///
19/// `Debug` 为超 trait:携带 clock 的配置结构(如 `WxDefaultConfig`)
20/// 可继续 derive `Debug`。
21pub trait WxClock: Send + Sync + Debug {
22 /// 当前时间(UNIX 纪元毫秒)。
23 fn now_ms(&self) -> i64;
24}
25
26/// 系统真实时钟(默认实现,行为与直接读 `SystemTime` 一致)。
27#[derive(Debug, Clone, Copy, Default)]
28pub struct SystemClock;
29
30impl WxClock for SystemClock {
31 fn now_ms(&self) -> i64 {
32 std::time::SystemTime::now()
33 .duration_since(std::time::UNIX_EPOCH)
34 .map(|d| d.as_millis() as i64)
35 .unwrap_or(0)
36 }
37}
38
39/// 手动推进的假时钟(仅测试使用)。
40///
41/// 内部 `Arc<AtomicI64>` 共享时间源:`clone()` 后各句柄推进同一时钟,
42/// 测试句柄与注入 config 的实例互通。
43#[derive(Debug, Clone)]
44pub struct FakeClock(pub Arc<AtomicI64>);
45
46impl FakeClock {
47 /// 构建起始时间为 `start_ms`(UNIX 毫秒)的假时钟。
48 pub fn new(start_ms: i64) -> Self {
49 Self(Arc::new(AtomicI64::new(start_ms)))
50 }
51
52 /// 推进时间(毫秒;负值即回拨)。
53 pub fn advance_ms(&self, delta: i64) {
54 self.0.fetch_add(delta, Ordering::SeqCst);
55 }
56}
57
58impl WxClock for FakeClock {
59 fn now_ms(&self) -> i64 {
60 self.0.load(Ordering::SeqCst)
61 }
62}