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
17const DATE_VALUE_LENGTH: usize = 29;
19
20pub trait DateTime {
24 const DATE_SIZE_HINT: usize = DATE_VALUE_LENGTH;
26
27 fn with_date<F, O>(&self, f: F) -> O
29 where
30 F: FnOnce(&[u8]) -> O;
31
32 fn now(&self) -> Instant;
33}
34
35pub struct DateTimeService {
37 state: Rc<RefCell<DateTimeState>>,
38 handle: JoinHandle<()>,
39}
40
41impl Drop for DateTimeService {
42 fn drop(&mut self) {
43 self.handle.abort();
45 }
46}
47
48impl Default for DateTimeService {
49 fn default() -> Self {
50 Self::new()
51 }
52}
53
54impl DateTimeService {
55 pub fn new() -> Self {
56 let state = Rc::new(RefCell::new(DateTimeState::default()));
58 let state_clone = Rc::clone(&state);
59 let handle = tokio::task::spawn_local(async move {
62 let mut interval = interval(Duration::from_millis(500));
63 loop {
64 let _ = interval.tick().await;
65 *state_clone.borrow_mut() = DateTimeState::default();
66 }
67 });
68
69 Self { state, handle }
70 }
71
72 #[inline]
73 pub fn get(&self) -> &DateTimeHandle {
74 self.state.deref()
75 }
76}
77
78pub(crate) type DateTimeHandle = RefCell<DateTimeState>;
79
80#[derive(Copy, Clone)]
82pub struct DateTimeState {
83 pub date: [u8; DATE_VALUE_LENGTH],
84 pub now: Instant,
85}
86
87impl Default for DateTimeState {
88 fn default() -> Self {
89 let mut date = Self {
90 date: [0; DATE_VALUE_LENGTH],
91 now: Instant::now(),
92 };
93 let _ = write!(date, "{}", HttpDate::from(SystemTime::now()));
94 date
95 }
96}
97
98impl Write for DateTimeState {
99 fn write_str(&mut self, s: &str) -> fmt::Result {
100 self.date[..].copy_from_slice(s.as_bytes());
101 Ok(())
102 }
103}
104
105impl DateTime for DateTimeHandle {
106 #[allow(dead_code)]
108 #[inline]
109 fn with_date<F, O>(&self, f: F) -> O
110 where
111 F: FnOnce(&[u8]) -> O,
112 {
113 let date = self.borrow();
114 f(&date.date[..])
115 }
116
117 #[inline(always)]
118 fn now(&self) -> Instant {
119 self.borrow().now
120 }
121}
122
123pub struct SystemTimeDateTimeHandler;
125
126impl DateTime for SystemTimeDateTimeHandler {
127 #[allow(dead_code)]
129 fn with_date<F, O>(&self, f: F) -> O
130 where
131 F: FnOnce(&[u8]) -> O,
132 {
133 let date = HttpDate::from(SystemTime::now()).to_string();
134 f(date.as_bytes())
135 }
136
137 fn now(&self) -> Instant {
138 Instant::now()
139 }
140}