stedi_sdk_config/
endpoint.rs

1//! Stedi SDK endpoint support.
2#![allow(deprecated)]
3
4use aws_smithy_http::endpoint::error::InvalidEndpointError;
5use aws_smithy_http::endpoint::{Endpoint, EndpointPrefix};
6use aws_types::region::{Region, SigningRegion};
7use aws_types::SigningService;
8use std::error::Error;
9use std::fmt::Debug;
10
11/// Endpoint to connect to an Stedi Service
12///
13/// An `StediEndpoint` captures all necessary information needed to connect to an Stedi service, including:
14/// - The URI of the endpoint (needed to actually send the request)
15/// - The name of the service (needed downstream for signing)
16/// - The signing region (which may differ from the actual region)
17#[derive(Clone, Debug)]
18pub struct StediEndpoint {
19    endpoint: Endpoint,
20    credential_scope: CredentialScope,
21}
22
23impl StediEndpoint {
24    /// Constructs a new Stedi endpoint.
25    pub fn new(endpoint: Endpoint, credential_scope: CredentialScope) -> StediEndpoint {
26        StediEndpoint {
27            endpoint,
28            credential_scope,
29        }
30    }
31
32    /// Returns the underlying endpoint.
33    pub fn endpoint(&self) -> &Endpoint {
34        &self.endpoint
35    }
36
37    /// Returns the credential scope.
38    pub fn credential_scope(&self) -> &CredentialScope {
39        &self.credential_scope
40    }
41
42    /// Sets the endpoint on a given `uri` based on this endpoint
43    pub fn set_endpoint(
44        &self,
45        uri: &mut http::Uri,
46        endpoint_prefix: Option<&EndpointPrefix>,
47    ) -> Result<(), InvalidEndpointError> {
48        self.endpoint.set_endpoint(uri, endpoint_prefix)
49    }
50}
51
52/// A boxed error.
53pub type BoxError = Box<dyn Error + Send + Sync + 'static>;
54
55/// Resolve the Stedi Endpoint for a given region
56///
57/// To provide a static endpoint, [`Endpoint`](aws_smithy_http::endpoint::Endpoint) implements this trait.
58/// Example usage:
59/// ```rust
60/// # mod sftp {
61/// # use stedi_sdk_config::endpoint::ResolveStediEndpoint;
62/// # pub struct ConfigBuilder;
63/// # impl ConfigBuilder {
64/// #     pub fn endpoint(&mut self, resolver: impl ResolveStediEndpoint + 'static) {
65/// #         // ...
66/// #     }
67/// # }
68/// # pub struct Config;
69/// # impl Config {
70/// #     pub fn builder() -> ConfigBuilder {
71/// #         ConfigBuilder
72/// #     }
73/// # }
74/// # }
75/// # fn wrapper() -> Result<(), aws_smithy_http::endpoint::error::InvalidEndpointError> {
76/// use aws_smithy_http::endpoint::Endpoint;
77/// let config = sftp::Config::builder()
78///     .endpoint(Endpoint::immutable("http://localhost:8080")?);
79/// #     Ok(())
80/// # }
81/// ```
82/// Each Stedi service generates their own implementation of `ResolveStediEndpoint`.
83pub trait ResolveStediEndpoint: Send + Sync + Debug {
84    /// Resolves the Stedi endpoint for a given region.
85    fn resolve_endpoint(&self, region: &Region) -> Result<StediEndpoint, BoxError>;
86}
87
88/// The scope for Stedi credentials.
89#[derive(Clone, Default, Debug)]
90pub struct CredentialScope {
91    region: Option<SigningRegion>,
92    service: Option<SigningService>,
93}
94
95impl CredentialScope {
96    /// Creates a builder for [`CredentialScope`].
97    pub fn builder() -> credential_scope::Builder {
98        credential_scope::Builder::default()
99    }
100}
101
102/// Types associated with [`CredentialScope`].
103pub mod credential_scope {
104    use crate::endpoint::CredentialScope;
105    use aws_types::region::SigningRegion;
106    use aws_types::SigningService;
107
108    /// A builder for [`CredentialScope`].
109    #[derive(Debug, Default)]
110    pub struct Builder {
111        region: Option<SigningRegion>,
112        service: Option<SigningService>,
113    }
114
115    impl Builder {
116        /// Sets the signing region.
117        pub fn region(mut self, region: impl Into<SigningRegion>) -> Self {
118            self.region = Some(region.into());
119            self
120        }
121
122        /// Sets the signing service.
123        pub fn service(mut self, service: impl Into<SigningService>) -> Self {
124            self.service = Some(service.into());
125            self
126        }
127
128        /// Constructs a [`CredentialScope`] from the builder.
129        pub fn build(self) -> CredentialScope {
130            CredentialScope {
131                region: self.region,
132                service: self.service,
133            }
134        }
135    }
136}
137
138impl CredentialScope {
139    /// Returns the signing region.
140    pub fn region(&self) -> Option<&SigningRegion> {
141        self.region.as_ref()
142    }
143
144    /// Returns the signing service.
145    pub fn service(&self) -> Option<&SigningService> {
146        self.service.as_ref()
147    }
148
149    /// Uses the values from `other` to fill in unconfigured parameters on this
150    /// credential scope object.
151    pub fn merge(&self, other: &CredentialScope) -> CredentialScope {
152        CredentialScope {
153            region: self.region.clone().or_else(|| other.region.clone()),
154            service: self.service.clone().or_else(|| other.service.clone()),
155        }
156    }
157}
158
159/// An `Endpoint` can be its own resolver to support static endpoints
160impl ResolveStediEndpoint for Endpoint {
161    fn resolve_endpoint(&self, _region: &Region) -> Result<StediEndpoint, BoxError> {
162        Ok(StediEndpoint {
163            endpoint: self.clone(),
164            credential_scope: Default::default(),
165        })
166    }
167}
168
169#[cfg(test)]
170mod test {
171    use crate::endpoint::CredentialScope;
172    use aws_types::region::SigningRegion;
173    use aws_types::SigningService;
174
175    #[test]
176    fn create_credentials_scope_from_strs() {
177        let scope = CredentialScope::builder()
178            .service("functions")
179            .region("us")
180            .build();
181        assert_eq!(
182            scope.service(),
183            Some(&SigningService::from_static("functions"))
184        );
185        assert_eq!(scope.region(), Some(&SigningRegion::from_static("us")));
186    }
187}