Skip to main content

s3_wasi_http/api/
list_buckets.rs

1use 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                                // Bucket
100                                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}