Skip to main content

aliyun_oss/operations/
bucket_transfer_accel.rs

1//! Transfer acceleration operations.
2
3use std::sync::Arc;
4
5use serde::{Deserialize, Serialize};
6
7use crate::client::{BucketOperations, OSSClientInner};
8use crate::error::{ErrorContext, OssError, OssErrorKind, Result};
9use crate::http::client::HttpRequest;
10use crate::types::bucket::BucketName;
11
12#[derive(Debug, Clone, Serialize)]
13#[serde(rename = "TransferAccelerationConfiguration")]
14struct TransferAccelConfiguration {
15    #[serde(rename = "Enabled")]
16    enabled: bool,
17}
18
19#[derive(Debug, Clone, Deserialize)]
20#[serde(rename = "TransferAccelerationConfiguration")]
21struct TransferAccelConfigurationResponse {
22    #[serde(rename = "Enabled")]
23    enabled: bool,
24}
25
26pub struct PutBucketTransferAccelBuilder {
27    client: Arc<OSSClientInner>,
28    bucket: BucketName,
29    enabled: bool,
30}
31
32impl PutBucketTransferAccelBuilder {
33    pub(crate) fn new(client: Arc<OSSClientInner>, bucket: BucketName, enabled: bool) -> Self {
34        Self {
35            client,
36            bucket,
37            enabled,
38        }
39    }
40
41    pub async fn send(self) -> Result<PutBucketTransferAccelOutput> {
42        let endpoint = self.client.endpoint.clone();
43        let uri = format!(
44            "https://{}.{}?transferAcceleration",
45            self.bucket.as_str(),
46            endpoint
47        );
48        let query_params: Vec<(String, String)> =
49            vec![("transferAcceleration".into(), String::new())];
50
51        let config = TransferAccelConfiguration {
52            enabled: self.enabled,
53        };
54        let body_xml = crate::util::xml::to_xml(&config)?;
55
56        let request = HttpRequest::builder()
57            .method(http::Method::PUT)
58            .uri(&uri)
59            .body(bytes::Bytes::from(body_xml))
60            .build();
61
62        let response = self
63            .client
64            .send_signed(request, Some(&self.bucket), query_params)
65            .await
66            .map_err(|e| OssError {
67                kind: OssErrorKind::TransportError,
68                context: Box::new(ErrorContext {
69                    operation: Some("PutBucketTransferAccel".into()),
70                    bucket: Some(self.bucket.to_string()),
71                    endpoint: Some(endpoint),
72                    ..Default::default()
73                }),
74                source: Some(Box::new(e)),
75            })?;
76
77        if response.status().is_success() {
78            Ok(PutBucketTransferAccelOutput {
79                request_id: response
80                    .headers
81                    .get("x-oss-request-id")
82                    .and_then(|v| v.to_str().ok())
83                    .unwrap_or("")
84                    .to_string(),
85            })
86        } else {
87            Err(OssError {
88                kind: OssErrorKind::ServiceError(Box::new(crate::error::OssServiceError {
89                    status_code: response.status().as_u16(),
90                    code: String::new(),
91                    message: String::new(),
92                    request_id: String::new(),
93                    host_id: String::new(),
94                    resource: Some(self.bucket.to_string()),
95                    string_to_sign: None,
96                })),
97                context: Box::new(ErrorContext {
98                    operation: Some("PutBucketTransferAccel".into()),
99                    bucket: Some(self.bucket.to_string()),
100                    ..Default::default()
101                }),
102                source: None,
103            })
104        }
105    }
106}
107
108#[derive(Debug, Clone)]
109pub struct PutBucketTransferAccelOutput {
110    pub request_id: String,
111}
112
113pub struct GetBucketTransferAccelBuilder {
114    client: Arc<OSSClientInner>,
115    bucket: BucketName,
116}
117
118impl GetBucketTransferAccelBuilder {
119    pub(crate) fn new(client: Arc<OSSClientInner>, bucket: BucketName) -> Self {
120        Self { client, bucket }
121    }
122
123    pub async fn send(self) -> Result<GetBucketTransferAccelOutput> {
124        let endpoint = self.client.endpoint.clone();
125        let uri = format!(
126            "https://{}.{}?transferAcceleration",
127            self.bucket.as_str(),
128            endpoint
129        );
130        let query_params: Vec<(String, String)> =
131            vec![("transferAcceleration".into(), String::new())];
132
133        let request = HttpRequest::builder()
134            .method(http::Method::GET)
135            .uri(&uri)
136            .build();
137
138        let response = self
139            .client
140            .send_signed(request, Some(&self.bucket), query_params)
141            .await
142            .map_err(|e| OssError {
143                kind: OssErrorKind::TransportError,
144                context: Box::new(ErrorContext {
145                    operation: Some("GetBucketTransferAccel".into()),
146                    bucket: Some(self.bucket.to_string()),
147                    endpoint: Some(endpoint),
148                    ..Default::default()
149                }),
150                source: Some(Box::new(e)),
151            })?;
152
153        if response.is_success() {
154            let body_str = response.body_as_str().unwrap_or("");
155            let config: TransferAccelConfigurationResponse = crate::util::xml::from_xml(body_str)
156                .map_err(|e| OssError {
157                kind: OssErrorKind::DeserializationError,
158                context: Box::new(ErrorContext {
159                    operation: Some("GetBucketTransferAccel: parse XML".into()),
160                    bucket: Some(self.bucket.to_string()),
161                    ..Default::default()
162                }),
163                source: Some(Box::new(e)),
164            })?;
165
166            Ok(GetBucketTransferAccelOutput {
167                enabled: config.enabled,
168            })
169        } else {
170            Err(OssError {
171                kind: OssErrorKind::ServiceError(Box::new(crate::error::OssServiceError {
172                    status_code: response.status().as_u16(),
173                    code: String::new(),
174                    message: String::new(),
175                    request_id: String::new(),
176                    host_id: String::new(),
177                    resource: Some(self.bucket.to_string()),
178                    string_to_sign: None,
179                })),
180                context: Box::new(ErrorContext {
181                    operation: Some("GetBucketTransferAccel".into()),
182                    bucket: Some(self.bucket.to_string()),
183                    ..Default::default()
184                }),
185                source: None,
186            })
187        }
188    }
189}
190
191#[derive(Debug, Clone)]
192pub struct GetBucketTransferAccelOutput {
193    pub enabled: bool,
194}
195
196impl BucketOperations {
197    pub fn put_transfer_acceleration(&self, enabled: bool) -> PutBucketTransferAccelBuilder {
198        PutBucketTransferAccelBuilder::new(
199            self.client_inner().clone(),
200            self.bucket_name().clone(),
201            enabled,
202        )
203    }
204
205    pub fn get_transfer_acceleration(&self) -> GetBucketTransferAccelBuilder {
206        GetBucketTransferAccelBuilder::new(self.client_inner().clone(), self.bucket_name().clone())
207    }
208}
209
210#[cfg(test)]
211mod tests {
212    use std::sync::Mutex;
213
214    use crate::client::OSSClientInner;
215    use crate::config::credentials::Credentials;
216    use crate::http::client::{HttpClient, HttpRequest, HttpResponse};
217    use crate::types::region::Region;
218
219    use super::*;
220
221    struct RecordingHttpClient {
222        requests: Arc<Mutex<Vec<HttpRequest>>>,
223        status_code: http::StatusCode,
224        response_body: bytes::Bytes,
225    }
226
227    #[async_trait::async_trait]
228    impl HttpClient for RecordingHttpClient {
229        async fn send(&self, request: HttpRequest) -> crate::error::Result<HttpResponse> {
230            self.requests.lock().unwrap().push(request);
231            let mut headers = http::HeaderMap::new();
232            headers.insert("x-oss-request-id", http::HeaderValue::from_static("rid-ta"));
233            Ok(HttpResponse {
234                status: self.status_code,
235                headers,
236                body: self.response_body.clone(),
237            })
238        }
239    }
240
241    fn create_test_inner(
242        body: bytes::Bytes,
243    ) -> (Arc<OSSClientInner>, Arc<Mutex<Vec<HttpRequest>>>) {
244        let requests = Arc::new(Mutex::new(Vec::new()));
245        let http = Arc::new(RecordingHttpClient {
246            requests: requests.clone(),
247            status_code: http::StatusCode::OK,
248            response_body: body,
249        });
250        let credentials = Arc::new(crate::config::credentials::StaticCredentialsProvider::new(
251            Credentials::builder()
252                .access_key_id("test-ak")
253                .access_key_secret("test-sk")
254                .build()
255                .unwrap(),
256        ));
257        let inner = Arc::new(OSSClientInner {
258            http,
259            credentials,
260            signer: Arc::from(crate::signer::create_signer(crate::signer::SignVersion::V4)),
261            region: Region::CnHangzhou,
262            endpoint: "oss-cn-hangzhou.aliyuncs.com".into(),
263        });
264        (inner, requests)
265    }
266
267    #[test]
268    fn transfer_accel_xml_enabled() {
269        let config = TransferAccelConfiguration { enabled: true };
270        let xml = crate::util::xml::to_xml(&config).unwrap();
271        assert!(xml.contains("<Enabled>true</Enabled>"));
272    }
273
274    #[tokio::test]
275    async fn get_transfer_accel_parses_response() {
276        let xml = r#"<?xml version="1.0" encoding="UTF-8"?>
277<TransferAccelerationConfiguration><Enabled>true</Enabled></TransferAccelerationConfiguration>"#;
278        let (inner, _) = create_test_inner(bytes::Bytes::from(xml));
279        let builder =
280            GetBucketTransferAccelBuilder::new(inner, BucketName::new("test-bucket").unwrap());
281        let output = builder.send().await.unwrap();
282        assert!(output.enabled);
283    }
284}