1use std::{
4 cell::RefCell,
5 fmt::{self, Write},
6 ops::Deref,
7 rc::Rc,
8 time::{Duration, SystemTime},
9};
10
11use httpdate::HttpDate;
12use tokio::{
13 task::JoinHandle,
14 time::{Instant, interval},
15};
16
17pub trait DateTime {
21 const DATE_VALUE_LENGTH: usize;
23
24 fn with_date<F, O>(&self, f: F) -> O
26 where
27 F: FnOnce(&[u8]) -> O;
28
29 fn now(&self) -> Instant;
30}
31
32pub struct DateTimeService {
34 state: Rc<RefCell<DateTimeState>>,
35 handle: JoinHandle<()>,
36}
37
38impl Drop for DateTimeService {
39 fn drop(&mut self) {
40 self.handle.abort();
42 }
43}
44
45impl Default for DateTimeService {
46 fn default() -> Self {
47 Self::new()
48 }
49}
50
51impl DateTimeService {
52 pub fn new() -> Self {
53 let state = Rc::new(RefCell::new(DateTimeState::new()));
55 let state_clone = Rc::clone(&state);
56 let handle = tokio::task::spawn_local(async move {
59 let mut interval = interval(Duration::from_millis(500));
60 let state = &*state_clone;
61 loop {
62 let _ = interval.tick().await;
63 *state.borrow_mut() = DateTimeState::new();
64 }
65 });
66
67 Self { state, handle }
68 }
69
70 #[inline]
71 pub fn get(&self) -> &DateTimeHandle {
72 self.state.deref()
73 }
74}
75
76pub(crate) type DateTimeHandle = RefCell<DateTimeState>;
77
78pub const DATE_VALUE_LENGTH: usize = 29;
80
81#[derive(Copy, Clone)]
83pub struct DateTimeState {
84 pub date: [u8; DATE_VALUE_LENGTH],
85 pub now: Instant,
86}
87
88impl Default for DateTimeState {
89 fn default() -> Self {
90 Self::new()
91 }
92}
93
94impl DateTimeState {
95 pub fn new() -> Self {
96 let mut date = Self {
97 date: [0; DATE_VALUE_LENGTH],
98 now: Instant::now(),
99 };
100 let _ = write!(date, "{}", HttpDate::from(SystemTime::now()));
101 date
102 }
103}
104
105impl Write for DateTimeState {
106 fn write_str(&mut self, s: &str) -> fmt::Result {
107 self.date[..].copy_from_slice(s.as_bytes());
108 Ok(())
109 }
110}
111
112impl DateTime for DateTimeHandle {
113 const DATE_VALUE_LENGTH: usize = DATE_VALUE_LENGTH;
114
115 #[allow(dead_code)]
117 #[inline]
118 fn with_date<F, O>(&self, f: F) -> O
119 where
120 F: FnOnce(&[u8]) -> O,
121 {
122 let date = self.borrow();
123 f(&date.date[..])
124 }
125
126 #[inline(always)]
127 fn now(&self) -> Instant {
128 self.borrow().now
129 }
130}
131
132pub struct SystemTimeDateTimeHandler;
134
135impl DateTime for SystemTimeDateTimeHandler {
136 const DATE_VALUE_LENGTH: usize = DATE_VALUE_LENGTH;
137
138 #[allow(dead_code)]
140 fn with_date<F, O>(&self, f: F) -> O
141 where
142 F: FnOnce(&[u8]) -> O,
143 {
144 let date = HttpDate::from(SystemTime::now()).to_string();
145 f(date.as_bytes())
146 }
147
148 fn now(&self) -> Instant {
149 Instant::now()
150 }
151}