Skip to main content

aliyun_oss/operations/
bucket_archive_read.rs

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