Skip to main content

made_client/
client_config.rs

1use std::time::Duration;
2
3use crate::RequestContext;
4
5/// Bounded connection policy for the public MADE endpoint.
6#[derive(Clone, Debug)]
7pub struct ClientConfig {
8    endpoint: String,
9    request_context: Option<RequestContext>,
10    connect_attempts: u32,
11    initial_backoff: Duration,
12    maximum_backoff: Duration,
13    tls_domain_name: Option<String>,
14    ca_certificate_pem: Option<Vec<u8>>,
15    client_identity_pem: Option<(Vec<u8>, Vec<u8>)>,
16}
17
18impl ClientConfig {
19    pub fn new(endpoint: impl Into<String>) -> Self {
20        Self {
21            endpoint: endpoint.into(),
22            request_context: None,
23            connect_attempts: 5,
24            initial_backoff: Duration::from_millis(100),
25            maximum_backoff: Duration::from_secs(2),
26            tls_domain_name: None,
27            ca_certificate_pem: None,
28            client_identity_pem: None,
29        }
30    }
31
32    /// Reuse one caller-generated namespace when reconstructing a logical invocation.
33    #[must_use]
34    pub fn with_request_context(mut self, request_context: RequestContext) -> Self {
35        self.request_context = Some(request_context);
36        self
37    }
38
39    /// Trust an additional PEM-encoded CA for the public endpoint.
40    #[must_use]
41    pub fn with_ca_certificate_pem(mut self, pem: impl Into<Vec<u8>>) -> Self {
42        self.ca_certificate_pem = Some(pem.into());
43        self
44    }
45
46    /// Present a PEM certificate chain and private key as the mTLS client identity.
47    #[must_use]
48    pub fn with_mtls_identity_pem(
49        mut self,
50        certificate_pem: impl Into<Vec<u8>>,
51        private_key_pem: impl Into<Vec<u8>>,
52    ) -> Self {
53        self.client_identity_pem = Some((certificate_pem.into(), private_key_pem.into()));
54        self
55    }
56
57    /// Override the TLS server name when it differs from the endpoint host.
58    #[must_use]
59    pub fn with_tls_domain_name(mut self, domain_name: impl Into<String>) -> Self {
60        self.tls_domain_name = Some(domain_name.into());
61        self
62    }
63
64    #[must_use]
65    pub fn with_connect_attempts(mut self, attempts: u32) -> Self {
66        self.connect_attempts = attempts.max(1);
67        self
68    }
69
70    #[must_use]
71    pub fn with_backoff(mut self, initial: Duration, maximum: Duration) -> Self {
72        self.initial_backoff = initial;
73        self.maximum_backoff = maximum.max(initial);
74        self
75    }
76
77    pub(crate) fn endpoint(&self) -> &str {
78        &self.endpoint
79    }
80
81    pub(crate) fn request_context(&self) -> Option<&RequestContext> {
82        self.request_context.as_ref()
83    }
84
85    pub(crate) fn connect_attempts(&self) -> u32 {
86        self.connect_attempts
87    }
88
89    pub(crate) fn initial_backoff(&self) -> Duration {
90        self.initial_backoff
91    }
92
93    pub(crate) fn maximum_backoff(&self) -> Duration {
94        self.maximum_backoff
95    }
96
97    pub(crate) fn uses_tls(&self) -> bool {
98        self.endpoint.starts_with("https://")
99            || self.ca_certificate_pem.is_some()
100            || self.client_identity_pem.is_some()
101            || self.tls_domain_name.is_some()
102    }
103
104    pub(crate) fn tls_domain_name(&self) -> Option<&str> {
105        self.tls_domain_name.as_deref()
106    }
107
108    pub(crate) fn ca_certificate_pem(&self) -> Option<&[u8]> {
109        self.ca_certificate_pem.as_deref()
110    }
111
112    pub(crate) fn client_identity_pem(&self) -> Option<(&[u8], &[u8])> {
113        self.client_identity_pem
114            .as_ref()
115            .map(|(certificate, key)| (certificate.as_slice(), key.as_slice()))
116    }
117}