Skip to main content

cloud_sdk_reqwest/asynchronous/
config.rs

1use core::fmt;
2
3use crate::shared::{
4    BearerCredential, BuildError, HttpsEndpoint, RawHyperClient, RequestTimeouts, UserAgent,
5    platform_client_config,
6};
7
8use super::{AsyncClient, RawAsyncClient};
9
10/// Builder requiring endpoint, bearer token, user agent, and all timeout
11/// dimensions before an asynchronous client can be constructed.
12pub struct AsyncClientBuilder {
13    endpoint: HttpsEndpoint,
14    credential: BearerCredential,
15    user_agent: UserAgent,
16    timeouts: RequestTimeouts,
17}
18
19/// Builder for a raw async client with no credentials or provider policy.
20pub struct RawAsyncClientBuilder {
21    endpoint: HttpsEndpoint,
22    user_agent: UserAgent,
23    timeouts: RequestTimeouts,
24}
25
26impl AsyncClientBuilder {
27    /// Creates a complete asynchronous-client configuration.
28    #[must_use]
29    pub const fn new(
30        endpoint: HttpsEndpoint,
31        credential: BearerCredential,
32        user_agent: UserAgent,
33        timeouts: RequestTimeouts,
34    ) -> Self {
35        Self {
36            endpoint,
37            credential,
38            user_agent,
39            timeouts,
40        }
41    }
42
43    /// Builds a hardened HTTPS-only client.
44    ///
45    /// Sending requests requires an active Tokio executor because reqwest uses
46    /// Tokio internally. The core
47    /// [`cloud_sdk::authentication::AsyncAuthenticatedTransport`] contract
48    /// remains executor-neutral.
49    pub fn build(self) -> Result<AsyncClient, BuildError> {
50        self.build_inner(true)
51    }
52
53    fn build_inner(self, https_only: bool) -> Result<AsyncClient, BuildError> {
54        if !self.credential.scope.matches_endpoint(&self.endpoint) {
55            return Err(BuildError::CredentialEndpointMismatch);
56        }
57        let client = configured_raw_client(
58            self.endpoint.clone(),
59            &self.user_agent,
60            self.timeouts,
61            https_only,
62        )?;
63        Ok(AsyncClient::new(
64            client,
65            self.endpoint,
66            self.credential,
67            !https_only,
68        ))
69    }
70
71    #[cfg(test)]
72    pub(super) fn build_for_loopback(self) -> Result<AsyncClient, BuildError> {
73        self.build_inner(false)
74    }
75}
76
77impl RawAsyncClientBuilder {
78    /// Creates a complete asynchronous raw executor configuration.
79    #[must_use]
80    pub const fn new(
81        endpoint: HttpsEndpoint,
82        user_agent: UserAgent,
83        timeouts: RequestTimeouts,
84    ) -> Self {
85        Self {
86            endpoint,
87            user_agent,
88            timeouts,
89        }
90    }
91
92    /// Builds an HTTPS-only executor with no implicit authorization.
93    pub fn build(self) -> Result<RawAsyncClient, BuildError> {
94        self.build_inner(true)
95    }
96
97    fn build_inner(self, https_only: bool) -> Result<RawAsyncClient, BuildError> {
98        configured_raw_client(self.endpoint, &self.user_agent, self.timeouts, https_only)
99    }
100
101    #[cfg(test)]
102    pub(super) fn build_for_loopback(self) -> Result<RawAsyncClient, BuildError> {
103        self.build_inner(false)
104    }
105}
106
107impl fmt::Debug for AsyncClientBuilder {
108    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
109        formatter
110            .debug_struct("AsyncClientBuilder")
111            .field("endpoint", &"[redacted]")
112            .field("credential", &"[redacted]")
113            .field("user_agent", &self.user_agent)
114            .field("timeouts", &self.timeouts)
115            .finish()
116    }
117}
118
119impl fmt::Debug for RawAsyncClientBuilder {
120    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
121        formatter
122            .debug_struct("RawAsyncClientBuilder")
123            .field("endpoint", &"[redacted]")
124            .field("user_agent", &self.user_agent)
125            .field("timeouts", &self.timeouts)
126            .finish()
127    }
128}
129
130pub(super) fn configured_raw_client(
131    endpoint: HttpsEndpoint,
132    user_agent: &UserAgent,
133    timeouts: RequestTimeouts,
134    https_only: bool,
135) -> Result<RawAsyncClient, BuildError> {
136    let tls_config = platform_client_config()?;
137    let client = RawHyperClient::new(
138        endpoint.clone(),
139        user_agent,
140        timeouts,
141        tls_config,
142        https_only,
143    )?;
144    Ok(RawAsyncClient::new(client, endpoint))
145}