Skip to main content

aws_multipart_upload/client/
sdk.rs

1use aws_config::ConfigLoader;
2
3use crate::client::part::{CompletedPart, EntityTag};
4use crate::client::request::*;
5use crate::client::{
6    DefaultRequestBuilder, RequestBuilder, UploadApi, UploadData, UploadId,
7};
8use crate::error::{ErrorRepr, ErrorWithUpload as _, Result};
9
10/// AWS S3 SDK client.
11///
12/// Pairs a [`Client`] with a [`RequestBuilder`] used to set additional
13/// properties on request objects before sending.
14///
15/// [`Client`]: aws_sdk::Client
16/// [`RequestBuilder`]: super::request::RequestBuilder
17#[derive(Debug, Clone)]
18pub struct SdkClient<B = DefaultRequestBuilder>(aws_sdk::Client, B);
19
20impl SdkClient {
21    /// Create a new `SdkClient` with default [`RequestBuilder`].
22    ///
23    /// [`RequestBuilder`]: super::request::RequestBuilder
24    pub fn new(client: aws_sdk::Client) -> Self {
25        SdkClient(client, DefaultRequestBuilder)
26    }
27
28    /// Create a new `SdkClient` from the supplied [`ConfigLoader`].
29    ///
30    /// [`ConfigLoader`]: aws_config::ConfigLoader
31    pub async fn from_config(loader: ConfigLoader) -> Self {
32        let config = loader.load().await;
33        let client = aws_sdk::Client::new(&config);
34        Self::new(client)
35    }
36
37    /// Create a new `SdkClient` with default [`RequestBuilder`] using the
38    /// default [`ConfigLoader`].
39    pub async fn defaults() -> Self {
40        let loader = aws_config::from_env();
41        Self::from_config(loader).await
42    }
43
44    /// Set a request builder for this S3 client.
45    pub fn with_request_builder<B: RequestBuilder>(
46        self,
47        builder: B,
48    ) -> SdkClient<B> {
49        SdkClient(self.0, builder)
50    }
51
52    /// Return a reference to the underlying S3 client.
53    pub fn client_ref(&self) -> &aws_sdk::Client {
54        &self.0
55    }
56}
57
58impl<B: RequestBuilder> SdkClient<B> {
59    /// Create a default `CreateRequestBuilder` to set properties on for a
60    /// `CreateMultipartUpload` request.
61    pub(crate) fn new_create_builder(&self) -> CreateRequestBuilder {
62        self.0.create_multipart_upload()
63    }
64
65    /// Create a default `UploadPartRequestBuilder` to set properties on for an
66    /// `UploadPart`.
67    pub(crate) fn new_part_builder(&self) -> UploadPartRequestBuilder {
68        self.0.upload_part()
69    }
70
71    /// Create a default `CompleteRequestBuilder` to set properties on for a
72    /// `CompleteMultipartUpload` request.
73    pub(crate) fn new_complete_builder(&self) -> CompleteRequestBuilder {
74        self.0.complete_multipart_upload()
75    }
76
77    /// Create a default `CompleteRequestBuilder` to set properties on for a
78    /// `CompleteMultipartUpload` request.
79    pub(crate) fn new_abort_builder(&self) -> AbortRequestBuilder {
80        self.0.abort_multipart_upload()
81    }
82}
83
84impl<B: RequestBuilder> UploadApi for SdkClient<B> {
85    async fn send_create_upload_request(
86        &self,
87        req: CreateRequest,
88    ) -> Result<UploadData> {
89        req.validate()?;
90        let base = self.new_create_builder();
91        let builder = req.with_builder(base);
92        let request = self.1.with_create_builder(builder);
93        let uri = req.uri();
94        let id = request
95            .send()
96            .await
97            .map_err(ErrorRepr::from)
98            .and_then(|resp| UploadId::try_from_create_resp(&resp))?;
99        Ok(UploadData::new(id, uri.clone()))
100    }
101
102    async fn send_new_part_upload_request(
103        &self,
104        mut req: UploadPartRequest,
105    ) -> Result<CompletedPart> {
106        req.validate()?;
107        let part_size = req.body.size();
108        let base = self.new_part_builder();
109        let builder = req.with_builder(base);
110        let request = self.1.with_upload_part_builder(builder);
111        let part = req.part_number();
112        let etag = request
113            .send()
114            .await
115            .map_err(ErrorRepr::from)
116            .and_then(|resp| EntityTag::try_from_upload_resp(&resp))?;
117        Ok(CompletedPart::new(etag, part, part_size))
118    }
119
120    async fn send_complete_upload_request(
121        &self,
122        req: CompleteRequest,
123    ) -> Result<CompletedUpload> {
124        req.validate()?;
125        let base = self.new_complete_builder();
126        let builder = req.with_builder(base);
127        let request = self.1.with_complete_builder(builder);
128        let id = req.id();
129        let uri = req.uri();
130        let completed = req.completed_parts();
131        let etag = request
132            .send()
133            .await
134            .map_err(ErrorRepr::from)
135            .and_then(|resp| EntityTag::try_from_complete_resp(&resp))
136            .err_with_upl(id, uri, completed)?;
137        Ok(CompletedUpload::new(uri.clone(), etag))
138    }
139
140    async fn send_abort_upload_request(&self, req: AbortRequest) -> Result<()> {
141        let base = self.new_abort_builder();
142        let builder = req.with_builder(base);
143        let request = self.1.with_abort_builder(builder);
144        let _ = request.send().await.map_err(ErrorRepr::from)?;
145        Ok(())
146    }
147}