s3_wasi_http/api/
list_buckets.rs1use anyhow::{Result, anyhow};
2use wstd::http::{Body, Method};
3use xml::reader::{EventReader, XmlEvent};
4
5use super::{
6 ApiBucket, ApiOwner, S3RequestBuilder, S3RequestData, S3ResponseData, parse_xml_string,
7};
8
9#[derive(Default)]
10pub struct ListBucketsRequest {
11 bucket_region: Option<String>,
12 token: Option<String>,
13 max_buckets: Option<i32>,
14 prefix: Option<String>,
15}
16
17
18impl S3RequestData for ListBucketsRequest {
19 type ResponseType = ListBucketsResponse;
20
21 fn into_builder(
22 &self,
23 access_key: &str,
24 secret_key: &str,
25 region: &str,
26 endpoint: &str,
27 ) -> Result<S3RequestBuilder<Self::ResponseType>> {
28 let mut builder =
29 S3RequestBuilder::new(Method::GET, "/", access_key, secret_key, region, endpoint);
30
31 if let Some(bucket_region) = &self.bucket_region {
32 builder.query("bucket-region", Some(bucket_region));
33 }
34 if let Some(token) = &self.token {
35 builder.query("continuation-token", Some(token));
36 }
37 if let Some(max_buckets) = self.max_buckets {
38 if (1..=10000).contains(&max_buckets) {
39 builder.query("max-buckets", Some(&max_buckets.to_string()));
40 } else {
41 return Err(anyhow!(
42 "max_buckets has to be constrained to part_number >= and part_number <= 10000, part_number is {max_buckets}"
43 ));
44 }
45 }
46 if let Some(prefix) = &self.prefix {
47 builder.query("prefix", Some(prefix));
48 }
49
50 Ok(builder)
51 }
52}
53
54pub struct ListBucketsResponse {
55 pub continuation_token: Option<String>,
56
57 pub buckets: Vec<ApiBucket>,
58 pub owner: ApiOwner,
59 pub prefix: Option<String>,
60}
61
62impl S3ResponseData for ListBucketsResponse {
63 async fn parse_body(response: &mut Body) -> Result<Self>
64 where
65 Self: Sized,
66 {
67 let data = response.contents().await?;
68 let mut parser = EventReader::new(data);
69
70 let mut list_bucket_response = ListBucketsResponse {
71 continuation_token: None,
72 buckets: Vec::new(),
73 owner: ApiOwner {
74 display_name: None,
75 id: String::new(),
76 },
77 prefix: None,
78 };
79 loop {
80 match parser.next()? {
81 XmlEvent::EndDocument => break,
82
83 XmlEvent::StartElement { name, .. } if name.local_name == "Prefix" => {
84 list_bucket_response.prefix = Some(parse_xml_string(&mut parser, "Prefix")?);
85 }
86 XmlEvent::StartElement { name, .. } if name.local_name == "ContinuationToken" => {
87 list_bucket_response.continuation_token =
88 Some(parse_xml_string(&mut parser, "ContinuationToken")?);
89 }
90 XmlEvent::StartElement { name, .. } if name.local_name == "Owner" => {
91 list_bucket_response.owner = ApiOwner::parse(&mut parser)?;
92 }
93 XmlEvent::StartElement { name, .. } if name.local_name == "Buckets" => {
94 loop {
95 match parser.next()? {
96 XmlEvent::EndElement { name } if name.local_name == "Buckets" => break,
97
98 XmlEvent::StartElement { .. } => {
99 list_bucket_response
101 .buckets
102 .push(ApiBucket::parse(&mut parser)?);
103 }
104
105 _ => {}
106 }
107 }
108 }
109
110 _ => {}
111 }
112 }
113
114 Ok(list_bucket_response)
115 }
116}