Skip to main content

qubit_http/options/
timeout_options.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9
10use std::time::Duration;
11
12use qubit_config::{ConfigReader, ConfigResult};
13
14use super::HttpConfigError;
15use crate::constants::{
16    DEFAULT_CONNECT_TIMEOUT_SECS, DEFAULT_READ_TIMEOUT_SECS, DEFAULT_WRITE_TIMEOUT_SECS,
17};
18
19/// Connect, read, write, and optional whole-request timeouts for HTTP I/O.
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct TimeoutOptions {
22    /// Connect timeout.
23    pub connect_timeout: Duration,
24    /// Read timeout.
25    pub read_timeout: Duration,
26    /// Write timeout.
27    pub write_timeout: Duration,
28    /// Optional global request timeout.
29    pub request_timeout: Option<Duration>,
30}
31
32impl Default for TimeoutOptions {
33    /// Connect / read / write durations use
34    /// [`crate::constants::DEFAULT_CONNECT_TIMEOUT_SECS`],
35    /// [`crate::constants::DEFAULT_READ_TIMEOUT_SECS`], and
36    /// [`crate::constants::DEFAULT_WRITE_TIMEOUT_SECS`]; no global request timeout.
37    ///
38    /// # Returns
39    /// Default [`TimeoutOptions`].
40    fn default() -> Self {
41        Self {
42            connect_timeout: Duration::from_secs(DEFAULT_CONNECT_TIMEOUT_SECS),
43            read_timeout: Duration::from_secs(DEFAULT_READ_TIMEOUT_SECS),
44            write_timeout: Duration::from_secs(DEFAULT_WRITE_TIMEOUT_SECS),
45            request_timeout: None,
46        }
47    }
48}
49
50struct TimeoutConfigInput {
51    connect_timeout: Option<Duration>,
52    read_timeout: Option<Duration>,
53    write_timeout: Option<Duration>,
54    request_timeout: Option<Duration>,
55}
56
57fn read_timeout_config<R>(config: &R) -> ConfigResult<TimeoutConfigInput>
58where
59    R: ConfigReader + ?Sized,
60{
61    Ok(TimeoutConfigInput {
62        connect_timeout: config.get_optional("connect_timeout")?,
63        read_timeout: config.get_optional("read_timeout")?,
64        write_timeout: config.get_optional("write_timeout")?,
65        request_timeout: config.get_optional("request_timeout")?,
66    })
67}
68
69impl TimeoutOptions {
70    /// Reads timeout settings from `config` using **relative** keys.
71    ///
72    /// # Parameters
73    /// - `config`: Any [`ConfigReader`] (e.g. root [`qubit_config::Config`] or
74    ///   `config.prefix_view("timeouts")`).
75    ///
76    /// Keys read (all optional; missing keys keep their defaults):
77    /// - `connect_timeout`
78    /// - `read_timeout`
79    /// - `write_timeout`
80    /// - `request_timeout`
81    ///
82    /// # Returns
83    /// Populated [`TimeoutOptions`] or [`HttpConfigError`] on type conversion failure.
84    pub fn from_config<R>(config: &R) -> Result<Self, HttpConfigError>
85    where
86        R: ConfigReader + ?Sized,
87    {
88        let raw = read_timeout_config(config).map_err(HttpConfigError::from)?;
89
90        let mut opts = TimeoutOptions::default();
91        if let Some(d) = raw.connect_timeout {
92            opts.connect_timeout = d;
93        }
94        if let Some(d) = raw.read_timeout {
95            opts.read_timeout = d;
96        }
97        if let Some(d) = raw.write_timeout {
98            opts.write_timeout = d;
99        }
100        opts.request_timeout = raw.request_timeout;
101
102        Ok(opts)
103    }
104}