1use quick_xml::{events::Event, Reader};
2use reqwest::header::{HeaderMap, HeaderValue, DATE};
3use serde::{Deserialize, Serialize};
4use std::collections::HashMap;
5
6use crate::auth::Auth;
7use crate::oss::RequestType;
8
9use super::errors::{Error, ObjectError};
10use super::oss::OSS;
11use super::utils::*;
12
13#[derive(Clone, Debug, Serialize, Deserialize)]
14#[serde(rename_all = "PascalCase")]
15pub struct CommonPrefix {
16 prefix: String,
17}
18
19impl CommonPrefix {
20 pub fn new(prefix: String) -> Self {
21 Self { prefix }
22 }
23
24 pub fn prefix(&self) -> &str {
25 &self.prefix
26 }
27}
28
29#[derive(Clone, Debug, Serialize, Deserialize)]
30#[serde(rename_all = "PascalCase")]
31pub struct ListObjects {
32 name: String,
33 delimiter: String,
34 prefix: String,
35 marker: String,
36 max_keys: String,
37 is_truncated: bool,
38
39 #[serde(default)]
40 contents: Vec<Object>,
41 #[serde(default)]
42 common_prefixes: Vec<CommonPrefix>,
43}
44
45impl ListObjects {
46 pub fn new(
47 name: String,
48 delimiter: String,
49 prefix: String,
50 marker: String,
51 max_keys: String,
52 is_truncated: bool,
53
54 contents: Vec<Object>,
55 common_prefixes: Vec<CommonPrefix>,
56 ) -> Self {
57 ListObjects {
58 name,
59 delimiter,
60 prefix,
61 marker,
62 max_keys,
63 is_truncated,
64
65 contents,
66 common_prefixes,
67 }
68 }
69
70 pub fn name(&self) -> &str {
71 &self.name
72 }
73
74 pub fn delimiter(&self) -> &str {
75 &self.delimiter
76 }
77
78 pub fn prefix(&self) -> &str {
79 &self.prefix
80 }
81
82 pub fn marker(&self) -> &str {
83 &self.marker
84 }
85
86 pub fn max_keys(&self) -> &str {
87 &self.max_keys
88 }
89
90 pub fn is_truncated(&self) -> bool {
91 self.is_truncated
92 }
93
94 pub fn contents(&self) -> &Vec<Object> {
95 &self.contents
96 }
97
98 pub fn common_prefixes(&self) -> &Vec<CommonPrefix> {
99 &self.common_prefixes
100 }
101}
102
103#[derive(Clone, Debug, Serialize, Deserialize, Default)]
104#[serde(rename_all = "PascalCase")]
105pub struct Owner {
106 #[serde(alias = "ID")]
107 pub id: String,
108 pub display_name: String,
109}
110
111#[derive(Clone, Debug, Serialize, Deserialize)]
112#[serde(rename_all = "PascalCase")]
113pub struct Object {
114 key: String,
115 last_modified: String,
116 size: usize,
117 e_tag: String,
118 r#type: String,
119 storage_class: String,
120 owner: Owner,
121}
122
123impl Object {
124 pub fn new(
125 key: String,
126 last_modified: String,
127 size: usize,
128
129 e_tag: String,
130 r#type: String,
131 storage_class: String,
132 owner: Owner,
133 ) -> Self {
134 Object {
135 key,
136 last_modified,
137 size,
138 e_tag,
139 r#type,
140 storage_class,
141 owner,
142 }
143 }
144
145 pub fn key(&self) -> &str {
146 &self.key
147 }
148
149 pub fn last_modified(&self) -> &str {
150 &self.last_modified
151 }
152
153 pub fn size(&self) -> usize {
154 self.size
155 }
156
157 pub fn e_tag(&self) -> &str {
158 &self.e_tag
159 }
160
161 pub fn r#type(&self) -> &str {
162 &self.r#type
163 }
164
165 pub fn storage_class(&self) -> &str {
166 &self.storage_class
167 }
168
169 pub fn id(&self) -> &str {
170 &self.owner.id
171 }
172
173 pub fn display_name(&self) -> &str {
174 &self.owner.display_name
175 }
176}
177
178trait PrivateObjectAPI {
179 fn generate_presigned_path<S1>(&self, object_name: S1, expires: usize) -> String
180 where
181 S1: AsRef<str> + Send;
182}
183
184pub trait ObjectAPI {
185 fn list_object<S, H, R>(&self, headers: H, resources: R) -> Result<ListObjects, Error>
186 where
187 S: AsRef<str>,
188 H: Into<Option<HashMap<S, S>>>,
189 R: Into<Option<HashMap<S, Option<S>>>>;
190
191 fn get_object<S1, S2, H, R>(
192 &self,
193 object_name: S1,
194 headers: H,
195 resources: R,
196 ) -> Result<Vec<u8>, Error>
197 where
198 S1: AsRef<str>,
199 S2: AsRef<str>,
200 H: Into<Option<HashMap<S2, S2>>>,
201 R: Into<Option<HashMap<S2, Option<S2>>>>;
202
203 fn get_object_acl<S>(&self, object_name: S) -> Result<String, Error>
204 where
205 S: AsRef<str>;
206
207 fn put_object_from_file<S1, S2, S3, H, R>(
208 &self,
209 file: S1,
210 object_name: S2,
211 headers: H,
212 resources: R,
213 ) -> Result<(), Error>
214 where
215 S1: AsRef<str>,
216 S2: AsRef<str>,
217 S3: AsRef<str>,
218 H: Into<Option<HashMap<S3, S3>>>,
219 R: Into<Option<HashMap<S3, Option<S3>>>>;
220
221 fn put_object_from_buffer<S1, S2, H, R>(
222 &self,
223 buf: &[u8],
224 object_name: S1,
225 headers: H,
226 resources: R,
227 ) -> Result<(), Error>
228 where
229 S1: AsRef<str>,
230 S2: AsRef<str>,
231 H: Into<Option<HashMap<S2, S2>>>,
232 R: Into<Option<HashMap<S2, Option<S2>>>>;
233
234 fn get_object_signed_url<S1>(&self, object_name: S1, expires: usize) -> String
235 where
236 S1: AsRef<str> + Send;
237
238 fn copy_object_from_object<S1, S2, S3, H, R>(
239 &self,
240 src: S1,
241 dest: S2,
242 headers: H,
243 resources: R,
244 ) -> Result<(), Error>
245 where
246 S1: AsRef<str>,
247 S2: AsRef<str>,
248 S3: AsRef<str>,
249 H: Into<Option<HashMap<S3, S3>>>,
250 R: Into<Option<HashMap<S3, Option<S3>>>>;
251
252 fn delete_object<S>(&self, object_name: S) -> Result<(), Error>
253 where
254 S: AsRef<str>;
255}
256
257impl<'a> PrivateObjectAPI for OSS<'a> {
258 fn generate_presigned_path<S1>(&self, object_name: S1, expires: usize) -> String
259 where
260 S1: AsRef<str> + Send,
261 {
262 let object_name = object_name.as_ref();
263 let mut headers = HeaderMap::new();
264 headers.insert(DATE, HeaderValue::from_str(&expires.to_string()).unwrap());
265 let signature = self.sign(
266 RequestType::Get.as_str(),
267 self.key_secret(),
268 self.bucket(),
269 object_name,
270 "",
271 &headers,
272 );
273 format!(
274 "/{}?Expires={}&OSSAccessKeyId={}&Signature={}",
275 urlencoding::encode(object_name),
276 expires,
277 urlencoding::encode(self.key_id()),
278 urlencoding::encode(&signature)
279 )
280 }
281}
282
283impl<'a> ObjectAPI for OSS<'a> {
284 fn list_object<S, H, R>(&self, headers: H, resources: R) -> Result<ListObjects, Error>
285 where
286 S: AsRef<str>,
287 H: Into<Option<HashMap<S, S>>>,
288 R: Into<Option<HashMap<S, Option<S>>>>,
289 {
290 let (host, headers) =
291 self.build_request(RequestType::Get, String::new(), headers, resources)?;
292
293 let resp = reqwest::blocking::Client::new()
294 .get(&host)
295 .headers(headers)
296 .send()?;
297
298 let body = resp.text()?;
299 let list_objects = quick_xml::de::from_str::<ListObjects>(&body)?;
300
301 Ok(list_objects)
302 }
303
304 fn get_object<S1, S2, H, R>(
305 &self,
306 object_name: S1,
307 headers: H,
308 resources: R,
309 ) -> Result<Vec<u8>, Error>
310 where
311 S1: AsRef<str>,
312 S2: AsRef<str>,
313 H: Into<Option<HashMap<S2, S2>>>,
314 R: Into<Option<HashMap<S2, Option<S2>>>>,
315 {
316 let (host, headers) =
317 self.build_request(RequestType::Get, object_name, headers, resources)?;
318
319 let mut resp = reqwest::blocking::Client::new()
320 .get(&host)
321 .headers(headers)
322 .send()?;
323 let mut buf: Vec<u8> = vec![];
324
325 if resp.status().is_success() {
326 resp.copy_to(&mut buf)?;
327 Ok(buf)
328 } else {
329 Err(Error::Object(ObjectError::GetError {
330 msg: format!("can not get object, status code: {}", resp.status()).into(),
331 }))
332 }
333 }
334
335 fn get_object_acl<S>(&self, object_name: S) -> Result<String, Error>
336 where
337 S: AsRef<str>,
338 {
339 let object_name = object_name.as_ref();
340 let mut params: HashMap<&str, Option<&str>> = HashMap::new();
341 params.insert("acl", None);
342 let result = String::from_utf8(self.get_object(object_name, None, Some(params))?)?;
343 let mut reader = Reader::from_str(&result);
344 reader.trim_text(true);
345 let mut grant = String::new();
346
347 loop {
348 match reader.read_event() {
349 Ok(Event::Start(ref e)) if e.name().as_ref() == b"Grant" => {
350 grant = reader.read_text(e.name())?.to_string();
351 }
352 Ok(Event::Eof) => break,
353 Err(e) => panic!("Error at position {}: {:?}", reader.buffer_position(), e),
354 _ => (),
355 }
356 }
357
358 Ok(grant)
359 }
360
361 fn get_object_signed_url<S1>(&self, object_name: S1, expires: usize) -> String
362 where
363 S1: AsRef<str> + Send,
364 {
365 format!(
366 "https://{}.{}{}",
367 self.bucket(),
368 self.endpoint(),
369 self.generate_presigned_path(object_name, expires),
370 )
371 }
372
373 fn put_object_from_file<S1, S2, S3, H, R>(
374 &self,
375 file: S1,
376 object_name: S2,
377 headers: H,
378 resources: R,
379 ) -> Result<(), Error>
380 where
381 S1: AsRef<str>,
382 S2: AsRef<str>,
383 S3: AsRef<str>,
384 H: Into<Option<HashMap<S3, S3>>>,
385 R: Into<Option<HashMap<S3, Option<S3>>>>,
386 {
387 let (host, headers) =
388 self.build_request(RequestType::Put, object_name, headers, resources)?;
389
390 let buf = load_file(file)?;
391
392 let resp = reqwest::blocking::Client::new()
393 .put(&host)
394 .headers(headers)
395 .body(buf)
396 .send()?;
397
398 if resp.status().is_success() {
399 Ok(())
400 } else {
401 Err(Error::Object(ObjectError::PutError {
402 msg: format!("can not put object, status code: {}", resp.status()).into(),
403 }))
404 }
405 }
406
407 fn put_object_from_buffer<S1, S2, H, R>(
408 &self,
409 buf: &[u8],
410 object_name: S1,
411 headers: H,
412 resources: R,
413 ) -> Result<(), Error>
414 where
415 S1: AsRef<str>,
416 S2: AsRef<str>,
417 H: Into<Option<HashMap<S2, S2>>>,
418 R: Into<Option<HashMap<S2, Option<S2>>>>,
419 {
420 let (host, headers) =
421 self.build_request(RequestType::Put, object_name, headers, resources)?;
422
423 let resp = reqwest::blocking::Client::new()
424 .put(&host)
425 .headers(headers)
426 .body(buf.to_owned())
427 .send()?;
428
429 if resp.status().is_success() {
430 Ok(())
431 } else {
432 Err(Error::Object(ObjectError::PutError {
433 msg: format!("can not put object, status code: {}", resp.status()).into(),
434 }))
435 }
436 }
437
438 fn copy_object_from_object<S1, S2, S3, H, R>(
439 &self,
440 src: S1,
441 object_name: S2,
442 headers: H,
443 resources: R,
444 ) -> Result<(), Error>
445 where
446 S1: AsRef<str>,
447 S2: AsRef<str>,
448 S3: AsRef<str>,
449 H: Into<Option<HashMap<S3, S3>>>,
450 R: Into<Option<HashMap<S3, Option<S3>>>>,
451 {
452 let (host, mut headers) =
453 self.build_request(RequestType::Put, object_name, headers, resources)?;
454 headers.insert("x-oss-copy-source", src.as_ref().parse()?);
455
456 let resp = reqwest::blocking::Client::new()
457 .put(&host)
458 .headers(headers)
459 .send()?;
460
461 if resp.status().is_success() {
462 Ok(())
463 } else {
464 Err(Error::Object(ObjectError::CopyError {
465 msg: format!("can not copy object, status code: {}", resp.status()).into(),
466 }))
467 }
468 }
469
470 fn delete_object<S>(&self, object_name: S) -> Result<(), Error>
471 where
472 S: AsRef<str>,
473 {
474 let headers = HashMap::<String, String>::new();
475 let (host, headers) =
476 self.build_request(RequestType::Delete, object_name, Some(headers), None)?;
477
478 let resp = reqwest::blocking::Client::new()
479 .delete(&host)
480 .headers(headers)
481 .send()?;
482
483 if resp.status().is_success() {
484 Ok(())
485 } else {
486 Err(Error::Object(ObjectError::DeleteError {
487 msg: format!("can not delete object, status code: {}", resp.status()).into(),
488 }))
489 }
490 }
491}