1use async_trait::async_trait;
3use quick_xml::{events::Event, Reader};
4use reqwest::header::{HeaderMap, DATE};
5use std::collections::HashMap;
6
7use super::auth::*;
8use super::errors::OSSError;
9use super::oss::OSS;
10
11#[derive(Clone, Debug)]
12pub struct ListBuckets {
13 prefix: String,
14 marker: String,
15 max_keys: String,
16 is_truncated: bool,
17 next_marker: String,
18
19 id: String,
20 display_name: String,
21
22 buckets: Vec<Bucket>,
23}
24
25impl ListBuckets {
26 #[allow(clippy::too_many_arguments)]
27 pub fn new(
28 prefix: String,
29 marker: String,
30 max_keys: String,
31 is_truncated: bool,
32 next_marker: String,
33 id: String,
34 display_name: String,
35 buckets: Vec<Bucket>,
36 ) -> Self {
37 ListBuckets {
38 prefix,
39 marker,
40 max_keys,
41 is_truncated,
42 next_marker,
43 id,
44 display_name,
45 buckets,
46 }
47 }
48
49 pub fn prefix(&self) -> &str {
50 &self.prefix
51 }
52
53 pub fn marker(&self) -> &str {
54 &self.marker
55 }
56
57 pub fn max_keys(&self) -> &str {
58 &self.max_keys
59 }
60
61 pub fn is_truncated(&self) -> bool {
62 self.is_truncated
63 }
64
65 pub fn next_marker(&self) -> &str {
66 &self.next_marker
67 }
68
69 pub fn id(&self) -> &str {
70 &self.id
71 }
72
73 pub fn display_name(&self) -> &str {
74 &self.display_name
75 }
76
77 pub fn buckets(&self) -> &Vec<Bucket> {
78 &self.buckets
79 }
80}
81
82#[derive(Clone, Debug)]
83pub struct Bucket {
84 name: String,
85 create_date: String,
86 location: String,
87 extranet_endpoint: String,
88 intranet_endpoint: String,
89 storage_class: String,
90}
91
92impl Bucket {
93 pub fn new(
94 name: String,
95 create_date: String,
96 location: String,
97 extranet_endpoint: String,
98 intranet_endpoint: String,
99 storage_class: String,
100 ) -> Self {
101 Bucket {
102 name,
103 create_date,
104 location,
105 extranet_endpoint,
106 intranet_endpoint,
107 storage_class,
108 }
109 }
110
111 pub fn name(&self) -> &str {
112 &self.name
113 }
114
115 pub fn create_data(&self) -> &str {
116 &self.create_date
117 }
118
119 pub fn location(&self) -> &str {
120 &self.location
121 }
122
123 pub fn extranet_endpoint(&self) -> &str {
124 &self.extranet_endpoint
125 }
126
127 pub fn intranet_endpoint(&self) -> &str {
128 &self.intranet_endpoint
129 }
130
131 pub fn storage_class(&self) -> &str {
132 &self.storage_class
133 }
134}
135
136#[async_trait]
137pub trait ServiceAPI {
138 async fn list_bucket<S, R>(&self, resources: R) -> Result<ListBuckets, OSSError>
139 where
140 S: AsRef<str> + Send,
141 R: Into<Option<HashMap<S, Option<S>>>> + Send;
142}
143
144#[async_trait]
145impl<'a> ServiceAPI for OSS<'a> {
146 async fn list_bucket<S, R>(&self, resources: R) -> Result<ListBuckets, OSSError>
147 where
148 S: AsRef<str> + Send,
149 R: Into<Option<HashMap<S, Option<S>>>> + Send,
150 {
151 let resources_str = if let Some(r) = resources.into() {
152 self.get_resources_str(&r)
153 } else {
154 String::new()
155 };
156 let host = self.endpoint();
157 let date = self.date();
158
159 let mut headers = HeaderMap::new();
160 headers.insert(DATE, date.parse()?);
161 let authorization = self.oss_sign(
162 "GET",
163 "",
164 "",
165 &resources_str,
166 &headers,
167 )?;
168 headers.insert("Authorization", authorization.parse()?);
169
170 let resp = self.http_client.get(host).headers(headers).send().await?;
171
172 let xml_str = resp.text().await?;
173 let mut result = Vec::new();
174 let mut reader = Reader::from_str(xml_str.as_str());
175 let mut prefix = String::new();
178 let mut marker = String::new();
179 let mut max_keys = String::new();
180 let mut is_truncated = false;
181 let mut next_marker = String::new();
182 let mut id = String::new();
183 let mut display_name = String::new();
184
185 let mut name = String::new();
186 let mut location = String::new();
187 let mut create_date = String::new();
188 let mut extranet_endpoint = String::new();
189 let mut intranet_endpoint = String::new();
190 let mut storage_class = String::new();
191
192 let list_buckets;
193
194 loop {
195 match reader.read_event() {
196 Ok(Event::Start(ref e)) => match e.name().as_ref() {
197 b"Prefix" => prefix = reader.read_text(e.name())?.to_string(),
198 b"Marker" => marker = reader.read_text(e.name())?.to_string(),
199 b"MaxKeys" => max_keys = reader.read_text(e.name())?.to_string(),
200 b"IsTruncated" => {
201 is_truncated = reader.read_text(e.name())? == "true"
202 }
203 b"NextMarker" => next_marker = reader.read_text(e.name())?.to_string(),
204 b"ID" => id = reader.read_text(e.name())?.to_string(),
205 b"DisplayName" => display_name = reader.read_text(e.name())?.to_string(),
206
207 b"Bucket" => {
208 name = String::new();
209 location = String::new();
210 create_date = String::new();
211 extranet_endpoint = String::new();
212 intranet_endpoint = String::new();
213 storage_class = String::new();
214 }
215
216 b"Name" => name = reader.read_text(e.name())?.to_string(),
217 b"CreationDate" => create_date = reader.read_text(e.name())?.to_string(),
218 b"ExtranetEndpoint" => {
219 extranet_endpoint = reader.read_text(e.name())?.to_string()
220 }
221 b"IntranetEndpoint" => {
222 intranet_endpoint = reader.read_text(e.name())?.to_string()
223 }
224 b"Location" => location = reader.read_text(e.name())?.to_string(),
225 b"StorageClass" => storage_class = reader.read_text(e.name())?.to_string(),
226 _ => (),
227 },
228 Ok(Event::End(ref e)) if e.name().as_ref() == b"Bucket" => {
229 let bucket = Bucket::new(
230 name.clone(),
231 create_date.clone(),
232 location.clone(),
233 extranet_endpoint.clone(),
234 intranet_endpoint.clone(),
235 storage_class.clone(),
236 );
237 result.push(bucket);
238 }
239 Ok(Event::Eof) => {
240 list_buckets = ListBuckets::new(
241 prefix,
242 marker,
243 max_keys,
244 is_truncated,
245 next_marker,
246 id,
247 display_name,
248 result,
249 );
250 break;
251 } Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
253 _ => (), }
255 }
256 Ok(list_buckets)
257 }
258}