oss_sdk_rs/
object.rs

1//! Copyright The NoXF/oss-rust-sdk Authors
2//! Copyright The iFREEGROUP/oss-sdk-rs Contributors
3
4use super::model::error::Error as ErrorResponse;
5use crate::{
6    errors::status_to_response,
7    model::{ object::ListBucketResult, Empty },
8    oss::{ ObjectMeta, RequestType },
9    prelude::OSS,
10};
11use std::collections::HashMap;
12
13use super::errors::OSSError;
14
15use async_trait::async_trait;
16use bytes::Bytes;
17use reqwest::StatusCode;
18
19#[async_trait]
20pub trait ObjectAPI {
21    async fn list_object<S, H, R>(
22        &self,
23        headers: H,
24        resources: R
25    )
26        -> Result<ListBucketResult, OSSError>
27        where
28            S: AsRef<str>,
29            H: Into<Option<HashMap<S, S>>> + Send,
30            R: Into<Option<HashMap<S, Option<S>>>> + Send;
31
32    async fn list_object_v2<S>(
33        &self,
34        prefix: Option<S>,
35        delimiter: Option<S>
36    ) -> Result<ListBucketResult, OSSError>
37        where S: AsRef<str> + Send;
38
39    async fn get_object<S1, S2, H, R>(
40        &self,
41        object_name: S1,
42        headers: H,
43        resources: R
44    )
45        -> Result<Bytes, OSSError>
46        where
47            S1: AsRef<str> + Send,
48            S2: AsRef<str> + Send,
49            H: Into<Option<HashMap<S2, S2>>> + Send,
50            R: Into<Option<HashMap<S2, Option<S2>>>> + Send;
51
52    async fn put_object<S1, S2, H, R>(
53        &self,
54        buf: &[u8],
55        object_name: S1,
56        headers: H,
57        resources: R
58    )
59        -> Result<(), OSSError>
60        where
61            S1: AsRef<str> + Send,
62            S2: AsRef<str> + Send,
63            H: Into<Option<HashMap<S2, S2>>> + Send,
64            R: Into<Option<HashMap<S2, Option<S2>>>> + Send;
65
66    async fn append_object<S1, S2, H, R>(
67        &self,
68        buf: &[u8],
69        object_name: S1,
70        headers: H,
71        resources: R
72    )
73        -> Result<Option<u64>, OSSError>
74        where
75            S1: AsRef<str> + Send,
76            S2: AsRef<str> + Send,
77            H: Into<Option<HashMap<S2, S2>>> + Send,
78            R: Into<Option<HashMap<S2, Option<S2>>>> + Send;
79
80    async fn copy_object_from_object<S1, S2, S3, H, R>(
81        &self,
82        src: S1,
83        dest: S2,
84        headers: H,
85        resources: R
86    )
87        -> Result<(), OSSError>
88        where
89            S1: AsRef<str> + Send,
90            S2: AsRef<str> + Send,
91            S3: AsRef<str> + Send,
92            H: Into<Option<HashMap<S3, S3>>> + Send,
93            R: Into<Option<HashMap<S3, Option<S3>>>> + Send;
94
95    async fn delete_object<S>(&self, object_name: S) -> Result<(), OSSError>
96        where S: AsRef<str> + Send;
97
98    async fn head_object<S>(&self, object_name: S) -> Result<ObjectMeta, OSSError>
99        where S: AsRef<str> + Send;
100}
101
102#[async_trait]
103impl<'a> ObjectAPI for OSS<'a> {
104    async fn list_object<S, H, R>(
105        &self,
106        headers: H,
107        resources: R
108    )
109        -> Result<ListBucketResult, OSSError>
110        where
111            S: AsRef<str>,
112            H: Into<Option<HashMap<S, S>>> + Send,
113            R: Into<Option<HashMap<S, Option<S>>>> + Send
114    {
115        let (host, headers) = self.build_request(
116            RequestType::Get,
117            String::new(),
118            headers,
119            resources
120        )?;
121
122        let resp = self.http_client.get(host).headers(headers).send().await?;
123
124        let status = resp.status();
125        let text = resp.text().await?;
126        status_to_response(status, text)
127    }
128
129    async fn list_object_v2<S>(
130        &self,
131        prefix: Option<S>,
132        delimiter: Option<S>
133    ) -> Result<ListBucketResult, OSSError>
134        where S: AsRef<str> + Send
135    {
136        let mut resources = HashMap::new();
137        resources.insert("list-type".to_string(), Some("2".to_string()));
138        resources.insert(
139            "delimiter".to_string(),
140            delimiter.map(|s| s.as_ref().to_string())
141        );
142        resources.insert(
143            "prefix".to_string(),
144            prefix.map(|s| s.as_ref().to_string())
145        );
146        resources.insert("max-keys".to_string(), Some("1000".to_string()));
147        let headers = HashMap::new();
148        let (host, headers) = self.build_request(
149            RequestType::Get,
150            String::new(),
151            Some(headers),
152            resources
153        )?;
154
155        let resp = self.http_client.get(host).headers(headers).send().await?;
156
157        let status = resp.status();
158        let text = resp.text().await?;
159        status_to_response(status, text)
160    }
161
162    async fn get_object<S1, S2, H, R>(
163        &self,
164        object_name: S1,
165        headers: H,
166        resources: R
167    )
168        -> Result<Bytes, OSSError>
169        where
170            S1: AsRef<str> + Send,
171            S2: AsRef<str> + Send,
172            H: Into<Option<HashMap<S2, S2>>> + Send,
173            R: Into<Option<HashMap<S2, Option<S2>>>> + Send
174    {
175        let (host, headers) = self.build_request(
176            RequestType::Get,
177            object_name,
178            headers,
179            resources
180        )?;
181
182        let resp = self.http_client.get(&host).headers(headers).send().await?;
183
184        let status = resp.status();
185
186        if status.is_success() {
187            Ok(resp.bytes().await?)
188        } else {
189            Err(OSSError::Object {
190                status_code: status,
191                message: "get object fail".into(),
192            })
193        }
194    }
195
196    async fn append_object<S1, S2, H, R>(
197        &self,
198        buf: &[u8],
199        object_name: S1,
200        headers: H,
201        resources: R
202    )
203        -> Result<Option<u64>, OSSError>
204        where
205            S1: AsRef<str> + Send,
206            S2: AsRef<str> + Send,
207            H: Into<Option<HashMap<S2, S2>>> + Send,
208            R: Into<Option<HashMap<S2, Option<S2>>>> + Send
209    {
210        // let mut resources:HashMap<&str, Option<&str>>= HashMap::new();
211        // resources.insert("append", None);
212        // resources.insert("position", Some("1"));
213
214        let (host, headers) = self.build_request(
215            RequestType::Post,
216            object_name,
217            headers,
218            resources
219        )?;
220        let resp = self.http_client.post(&host).headers(headers).body(buf.to_owned()).send().await?;
221        let status = resp.status();
222
223        let resp_headers = resp.headers();
224        match status {
225            | StatusCode::OK
226            | StatusCode::NO_CONTENT
227            | StatusCode::CREATED
228            | StatusCode::ACCEPTED => {
229                let next_position = if
230                    let Some(next) = resp_headers.get("x-oss-next-append-position")
231                {
232                    let next = String::from_utf8_lossy(next.as_bytes()).to_string();
233                    match next.parse::<u64>() {
234                        Ok(u) => Some(u),
235                        Err(_) => None,
236                    }
237                } else {
238                    None
239                };
240                Ok(next_position)
241            }
242            StatusCode::BAD_REQUEST | StatusCode::FORBIDDEN | StatusCode::CONFLICT => {
243                let text = resp.text().await?;
244                // dbg!(&text);
245                let er: ErrorResponse = serde_xml_rs::from_str(&text)?;
246                Err(OSSError::Object {
247                    status_code: status,
248                    message: er.message,
249                })
250            }
251            _ => Err(OSSError::Unknown),
252        }
253    }
254
255    async fn put_object<S1, S2, H, R>(
256        &self,
257        buf: &[u8],
258        object_name: S1,
259        headers: H,
260        resources: R
261    )
262        -> Result<(), OSSError>
263        where
264            S1: AsRef<str> + Send,
265            S2: AsRef<str> + Send,
266            H: Into<Option<HashMap<S2, S2>>> + Send,
267            R: Into<Option<HashMap<S2, Option<S2>>>> + Send
268    {
269        let (host, headers) = self.build_request(
270            RequestType::Put,
271            object_name,
272            headers,
273            resources
274        )?;
275
276        let resp = self.http_client.put(&host).headers(headers).body(buf.to_owned()).send().await?;
277        let status = resp.status();
278        let text = resp.text().await?;
279
280        let _ = status_to_response::<Empty>(status, text)?;
281        Ok(())
282    }
283
284    async fn copy_object_from_object<S1, S2, S3, H, R>(
285        &self,
286        src: S1,
287        dest: S2,
288        headers: H,
289        resources: R
290    )
291        -> Result<(), OSSError>
292        where
293            S1: AsRef<str> + Send,
294            S2: AsRef<str> + Send,
295            S3: AsRef<str> + Send,
296            H: Into<Option<HashMap<S3, S3>>> + Send,
297            R: Into<Option<HashMap<S3, Option<S3>>>> + Send
298    {
299        let (host, mut headers) = self.build_request(RequestType::Put, dest, headers, resources)?;
300        headers.insert("x-oss-copy-source", src.as_ref().parse()?);
301
302        let resp = self.http_client.put(&host).headers(headers).send().await?;
303
304        let status = resp.status();
305        let text = resp.text().await?;
306        status_to_response::<Empty>(status, text)?;
307        Ok(())
308    }
309
310    async fn delete_object<S>(&self, object_name: S) -> Result<(), OSSError>
311        where S: AsRef<str> + Send
312    {
313        let headers = HashMap::<String, String>::new();
314        let (host, headers) = self.build_request(
315            RequestType::Delete,
316            object_name,
317            Some(headers),
318            None
319        )?;
320
321        let resp = self.http_client.delete(&host).headers(headers).send().await?;
322
323        let status = resp.status();
324        let text = resp.text().await?;
325
326        let _ = status_to_response::<Empty>(status, text)?;
327        Ok(())
328    }
329
330    async fn head_object<S>(&self, object_name: S) -> Result<ObjectMeta, OSSError>
331        where S: AsRef<str> + Send
332    {
333        let (host, headers) = self.build_request(
334            RequestType::Head,
335            object_name,
336            None::<HashMap<String, String>>,
337            None
338        )?;
339
340        let resp = self.http_client.head(&host).headers(headers).send().await?;
341        let status = resp.status();
342        if resp.status().is_success() {
343            Ok(ObjectMeta::from_header_map(resp.headers())?)
344        } else {
345            Err(OSSError::Object {
346                status_code: status,
347                message: "head object error".into(),
348            })
349        }
350    }
351}