Skip to main content

aliyun_oss/operations/
object_list.rs

1use std::sync::Arc;
2
3use crate::client::{BucketOperations, OSSClientInner};
4use crate::error::{ErrorContext, OssError, OssErrorKind, Result};
5use crate::http::client::HttpRequest;
6use crate::types::bucket::BucketName;
7use crate::util::uri::oss_endpoint_url;
8
9pub struct ListObjectsBuilder {
10    client: Arc<OSSClientInner>,
11    bucket: BucketName,
12    prefix: Option<String>,
13    delimiter: Option<String>,
14    marker: Option<String>,
15    max_keys: Option<i32>,
16    encoding_type: Option<String>,
17}
18
19impl ListObjectsBuilder {
20    pub(crate) fn new(client: Arc<OSSClientInner>, bucket: BucketName) -> Self {
21        Self {
22            client,
23            bucket,
24            prefix: None,
25            delimiter: None,
26            marker: None,
27            max_keys: None,
28            encoding_type: None,
29        }
30    }
31
32    pub fn prefix(mut self, prefix: impl Into<String>) -> Self {
33        self.prefix = Some(prefix.into());
34        self
35    }
36
37    pub fn delimiter(mut self, delimiter: impl Into<String>) -> Self {
38        self.delimiter = Some(delimiter.into());
39        self
40    }
41
42    pub fn marker(mut self, marker: impl Into<String>) -> Self {
43        self.marker = Some(marker.into());
44        self
45    }
46
47    pub fn max_keys(mut self, max_keys: i32) -> Self {
48        self.max_keys = Some(max_keys);
49        self
50    }
51
52    pub fn encoding_type(mut self, et: impl Into<String>) -> Self {
53        self.encoding_type = Some(et.into());
54        self
55    }
56
57    pub async fn send(self) -> Result<crate::types::response::ListObjectsOutput> {
58        let endpoint = self.client.endpoint.clone();
59        let uri = oss_endpoint_url(&endpoint, Some(self.bucket.as_str()), None);
60
61        let mut query_pairs: Vec<(String, String)> = Vec::new();
62        if let Some(ref p) = self.prefix {
63            query_pairs.push(("prefix".into(), crate::util::uri::uri_encode(p)));
64        }
65        if let Some(ref d) = self.delimiter {
66            query_pairs.push(("delimiter".into(), d.clone()));
67        }
68        if let Some(ref m) = self.marker {
69            query_pairs.push(("marker".into(), m.clone()));
70        }
71        if let Some(mk) = self.max_keys {
72            query_pairs.push(("max-keys".into(), mk.to_string()));
73        }
74        if let Some(ref et) = self.encoding_type {
75            query_pairs.push(("encoding-type".into(), et.clone()));
76        }
77
78        let query_string = if query_pairs.is_empty() {
79            String::new()
80        } else {
81            let parts: Vec<String> = query_pairs
82                .iter()
83                .map(|(k, v)| format!("{}={}", k, v))
84                .collect();
85            format!("?{}", parts.join("&"))
86        };
87        let full_uri = format!("{}{}", uri, query_string);
88
89        let request = HttpRequest::builder()
90            .method(http::Method::GET)
91            .uri(&full_uri)
92            .build();
93
94        let response = self
95            .client
96            .send_signed(request, Some(&self.bucket), query_pairs)
97            .await
98            .map_err(|e| OssError {
99                kind: OssErrorKind::TransportError,
100                context: Box::new(ErrorContext {
101                    operation: Some("ListObjects".into()),
102                    bucket: Some(self.bucket.to_string()),
103                    endpoint: Some(endpoint),
104                    ..Default::default()
105                }),
106                source: Some(Box::new(e)),
107            })?;
108
109        if response.is_success() {
110            let body_str = response.body_as_str().unwrap_or("");
111            Ok(crate::util::xml::from_xml(body_str)?)
112        } else {
113            Err(OssError {
114                kind: OssErrorKind::ServiceError(Box::new(crate::error::OssServiceError {
115                    status_code: response.status().as_u16(),
116                    code: String::new(),
117                    message: String::new(),
118                    request_id: String::new(),
119                    host_id: String::new(),
120                    resource: Some(self.bucket.to_string()),
121                    string_to_sign: None,
122                })),
123                context: Box::new(ErrorContext {
124                    operation: Some("ListObjects".into()),
125                    bucket: Some(self.bucket.to_string()),
126                    ..Default::default()
127                }),
128                source: None,
129            })
130        }
131    }
132}
133
134pub struct ListObjectsV2Builder {
135    client: Arc<OSSClientInner>,
136    bucket: BucketName,
137    prefix: Option<String>,
138    delimiter: Option<String>,
139    start_after: Option<String>,
140    continuation_token: Option<String>,
141    max_keys: Option<i32>,
142    encoding_type: Option<String>,
143    fetch_owner: Option<bool>,
144}
145
146impl ListObjectsV2Builder {
147    pub(crate) fn new(client: Arc<OSSClientInner>, bucket: BucketName) -> Self {
148        Self {
149            client,
150            bucket,
151            prefix: None,
152            delimiter: None,
153            start_after: None,
154            continuation_token: None,
155            max_keys: None,
156            encoding_type: None,
157            fetch_owner: None,
158        }
159    }
160
161    pub fn prefix(mut self, prefix: impl Into<String>) -> Self {
162        self.prefix = Some(prefix.into());
163        self
164    }
165
166    pub fn delimiter(mut self, delimiter: impl Into<String>) -> Self {
167        self.delimiter = Some(delimiter.into());
168        self
169    }
170
171    pub fn start_after(mut self, start_after: impl Into<String>) -> Self {
172        self.start_after = Some(start_after.into());
173        self
174    }
175
176    pub fn continuation_token(mut self, token: impl Into<String>) -> Self {
177        self.continuation_token = Some(token.into());
178        self
179    }
180
181    pub fn max_keys(mut self, max_keys: i32) -> Self {
182        self.max_keys = Some(max_keys);
183        self
184    }
185
186    pub fn encoding_type(mut self, et: impl Into<String>) -> Self {
187        self.encoding_type = Some(et.into());
188        self
189    }
190
191    pub fn fetch_owner(mut self, fetch: bool) -> Self {
192        self.fetch_owner = Some(fetch);
193        self
194    }
195
196    pub async fn send(self) -> Result<crate::types::response::ListObjectsV2Output> {
197        let endpoint = self.client.endpoint.clone();
198        let uri = oss_endpoint_url(&endpoint, Some(self.bucket.as_str()), None);
199
200        let mut query_pairs: Vec<(String, String)> = Vec::new();
201        query_pairs.push(("list-type".into(), "2".into()));
202        if let Some(ref p) = self.prefix {
203            query_pairs.push(("prefix".into(), crate::util::uri::uri_encode(p)));
204        }
205        if let Some(ref d) = self.delimiter {
206            query_pairs.push(("delimiter".into(), d.clone()));
207        }
208        if let Some(ref s) = self.start_after {
209            query_pairs.push(("start-after".into(), s.clone()));
210        }
211        if let Some(ref ct) = self.continuation_token {
212            query_pairs.push(("continuation-token".into(), ct.clone()));
213        }
214        if let Some(mk) = self.max_keys {
215            query_pairs.push(("max-keys".into(), mk.to_string()));
216        }
217        if let Some(ref et) = self.encoding_type {
218            query_pairs.push(("encoding-type".into(), et.clone()));
219        }
220        if let Some(fo) = self.fetch_owner {
221            query_pairs.push(("fetch-owner".into(), fo.to_string()));
222        }
223
224        let query_string: String = if query_pairs.is_empty() {
225            String::new()
226        } else {
227            let parts: Vec<String> = query_pairs
228                .iter()
229                .map(|(k, v)| format!("{}={}", k, v))
230                .collect();
231            format!("?{}", parts.join("&"))
232        };
233        let full_uri = format!("{}{}", uri, query_string);
234
235        let request = HttpRequest::builder()
236            .method(http::Method::GET)
237            .uri(&full_uri)
238            .build();
239
240        let response = self
241            .client
242            .send_signed(request, Some(&self.bucket), query_pairs)
243            .await
244            .map_err(|e| OssError {
245                kind: OssErrorKind::TransportError,
246                context: Box::new(ErrorContext {
247                    operation: Some("ListObjectsV2".into()),
248                    bucket: Some(self.bucket.to_string()),
249                    endpoint: Some(endpoint),
250                    ..Default::default()
251                }),
252                source: Some(Box::new(e)),
253            })?;
254
255        if response.is_success() {
256            let body_str = response.body_as_str().unwrap_or("");
257            Ok(crate::util::xml::from_xml(body_str)?)
258        } else {
259            Err(OssError {
260                kind: OssErrorKind::ServiceError(Box::new(crate::error::OssServiceError {
261                    status_code: response.status().as_u16(),
262                    code: String::new(),
263                    message: String::new(),
264                    request_id: String::new(),
265                    host_id: String::new(),
266                    resource: Some(self.bucket.to_string()),
267                    string_to_sign: None,
268                })),
269                context: Box::new(ErrorContext {
270                    operation: Some("ListObjectsV2".into()),
271                    bucket: Some(self.bucket.to_string()),
272                    ..Default::default()
273                }),
274                source: None,
275            })
276        }
277    }
278}
279
280pub struct ListObjectVersionsBuilder {
281    client: Arc<OSSClientInner>,
282    bucket: BucketName,
283    prefix: Option<String>,
284    delimiter: Option<String>,
285    key_marker: Option<String>,
286    version_id_marker: Option<String>,
287    max_keys: Option<i32>,
288    encoding_type: Option<String>,
289}
290
291impl ListObjectVersionsBuilder {
292    pub(crate) fn new(client: Arc<OSSClientInner>, bucket: BucketName) -> Self {
293        Self {
294            client,
295            bucket,
296            prefix: None,
297            delimiter: None,
298            key_marker: None,
299            version_id_marker: None,
300            max_keys: None,
301            encoding_type: None,
302        }
303    }
304
305    pub fn prefix(mut self, v: impl Into<String>) -> Self {
306        self.prefix = Some(v.into());
307        self
308    }
309
310    pub fn delimiter(mut self, v: impl Into<String>) -> Self {
311        self.delimiter = Some(v.into());
312        self
313    }
314
315    pub fn key_marker(mut self, v: impl Into<String>) -> Self {
316        self.key_marker = Some(v.into());
317        self
318    }
319
320    pub fn version_id_marker(mut self, v: impl Into<String>) -> Self {
321        self.version_id_marker = Some(v.into());
322        self
323    }
324
325    pub fn max_keys(mut self, v: i32) -> Self {
326        self.max_keys = Some(v);
327        self
328    }
329
330    pub fn encoding_type(mut self, v: impl Into<String>) -> Self {
331        self.encoding_type = Some(v.into());
332        self
333    }
334
335    pub async fn send(self) -> Result<crate::types::response::ListVersionsOutput> {
336        let endpoint = self.client.endpoint.clone();
337        let uri = oss_endpoint_url(&endpoint, Some(self.bucket.as_str()), None);
338
339        let mut query_pairs: Vec<(String, String)> = Vec::new();
340        query_pairs.push(("versions".into(), String::new()));
341        if let Some(ref p) = self.prefix {
342            query_pairs.push(("prefix".into(), crate::util::uri::uri_encode(p)));
343        }
344        if let Some(ref d) = self.delimiter {
345            query_pairs.push(("delimiter".into(), d.clone()));
346        }
347        if let Some(ref km) = self.key_marker {
348            query_pairs.push(("key-marker".into(), km.clone()));
349        }
350        if let Some(ref vim) = self.version_id_marker {
351            query_pairs.push(("version-id-marker".into(), vim.clone()));
352        }
353        if let Some(mk) = self.max_keys {
354            query_pairs.push(("max-keys".into(), mk.to_string()));
355        }
356        if let Some(ref et) = self.encoding_type {
357            query_pairs.push(("encoding-type".into(), et.clone()));
358        }
359
360        let query_string: String = if query_pairs.is_empty() {
361            String::new()
362        } else {
363            let parts: Vec<String> = query_pairs
364                .iter()
365                .map(|(k, v)| format!("{}={}", k, v))
366                .collect();
367            format!("?{}", parts.join("&"))
368        };
369        let full_uri = format!("{}{}", uri, query_string);
370
371        let request = HttpRequest::builder()
372            .method(http::Method::GET)
373            .uri(&full_uri)
374            .build();
375
376        let response = self
377            .client
378            .send_signed(request, Some(&self.bucket), query_pairs)
379            .await
380            .map_err(|e| OssError {
381                kind: OssErrorKind::TransportError,
382                context: Box::new(ErrorContext {
383                    operation: Some("ListObjectVersions".into()),
384                    bucket: Some(self.bucket.to_string()),
385                    endpoint: Some(endpoint),
386                    ..Default::default()
387                }),
388                source: Some(Box::new(e)),
389            })?;
390
391        if response.is_success() {
392            let body_str = response.body_as_str().unwrap_or("");
393            Ok(crate::util::xml::from_xml(body_str)?)
394        } else {
395            Err(OssError {
396                kind: OssErrorKind::ServiceError(Box::new(crate::error::OssServiceError {
397                    status_code: response.status().as_u16(),
398                    code: String::new(),
399                    message: String::new(),
400                    request_id: String::new(),
401                    host_id: String::new(),
402                    resource: Some(self.bucket.to_string()),
403                    string_to_sign: None,
404                })),
405                context: Box::new(ErrorContext {
406                    operation: Some("ListObjectVersions".into()),
407                    bucket: Some(self.bucket.to_string()),
408                    ..Default::default()
409                }),
410                source: None,
411            })
412        }
413    }
414}
415
416impl BucketOperations {
417    pub fn list_objects(&self) -> ListObjectsBuilder {
418        ListObjectsBuilder::new(self.client_inner().clone(), self.bucket_name().clone())
419    }
420
421    pub fn list_objects_v2(&self) -> ListObjectsV2Builder {
422        ListObjectsV2Builder::new(self.client_inner().clone(), self.bucket_name().clone())
423    }
424
425    pub fn list_object_versions(&self) -> ListObjectVersionsBuilder {
426        ListObjectVersionsBuilder::new(self.client_inner().clone(), self.bucket_name().clone())
427    }
428}