fw_client/
middleware.rs

1use http::Extensions;
2use reqwest::{Request, Response};
3use reqwest_middleware::{Middleware, Next, Result};
4use reqwest_retry::{
5    DefaultRetryableStrategy, RetryPolicy, RetryTransientMiddleware, RetryableStrategy,
6};
7
8/// Custom extension options for the request
9///
10/// The `FWClient` uses a custom [`middleware`](FWRetryTransientMiddleware) to handle retry logic.
11/// the `FWOptions` struct allows you to control the behavior of the middleware.
12#[derive(Debug, Clone)]
13pub struct FWOptions {
14    /// If true, the middleware will skip retry logic.
15    pub skip_retry: bool,
16    /// If true, the middleware will remove the `Authorization` header from the request.
17    pub no_auth: bool,
18}
19
20pub struct FWRetryTransientMiddleware<
21    T: RetryPolicy + Send + Sync + 'static,
22    R: RetryableStrategy + Send + Sync + 'static = DefaultRetryableStrategy,
23>(Option<RetryTransientMiddleware<T, R>>);
24
25impl<T, R> FWRetryTransientMiddleware<T, R>
26where
27    T: RetryPolicy + Send + Sync + 'static,
28    R: RetryableStrategy + Send + Sync + 'static,
29{
30    /// Create a new instance of `FWRetryTransientMiddleware` with the provided
31    /// [`RetryTransientMiddleware`].
32    pub fn new(retry: Option<RetryTransientMiddleware<T, R>>) -> Self {
33        Self(retry)
34    }
35}
36
37#[async_trait::async_trait]
38impl<T, R> Middleware for FWRetryTransientMiddleware<T, R>
39where
40    T: RetryPolicy + Send + Sync,
41    R: RetryableStrategy + Send + Sync + 'static,
42{
43    async fn handle(
44        &self,
45        mut req: Request,
46        extensions: &mut Extensions,
47        next: Next<'_>,
48    ) -> Result<Response> {
49        // If the request cannot be cloned (try_clone returns None) we skip retry logic
50        let mut skip_retry = req.try_clone().is_none();
51        if let Some(options) = extensions.get::<FWOptions>() {
52            if options.no_auth {
53                req.headers_mut().remove("Authorization");
54            }
55            if options.skip_retry {
56                skip_retry = true;
57            }
58        }
59        if skip_retry {
60            return next.run(req, extensions).await;
61        }
62        match &self.0 {
63            Some(middleware) => middleware.handle(req, extensions, next).await,
64            None => next.run(req, extensions).await,
65        }
66    }
67}