micro_web/date/mod.rs
1//! HTTP date header value management service.
2//!
3//! This module provides a service for efficiently managing and updating HTTP date header values
4//! in a concurrent environment. It updates the date string periodically to avoid repeated
5//! date string formatting operations in high-concurrency scenarios.
6
7use arc_swap::ArcSwap;
8use bytes::Bytes;
9use http::HeaderValue;
10use once_cell::sync::Lazy;
11use std::sync::Arc;
12use std::time::Duration;
13
14mod date_service_decorator;
15
16pub use date_service_decorator::DateServiceDecorator;
17
18/// A service that maintains and periodically updates the current HTTP date string.
19///
20/// This service runs a background task that updates the date string every 700ms,
21/// providing an efficient way to access formatted HTTP date strings without
22/// formatting them on every request.
23#[derive(Debug)]
24pub struct DateService {
25 current: Arc<ArcSwap<Bytes>>,
26 handle: tokio::task::JoinHandle<()>,
27}
28
29static DATE_SERVICE: Lazy<DateService> = Lazy::new(|| DateService::new_with_update_interval(Duration::from_millis(800)));
30
31impl DateService {
32 /// Returns a reference to the global singleton instance of `DateService`.
33 ///
34 /// This method provides access to a shared `DateService` instance that can be used
35 /// across the application to efficiently handle HTTP date headers.
36 ///
37 /// # Returns
38 /// A static reference to the global `DateService` instance.
39 pub fn get_global_instance() -> &'static DateService {
40 &DATE_SERVICE
41 }
42
43 /// Creates a new `DateService` instance.
44 ///
45 /// This method initializes the service with the current system time and starts
46 /// a background task that updates the date string every 700ms.
47 ///
48 /// # Returns
49 /// Returns a new `DateService` instance with the background update task running.
50 fn new_with_update_interval(update_interval: Duration) -> Self {
51 let mut buf = faf_http_date::get_date_buff_no_key();
52 faf_http_date::get_date_no_key(&mut buf);
53 let bytes = Bytes::from_owner(buf);
54
55 let current = Arc::new(ArcSwap::from_pointee(bytes));
56 let current_arc = Arc::clone(¤t);
57
58 let handle = tokio::spawn(async move {
59 loop {
60 tokio::time::sleep(update_interval).await;
61 let mut buf = faf_http_date::get_date_buff_no_key();
62 faf_http_date::get_date_no_key(&mut buf);
63 let bytes = Bytes::from_owner(buf);
64 current_arc.store(Arc::new(bytes));
65 }
66 });
67
68 DateService { current, handle }
69 }
70
71 /// Provides access to the current HTTP date string through a callback function.
72 ///
73 /// This method allows safe access to the current date string without exposing
74 /// the internal synchronization mechanisms.
75 pub(crate) fn with_http_date<F>(&self, mut f: F)
76 where
77 F: FnMut(HeaderValue),
78 {
79 let date = self.current.load().as_ref().clone();
80 // SAFE: date is created by faf_http_date, it's valid
81 let header_value = unsafe { HeaderValue::from_maybe_shared_unchecked(date) };
82 f(header_value)
83 }
84}
85
86/// Implements the `Drop` trait to ensure the background task is properly cleaned up
87/// when the `DateService` is dropped.
88impl Drop for DateService {
89 fn drop(&mut self) {
90 self.handle.abort();
91 }
92}