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
17use crate::http::header::HeaderValue;
18
19const DATE_VALUE_LENGTH: usize = 29;
21
22pub trait DateTime {
26 const DATE_SIZE_HINT: usize = DATE_VALUE_LENGTH;
28
29 fn with_date<F, O>(&self, f: F) -> O
31 where
32 F: FnOnce(&[u8]) -> O;
33
34 fn with_date_header<F, O>(&self, f: F) -> O
35 where
36 F: FnOnce(&HeaderValue) -> O;
37
38 fn now(&self) -> Instant;
39}
40
41pub struct DateTimeService {
43 state: Rc<RefCell<DateTimeState>>,
44 handle: JoinHandle<()>,
45}
46
47impl Drop for DateTimeService {
48 fn drop(&mut self) {
49 self.handle.abort();
51 }
52}
53
54impl Default for DateTimeService {
55 fn default() -> Self {
56 Self::new()
57 }
58}
59
60impl DateTimeService {
61 pub fn new() -> Self {
62 let state = Rc::new(RefCell::new(DateTimeState::default()));
64 let state_clone = Rc::clone(&state);
65 let handle = tokio::task::spawn_local(async move {
68 let mut interval = interval(Duration::from_millis(500));
69 loop {
70 let _ = interval.tick().await;
71 *state_clone.borrow_mut() = DateTimeState::default();
72 }
73 });
74
75 Self { state, handle }
76 }
77
78 #[inline]
79 pub fn get(&self) -> &DateTimeHandle {
80 self.state.deref()
81 }
82}
83
84pub(crate) type DateTimeHandle = RefCell<DateTimeState>;
85
86#[derive(Clone)]
88pub struct DateTimeState {
89 pub date: [u8; DATE_VALUE_LENGTH],
90 pub date_header: HeaderValue,
91 pub now: Instant,
92}
93
94impl Default for DateTimeState {
95 fn default() -> Self {
96 let mut date = Self {
97 date: [0; DATE_VALUE_LENGTH],
98 date_header: HeaderValue::from_static(""),
99 now: Instant::now(),
100 };
101 let _ = write!(date, "{}", HttpDate::from(SystemTime::now()));
102 date.date_header = HeaderValue::from_bytes(&date.date).unwrap();
103 date
104 }
105}
106
107impl Write for DateTimeState {
108 fn write_str(&mut self, s: &str) -> fmt::Result {
109 self.date[..].copy_from_slice(s.as_bytes());
110 Ok(())
111 }
112}
113
114impl DateTime for DateTimeHandle {
115 #[inline]
117 fn with_date<F, O>(&self, f: F) -> O
118 where
119 F: FnOnce(&[u8]) -> O,
120 {
121 let date = self.borrow();
122 f(&date.date[..])
123 }
124
125 #[inline]
126 fn with_date_header<F, O>(&self, f: F) -> O
127 where
128 F: FnOnce(&HeaderValue) -> O,
129 {
130 let date = self.borrow();
131 f(&date.date_header)
132 }
133
134 #[inline(always)]
135 fn now(&self) -> Instant {
136 self.borrow().now
137 }
138}
139
140pub struct SystemTimeDateTimeHandler;
142
143impl DateTime for SystemTimeDateTimeHandler {
144 #[allow(dead_code)]
146 fn with_date<F, O>(&self, f: F) -> O
147 where
148 F: FnOnce(&[u8]) -> O,
149 {
150 let date = HttpDate::from(SystemTime::now()).to_string();
151 f(date.as_bytes())
152 }
153
154 #[allow(dead_code)]
155 fn with_date_header<F, O>(&self, f: F) -> O
156 where
157 F: FnOnce(&HeaderValue) -> O,
158 {
159 self.with_date(|date| {
160 let val = HeaderValue::from_bytes(date).unwrap();
161 f(&val)
162 })
163 }
164
165 fn now(&self) -> Instant {
166 Instant::now()
167 }
168}