Skip to main content

cloud_sdk_reqwest/asynchronous/
config.rs

1use core::fmt;
2
3use crate::shared::{
4    BearerCredential, BuildError, HttpsEndpoint, LinkLocalHttpEndpoint, RawHyperClient,
5    RequestTimeouts, UserAgent, 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
26/// Builder for the credential-free raw IPv4 link-local HTTP executor.
27pub struct RawLinkLocalAsyncClientBuilder {
28    endpoint: LinkLocalHttpEndpoint,
29    user_agent: UserAgent,
30    timeouts: RequestTimeouts,
31}
32
33impl AsyncClientBuilder {
34    /// Creates a complete asynchronous-client configuration.
35    #[must_use]
36    pub const fn new(
37        endpoint: HttpsEndpoint,
38        credential: BearerCredential,
39        user_agent: UserAgent,
40        timeouts: RequestTimeouts,
41    ) -> Self {
42        Self {
43            endpoint,
44            credential,
45            user_agent,
46            timeouts,
47        }
48    }
49
50    /// Builds a hardened HTTPS-only client.
51    ///
52    /// Sending requests requires an active Tokio executor because reqwest uses
53    /// Tokio internally. The core
54    /// [`cloud_sdk::authentication::AsyncAuthenticatedTransport`] contract
55    /// remains executor-neutral.
56    pub fn build(self) -> Result<AsyncClient, BuildError> {
57        self.build_inner(true)
58    }
59
60    fn build_inner(self, https_only: bool) -> Result<AsyncClient, BuildError> {
61        if !self.credential.scope.matches_endpoint(&self.endpoint) {
62            return Err(BuildError::CredentialEndpointMismatch);
63        }
64        let client = configured_raw_client(
65            self.endpoint.clone(),
66            &self.user_agent,
67            self.timeouts,
68            https_only,
69        )?;
70        Ok(AsyncClient::new(
71            client,
72            self.endpoint,
73            self.credential,
74            !https_only,
75        ))
76    }
77
78    #[cfg(test)]
79    pub(super) fn build_for_loopback(self) -> Result<AsyncClient, BuildError> {
80        self.build_inner(false)
81    }
82}
83
84impl RawAsyncClientBuilder {
85    /// Creates a complete asynchronous raw executor configuration.
86    #[must_use]
87    pub const fn new(
88        endpoint: HttpsEndpoint,
89        user_agent: UserAgent,
90        timeouts: RequestTimeouts,
91    ) -> Self {
92        Self {
93            endpoint,
94            user_agent,
95            timeouts,
96        }
97    }
98
99    /// Builds an HTTPS-only executor with no implicit authorization.
100    pub fn build(self) -> Result<RawAsyncClient, BuildError> {
101        self.build_inner(true)
102    }
103
104    fn build_inner(self, https_only: bool) -> Result<RawAsyncClient, BuildError> {
105        configured_raw_client(self.endpoint, &self.user_agent, self.timeouts, https_only)
106    }
107
108    #[cfg(test)]
109    pub(super) fn build_for_loopback(self) -> Result<RawAsyncClient, BuildError> {
110        self.build_inner(false)
111    }
112}
113
114impl RawLinkLocalAsyncClientBuilder {
115    /// Creates a direct-link-local HTTP builder with no credential path.
116    #[must_use]
117    pub const fn new(
118        endpoint: LinkLocalHttpEndpoint,
119        user_agent: UserAgent,
120        timeouts: RequestTimeouts,
121    ) -> Self {
122        Self {
123            endpoint,
124            user_agent,
125            timeouts,
126        }
127    }
128
129    /// Builds an HTTP executor restricted to the configured link-local endpoint.
130    pub fn build(self) -> Result<RawAsyncClient, BuildError> {
131        configured_raw_client(
132            self.endpoint.into_inner(),
133            &self.user_agent,
134            self.timeouts,
135            false,
136        )
137    }
138}
139
140impl fmt::Debug for AsyncClientBuilder {
141    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
142        formatter
143            .debug_struct("AsyncClientBuilder")
144            .field("endpoint", &"[redacted]")
145            .field("credential", &"[redacted]")
146            .field("user_agent", &self.user_agent)
147            .field("timeouts", &self.timeouts)
148            .finish()
149    }
150}
151
152impl fmt::Debug for RawAsyncClientBuilder {
153    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
154        formatter
155            .debug_struct("RawAsyncClientBuilder")
156            .field("endpoint", &"[redacted]")
157            .field("user_agent", &self.user_agent)
158            .field("timeouts", &self.timeouts)
159            .finish()
160    }
161}
162
163impl fmt::Debug for RawLinkLocalAsyncClientBuilder {
164    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
165        formatter
166            .debug_struct("RawLinkLocalAsyncClientBuilder")
167            .field("endpoint", &"[redacted]")
168            .field("user_agent", &self.user_agent)
169            .field("timeouts", &self.timeouts)
170            .finish()
171    }
172}
173
174pub(super) fn configured_raw_client(
175    endpoint: HttpsEndpoint,
176    user_agent: &UserAgent,
177    timeouts: RequestTimeouts,
178    https_only: bool,
179) -> Result<RawAsyncClient, BuildError> {
180    let tls_config = platform_client_config()?;
181    let client = RawHyperClient::new(
182        endpoint.clone(),
183        user_agent,
184        timeouts,
185        tls_config,
186        https_only,
187    )?;
188    Ok(RawAsyncClient::new(client, endpoint))
189}