matrix_sdk/config/
request.rs

1// Copyright 2021 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::{
16    fmt::{self, Debug},
17    num::NonZeroUsize,
18    time::Duration,
19};
20
21use matrix_sdk_common::debug::DebugStructExt;
22use ruma::api::MatrixVersion;
23
24use crate::http_client::DEFAULT_REQUEST_TIMEOUT;
25
26/// Configuration for requests the `Client` makes.
27///
28/// This sets how often and for how long a request should be repeated. As well
29/// as how long a successful request is allowed to take.
30///
31/// By default requests are retried indefinitely and use no timeout.
32///
33/// # Examples
34///
35/// ```
36/// use matrix_sdk::config::RequestConfig;
37/// use std::time::Duration;
38///
39/// // This sets makes requests fail after a single send request and sets the timeout to 30s
40/// let request_config = RequestConfig::new()
41///     .disable_retry()
42///     .timeout(Duration::from_secs(30));
43/// ```
44#[derive(Copy, Clone)]
45pub struct RequestConfig {
46    pub(crate) timeout: Duration,
47    pub(crate) retry_limit: Option<u64>,
48    pub(crate) retry_timeout: Option<Duration>,
49    pub(crate) max_concurrent_requests: Option<NonZeroUsize>,
50    pub(crate) force_auth: bool,
51    pub(crate) force_matrix_version: Option<MatrixVersion>,
52}
53
54#[cfg(not(tarpaulin_include))]
55impl Debug for RequestConfig {
56    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
57        let Self {
58            timeout,
59            retry_limit,
60            retry_timeout,
61            force_auth,
62            max_concurrent_requests,
63            force_matrix_version,
64        } = self;
65
66        let mut res = fmt.debug_struct("RequestConfig");
67        res.field("timeout", timeout)
68            .maybe_field("retry_limit", retry_limit)
69            .maybe_field("retry_timeout", retry_timeout)
70            .maybe_field("max_concurrent_requests", max_concurrent_requests)
71            .maybe_field("force_matrix_version", force_matrix_version);
72
73        if *force_auth {
74            res.field("force_auth", &true);
75        }
76
77        res.finish()
78    }
79}
80
81impl Default for RequestConfig {
82    fn default() -> Self {
83        Self {
84            timeout: DEFAULT_REQUEST_TIMEOUT,
85            retry_limit: Default::default(),
86            retry_timeout: Default::default(),
87            max_concurrent_requests: Default::default(),
88            force_auth: false,
89            force_matrix_version: Default::default(),
90        }
91    }
92}
93
94impl RequestConfig {
95    /// Create a new default `RequestConfig`.
96    #[must_use]
97    pub fn new() -> Self {
98        Default::default()
99    }
100
101    /// Create a new `RequestConfig` with default values, except the retry limit
102    /// which is set to 3.
103    #[must_use]
104    pub fn short_retry() -> Self {
105        Self::default().retry_limit(3)
106    }
107
108    /// This is a convince method to disable the retries of a request. Setting
109    /// the `retry_limit` to `0` has the same effect.
110    #[must_use]
111    pub fn disable_retry(mut self) -> Self {
112        self.retry_limit = Some(0);
113        self
114    }
115
116    /// The number of times a request should be retried. The default is no
117    /// limit.
118    #[must_use]
119    pub fn retry_limit(mut self, retry_limit: u64) -> Self {
120        self.retry_limit = Some(retry_limit);
121        self
122    }
123
124    /// The total limit of request that are pending or run concurrently.
125    /// Any additional request beyond that number will be waiting until another
126    /// concurrent requests finished. Requests are queued fairly.
127    #[must_use]
128    pub fn max_concurrent_requests(mut self, limit: Option<NonZeroUsize>) -> Self {
129        self.max_concurrent_requests = limit;
130        self
131    }
132
133    /// Set the timeout duration for all HTTP requests.
134    #[must_use]
135    pub fn timeout(mut self, timeout: Duration) -> Self {
136        self.timeout = timeout;
137        self
138    }
139
140    /// Set a timeout for how long a request should be retried. The default is
141    /// no timeout, meaning requests are retried forever.
142    #[must_use]
143    pub fn retry_timeout(mut self, retry_timeout: Duration) -> Self {
144        self.retry_timeout = Some(retry_timeout);
145        self
146    }
147
148    /// Force sending authorization even if the endpoint does not require it.
149    /// Default is only sending authorization if it is required.
150    #[must_use]
151    pub fn force_auth(mut self) -> Self {
152        self.force_auth = true;
153        self
154    }
155
156    /// Force the Matrix version used to select which version of the endpoint to
157    /// use.
158    ///
159    /// Can be used to force the use of a stable endpoint when the versions
160    /// advertised by the homeserver do not support it.
161    #[must_use]
162    pub(crate) fn force_matrix_version(mut self, version: MatrixVersion) -> Self {
163        self.force_matrix_version = Some(version);
164        self
165    }
166}
167
168#[cfg(test)]
169mod tests {
170    use std::time::Duration;
171
172    use super::RequestConfig;
173
174    #[test]
175    fn smoketest() {
176        let cfg = RequestConfig::new()
177            .force_auth()
178            .retry_timeout(Duration::from_secs(32))
179            .retry_limit(4)
180            .timeout(Duration::from_secs(600));
181
182        assert!(cfg.force_auth);
183        assert_eq!(cfg.retry_limit, Some(4));
184        assert_eq!(cfg.retry_timeout, Some(Duration::from_secs(32)));
185        assert_eq!(cfg.timeout, Duration::from_secs(600));
186    }
187
188    #[test]
189    fn testing_retry_settings() {
190        let mut cfg = RequestConfig::new();
191        assert_eq!(cfg.retry_limit, None);
192        cfg = cfg.retry_limit(10);
193        assert_eq!(cfg.retry_limit, Some(10));
194        cfg = cfg.disable_retry();
195        assert_eq!(cfg.retry_limit, Some(0));
196
197        let cfg = RequestConfig::short_retry();
198        assert_eq!(cfg.retry_limit, Some(3));
199    }
200}