Skip to main content

providers_kit/config/
transport.rs

1use std::time::Duration;
2
3use crate::KitError;
4use crate::config::RetryPolicy;
5use crate::error::ValidationViolation;
6
7/// Shared HTTP transport settings used by provider backends.
8///
9/// These settings feed the transport-owned checked-request layer. Replayable
10/// requests can use [`RetryPolicy`] within the same logical request deadline,
11/// while non-replayable requests still use the same transport defaults without
12/// retrying.
13///
14/// # Examples
15/// ```rust
16/// let transport = providers_kit::config::TransportConfig::default();
17/// let _ = transport;
18/// ```
19#[derive(Clone, Debug, PartialEq, Eq)]
20pub struct TransportConfig {
21    request_timeout: Duration,
22    connect_timeout: Duration,
23    pool_idle_timeout: Duration,
24    retry: RetryPolicy,
25}
26
27impl Default for TransportConfig {
28    fn default() -> Self {
29        Self {
30            request_timeout: Duration::from_secs(120),
31            connect_timeout: Duration::from_secs(15),
32            pool_idle_timeout: Duration::from_secs(90),
33            retry: RetryPolicy::default(),
34        }
35    }
36}
37
38impl TransportConfig {
39    /// Creates validated transport timing and retry policy.
40    ///
41    /// # Errors
42    ///
43    /// Returns a configuration error when any timeout is zero or cannot fit the monotonic clock range. Configuration does not authorize retries for non-replayable operations.
44    ///
45    /// # Examples
46    ///
47    /// ```
48    /// use providers_kit::config::{RetryPolicy, TransportConfig};
49    /// use std::time::Duration;
50    /// let transport = TransportConfig::new(
51    ///     Duration::from_secs(60),
52    ///     Duration::from_secs(5),
53    ///     Duration::from_secs(30),
54    ///     RetryPolicy::default(),
55    /// )?;
56    /// assert_ne!(transport, TransportConfig::default());
57    /// assert!(
58    ///     TransportConfig::new(
59    ///         Duration::ZERO,
60    ///         Duration::from_secs(5),
61    ///         Duration::from_secs(30),
62    ///         RetryPolicy::default()
63    ///     )
64    ///     .is_err()
65    /// );
66    ///
67    /// # Ok::<(), providers_kit::KitError>(())
68    /// ```
69    ///
70    pub fn new(
71        request_timeout: Duration,
72        connect_timeout: Duration,
73        pool_idle_timeout: Duration,
74        retry: RetryPolicy,
75    ) -> Result<Self, KitError> {
76        let now = std::time::Instant::now();
77        for (field, timeout) in [
78            ("transport.request_timeout", request_timeout),
79            ("transport.connect_timeout", connect_timeout),
80            ("transport.pool_idle_timeout", pool_idle_timeout),
81        ] {
82            if timeout.is_zero() {
83                return Err(KitError::config(
84                    ValidationViolation::OutOfRange {
85                        field,
86                        rule: "must be positive",
87                    },
88                    "transport timeouts must be non-zero",
89                ));
90            }
91            if now.checked_add(timeout).is_none() {
92                return Err(KitError::config(
93                    ValidationViolation::OutOfRange {
94                        field,
95                        rule: "must fit the monotonic clock range",
96                    },
97                    "transport timeout exceeds the supported clock range",
98                ));
99            }
100        }
101        Ok(Self {
102            request_timeout,
103            connect_timeout,
104            pool_idle_timeout,
105            retry,
106        })
107    }
108
109    #[must_use]
110    /// Returns the total deadline for one logical HTTP request.
111    pub(crate) const fn request_timeout(&self) -> Duration {
112        self.request_timeout
113    }
114
115    #[must_use]
116    /// Returns the TCP/TLS connection-establishment bound.
117    pub(crate) const fn connect_timeout(&self) -> Duration {
118        self.connect_timeout
119    }
120
121    #[must_use]
122    /// Returns the idle pooled-connection retention bound.
123    pub(crate) const fn pool_idle_timeout(&self) -> Duration {
124        self.pool_idle_timeout
125    }
126
127    #[must_use]
128    /// Returns the replay-safe retry policy.
129    pub(crate) const fn retry(&self) -> &RetryPolicy {
130        &self.retry
131    }
132}