aliyun_oss_rs/bucket/
list_objects.rs

1use crate::common::body_to_bytes;
2use crate::{
3    Error,
4    common::{Owner, StorageClass},
5    error::normal_error,
6    request::{Oss, OssRequest},
7};
8use http::Method;
9use serde_derive::Deserialize;
10use std::cmp;
11
12// Returned content
13#[derive(Debug, Deserialize)]
14#[serde(rename_all = "PascalCase")]
15pub struct ObjectsList {
16    // Continuation token for subsequent requests
17    pub next_continuation_token: Option<String>,
18    // File list
19    pub contents: Option<Vec<ObjectInfo>>,
20    // Group list
21    pub common_prefixes: Option<Vec<CommonPrefixes>>,
22}
23
24/// Object information
25#[derive(Debug, Deserialize)]
26#[serde(rename_all = "PascalCase")]
27pub struct ObjectInfo {
28    /// Object path
29    pub key: String,
30    /// Last modified time of the object
31    pub last_modified: String,
32    /// The ETag is generated for each object to identify its content. It can be used to check if the object has changed, but it is not recommended to use it as an MD5 checksum for data integrity.
33    pub e_tag: String,
34    #[serde(rename = "Type")]
35    pub type_field: String,
36    /// Size of the object in bytes
37    pub size: u64,
38    /// Storage class of the object
39    pub storage_class: StorageClass,
40    /// Restore status of the object
41    pub restore_info: Option<String>,
42    /// Owner information of the bucket
43    pub owner: Option<Owner>,
44}
45
46/// Group list
47#[derive(Debug, Deserialize)]
48#[serde(rename_all = "PascalCase")]
49pub struct CommonPrefixes {
50    /// Prefix
51    pub prefix: String,
52}
53
54/// List information of all files in the bucket
55///
56/// By default, retrieves the first 1000 files
57///
58/// See the [Alibaba Cloud documentation](https://help.aliyun.com/document_detail/187544.html) for details
59pub struct ListObjects {
60    req: OssRequest,
61}
62
63impl ListObjects {
64    pub(super) fn new(oss: Oss) -> Self {
65        let mut req = OssRequest::new(oss, Method::GET);
66        req.insert_query("list-type", "2");
67        req.insert_query("max-keys", "1000");
68        ListObjects { req }
69    }
70    /// Character used to group object names. All object names containing the specified prefix are grouped between the first occurrences of the delimiter (i.e., CommonPrefixes)
71    pub fn set_delimiter(mut self, delimiter: impl ToString) -> Self {
72        self.req.insert_query("delimiter", delimiter);
73        self
74    }
75    /// Specify where to start listing objects alphabetically after start-after.
76    ///
77    /// start-after is used for pagination and must be less than 1024 bytes.
78    ///
79    /// When performing conditional queries, even if start-after does not exist, listing starts from the next object in alphabetical order.
80    pub fn set_start_after(mut self, start_after: impl ToString) -> Self {
81        self.req.insert_query("start-after", start_after);
82        self
83    }
84    /// Specify the token from which the listing operation should begin.
85    ///
86    /// This token can be obtained from NextContinuationToken in the ListObjects result.
87    pub fn set_continuation_token(mut self, continuation_token: impl ToString) -> Self {
88        self.req
89            .insert_query("continuation-token", continuation_token);
90        self
91    }
92    /// Restrict the returned object keys to those with the given prefix.
93    pub fn set_prefix(mut self, prefix: impl ToString) -> Self {
94        self.req.insert_query("prefix", prefix.to_string());
95        self
96    }
97    /// Specify the maximum number of files to return.
98    ///
99    /// When a delimiter is set, this counts both files and groups
100    ///
101    /// Default: 1000, range 1-1000; values outside the range use the default
102    pub fn set_max_keys(mut self, max_keys: u32) -> Self {
103        let max_keys = cmp::min(1000, cmp::max(1, max_keys));
104        self.req.insert_query("max-keys", max_keys);
105        self
106    }
107    /// Specify whether to include owner information in the result.
108    pub fn fetch_owner(mut self) -> Self {
109        self.req.insert_query("fetch-owner", "true");
110        self
111    }
112    /// Send the request
113    ///
114    pub async fn send(self) -> Result<ObjectsList, Error> {
115        // Build the HTTP request
116        let response = self.req.send_to_oss()?.await?;
117        // Parse the response
118        let status_code = response.status();
119        match status_code {
120            code if code.is_success() => {
121                let response_bytes = body_to_bytes(response.into_body())
122                    .await
123                    .map_err(|_| Error::OssInvalidResponse(None))?;
124                let object_list: ObjectsList = serde_xml_rs::from_reader(&*response_bytes)
125                    .map_err(|_| Error::OssInvalidResponse(Some(response_bytes)))?;
126                Ok(object_list)
127            }
128            _ => return Err(normal_error(response).await),
129        }
130    }
131}