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 http::HeaderValue;
9use httpdate::fmt_http_date;
10use std::sync::Arc;
11use std::time::{Duration, SystemTime};
12
13mod date_service_decorator;
14
15pub use date_service_decorator::DateServiceDecorator;
16
17/// A service that maintains and periodically updates the current HTTP date string.
18///
19/// This service runs a background task that updates the date string every 700ms,
20/// providing an efficient way to access formatted HTTP date strings without
21/// formatting them on every request.
22pub struct DateService {
23    current: Arc<ArcSwap<(SystemTime, HeaderValue)>>,
24    handle: tokio::task::JoinHandle<()>,
25}
26
27impl DateService {
28    /// Creates a new `DateService` instance.
29    ///
30    /// This method initializes the service with the current system time and starts
31    /// a background task that updates the date string every 700ms.
32    ///
33    /// # Returns
34    /// Returns a new `DateService` instance with the background update task running.
35    pub(crate) fn new() -> Self {
36        let system_time = SystemTime::now();
37        let http_date = fmt_http_date(system_time);
38        let date_value = HeaderValue::try_from(http_date).expect("http_date should not fail");
39
40        let current = Arc::new(ArcSwap::from_pointee((system_time, date_value)));
41        let current_arc = Arc::clone(&current);
42
43        let handle = tokio::spawn(async move {
44            loop {
45                tokio::time::sleep(Duration::from_millis(700)).await;
46                let system_time = SystemTime::now();
47                let http_date = fmt_http_date(system_time);
48                let date_value = HeaderValue::try_from(http_date).expect("http_date should not fail");
49                current_arc.store(Arc::new((system_time, date_value)));
50            }
51        });
52
53        DateService { current, handle }
54    }
55
56    /// Provides access to the current HTTP date string through a callback function.
57    ///
58    /// This method allows safe access to the current date string without exposing
59    /// the internal synchronization mechanisms.
60    pub(crate) fn with_http_date<F>(&self, mut f: F)
61    where
62        F: FnMut(&HeaderValue),
63    {
64        let date = &self.current.load().1;
65        f(date)
66    }
67}
68
69/// Implements the `Drop` trait to ensure the background task is properly cleaned up
70/// when the `DateService` is dropped.
71impl Drop for DateService {
72    fn drop(&mut self) {
73        self.handle.abort();
74    }
75}