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}