oss_sdk_rs/
service.rs

1//! Copyright The NoXF/oss-rust-sdk Authors
2use 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        // reader.trim_text(true);
176
177        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                } // exits the loop when reaching end of file
252                Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
253                _ => (), // There are several other `Event`s we do not consider here
254            }
255        }
256        Ok(list_buckets)
257    }
258}