1use anyhow::Result;
2use aws_credential_types::Credentials;
3use http_body_util::combinators::BoxBody;
4use http_body_util::BodyExt;
5use hyper::body::Bytes;
6use hyper::{Method, Request, Response};
7use hyper_rustls::HttpsConnectorBuilder;
8use hyper_util::client::legacy::Client as HttpClient;
9use hyper_util::rt::TokioExecutor;
10use std::time::SystemTime;
11
12use crate::config::{get_default_credentials, get_default_region};
13use crate::error::Error;
14use crate::error::Error::{BuildRequestError, ReadResponseError, SendRequestError};
15use crate::sigv4::sign_request;
16
17mod config;
18pub mod error;
19mod sigv4;
20
21pub struct Client {
23 uri: String,
24 method: Method,
25 body: String,
26 region: Option<String>,
27 profile: Option<String>,
28 home: Option<String>,
29}
30
31impl Client {
32 pub fn new(
33 uri: &str,
34 method: &Method,
35 body: &str,
36 region: Option<String>,
37 profile: Option<String>,
38 home: Option<String>,
39 ) -> Self {
40 Self {
41 uri: String::from(uri),
42 method: method.clone(),
43 body: String::from(body),
44 region,
45 profile,
46 home,
47 }
48 }
49
50 pub async fn request(
52 &self,
53 credentials: Option<Credentials>,
54 ) -> Result<Response<BoxBody<Bytes, Error>>, Error> {
55 let credentials = match credentials {
56 Some(r) => r,
57 None => get_default_credentials().await?,
58 };
59
60 let region = match self.region.clone() {
61 Some(r) => r,
62 None => get_default_region(self.profile.clone(), self.home.clone()).await?,
63 };
64
65 let mut request = Request::builder()
66 .header("Content-Type", "application/json")
67 .uri(self.uri.clone())
68 .method(self.method.clone())
69 .body(self.body.clone())
70 .map_err(BuildRequestError)?;
71
72 sign_request(SystemTime::now(), ®ion, "es", credentials, &mut request).await?;
73
74 let connector = HttpsConnectorBuilder::new()
75 .with_webpki_roots()
76 .https_only()
77 .enable_http1()
78 .build();
79
80 let response = HttpClient::builder(TokioExecutor::new())
81 .build(connector)
82 .request(request)
83 .await
84 .map_err(SendRequestError)?
85 .map(|i| i.map_err(ReadResponseError).boxed());
86
87 Ok(response)
88 }
89}