1use builders::{DeleteObjectBuilder, GetObjectBuilder, PutObjectBuilder};
2
3use crate::oss::{self, api::objects::stand::builders::GetObjectMetaBuilder};
4
5use self::builders::{
6 AppendObjectBuilder, CopyObjectBuilder, DeleteMultipleObjectsBuilder, HeadObjectBuilder,
7 RestoreObjectBuilder,
8};
9
10pub mod builders {
11
12 use std::collections::HashMap;
13
14 use chrono::{DateTime, Utc};
15 use oss::http::{
16 header::{
17 HeaderMap, ACCEPT_ENCODING, CACHE_CONTROL, CONTENT_DISPOSITION, CONTENT_ENCODING,
18 CONTENT_LANGUAGE, CONTENT_LENGTH, CONTENT_TYPE, ETAG, EXPIRES, IF_MATCH,
19 IF_MODIFIED_SINCE, IF_NONE_MATCH, IF_UNMODIFIED_SINCE, RANGE,
20 },
21 CacheControl, ContentDisposition, ContentEncoding,
22 };
23 use reqwest::Response;
24 use serde::{Deserialize, Serialize};
25
26 use crate::{oss::entities::object::delete_multiple::DeleteResult, util::ByteRange};
27 use crate::{
28 oss::{
29 self,
30 api::{self, insert_custom_header, insert_header, ApiResponseFrom},
31 entities::{
32 object::{
33 delete_multiple::{Delete, Object},
34 CopyObjectResult, JobParameters, MetadataDirective, RestoreRequest,
35 TaggingDirective, Tier,
36 },
37 ObjectACL, ServerSideEncryption, StorageClass,
38 },
39 http, Bytes,
40 },
41 util::oss_md5,
42 };
43
44 #[derive(Debug, Default)]
45 struct PutObjectBuilderHeaders<'a> {
46 content_type: Option<String>,
47 content_encoding: Option<http::ContentEncoding>,
48 content_language: Option<String>,
49 content_disposition: Option<http::ContentDisposition>,
50 cache_control: Option<http::CacheControl>,
51 expires: Option<&'a str>,
52 content_length: Option<u64>,
53 content_md5: Option<String>,
54 etag: Option<String>,
55 forbid_overwrite: Option<bool>,
56 encryption: Option<ServerSideEncryption>,
57 data_encryption: Option<String>,
58 encryption_key_id: Option<String>,
59 object_acl: Option<ObjectACL>,
60 storage_class: Option<StorageClass>,
61 oss_tagging: Option<Vec<(&'a str, &'a str)>>,
62 oss_meta: Option<Vec<(&'a str, &'a str)>>,
64 }
65
66 pub struct PutObjectBuilder<'a> {
67 client: &'a oss::Client<'a>,
68 object: &'a str,
69 content: oss::Bytes,
70 headers: PutObjectBuilderHeaders<'a>,
71 timeout: Option<u64>,
72 }
73
74 impl<'a> PutObjectBuilder<'a> {
75 pub(crate) fn new(client: &'a oss::Client, object: &'a str) -> Self {
76 Self {
77 client,
78 object,
79 content: oss::Bytes::new(),
80 headers: PutObjectBuilderHeaders::default(),
81 timeout: None,
82 }
83 }
84
85 pub fn with_content_type(mut self, value: &'a str) -> Self {
86 self.headers.content_type = Some(value.to_string());
87 self
88 }
89
90 pub fn with_content_language(mut self, value: &'a str) -> Self {
91 self.headers.content_language = Some(value.to_string());
92 self
93 }
94
95 pub fn with_cache_control(mut self, value: http::CacheControl) -> Self {
96 self.headers.cache_control = Some(value);
97 self
98 }
99
100 pub fn with_content_disposition(mut self, value: http::ContentDisposition) -> Self {
101 self.headers.content_disposition = Some(value);
102 self
103 }
104
105 pub fn with_content_encoding(mut self, value: http::ContentEncoding) -> Self {
106 self.headers.content_encoding = Some(value);
107 self
108 }
109
110 pub fn with_content_md5(mut self, value: &'a str) -> Self {
111 self.headers.content_md5 = Some(value.to_string());
112 self
113 }
114
115 pub fn with_content_length(mut self, value: u64) -> Self {
116 self.headers.content_length = Some(value);
117 self
118 }
119
120 pub fn with_etag(mut self, value: &'a str) -> Self {
121 self.headers.etag = Some(value.to_string());
122 self
123 }
124
125 pub fn with_expires(mut self, value: &'a str) -> Self {
126 self.headers.expires = Some(value);
127 self
128 }
129
130 pub fn with_forbid_overwrite(mut self, value: bool) -> Self {
131 self.headers.forbid_overwrite = Some(value);
132 self
133 }
134
135 pub fn with_encryption(mut self, value: ServerSideEncryption) -> Self {
136 self.headers.encryption = Some(value);
137 self
138 }
139
140 pub fn with_data_encryption(mut self, value: &'a str) -> Self {
141 self.headers.data_encryption = Some(value.to_string());
142 self
143 }
144
145 pub fn with_encryption_key_id(mut self, value: &'a str) -> Self {
146 self.headers.encryption_key_id = Some(value.to_string());
147 self
148 }
149
150 pub fn with_object_acl(mut self, value: ObjectACL) -> Self {
151 self.headers.object_acl = Some(value);
152 self
153 }
154
155 pub fn with_storage_class(mut self, value: StorageClass) -> Self {
156 self.headers.storage_class = Some(value);
157 self
158 }
159
160 pub fn with_oss_tagging(mut self, value: Vec<(&'a str, &'a str)>) -> Self {
161 self.headers.oss_tagging = Some(value);
162 self
163 }
164
165 pub fn with_oss_meta(mut self, value: Vec<(&'a str, &'a str)>) -> Self {
166 self.headers.oss_meta = Some(value);
167 self
168 }
169
170 pub fn with_content(mut self, content: oss::Bytes) -> Self {
171 self.content = content;
172 self
173 }
174
175 pub fn with_timeout(mut self, value: u64) -> Self {
176 self.timeout = Some(value);
177 self
178 }
179
180 fn headers(&self) -> http::HeaderMap {
181 let mut headers = http::HeaderMap::new();
182
183 if let Some(content_type) = &self.headers.content_type {
184 insert_header(&mut headers, CONTENT_TYPE, content_type);
185 }
186
187 if let Some(content_language) = &self.headers.content_language {
188 insert_header(&mut headers, CONTENT_LANGUAGE, content_language);
189 }
190 if let Some(content_type) = &self.headers.content_type {
191 insert_header(&mut headers, CONTENT_TYPE, content_type);
192 }
193
194 if let Some(cache_control) = &self.headers.cache_control {
195 insert_header(&mut headers, CACHE_CONTROL, cache_control);
196 }
197
198 if let Some(content_disposition) = &self.headers.content_disposition {
199 insert_header(&mut headers, CONTENT_DISPOSITION, content_disposition);
200 }
201
202 if let Some(content_encoding) = &self.headers.content_encoding {
203 insert_header(&mut headers, CONTENT_ENCODING, content_encoding);
204 }
205
206 if let Some(content_length) = &self.headers.content_length {
207 insert_header(&mut headers, CONTENT_LENGTH, content_length);
208 }
209
210 if let Some(etag) = &self.headers.etag {
211 insert_header(&mut headers, ETAG, etag);
212 }
213
214 if let Some(content_md5) = &self.headers.content_md5 {
215 headers.insert("Content-MD5", content_md5.parse().unwrap());
216 }
217
218 if let Some(expires) = &self.headers.expires {
219 insert_header(&mut headers, EXPIRES, expires);
220 }
221
222 if let Some(forbid_overwrite) = &self.headers.forbid_overwrite {
223 insert_custom_header(&mut headers, "x-oss-forbid-overwrite", forbid_overwrite);
224 }
225
226 if let Some(encryption) = &self.headers.encryption {
227 insert_custom_header(&mut headers, "x-oss-server-side-encryption", encryption);
228 }
229
230 if let Some(data_encryption) = &self.headers.data_encryption {
231 headers.insert(
232 "x-oss-server-side-data-encryption",
233 data_encryption.parse().unwrap(),
234 );
235 }
236
237 if let Some(encryption_key_id) = &self.headers.encryption_key_id {
238 insert_custom_header(
239 &mut headers,
240 "x-oss-server-side-encryption-key-id",
241 encryption_key_id,
242 );
243 }
244
245 if let Some(object_acl) = &self.headers.object_acl {
246 insert_custom_header(&mut headers, "x-oss-object-acl", object_acl);
247 }
248
249 if let Some(storage_class) = &self.headers.storage_class {
250 insert_custom_header(&mut headers, "x-oss-storage-class", storage_class);
251 }
252
253 if let Some(tags) = &self.headers.oss_tagging {
254 let kv: HashMap<&str, &str> = tags.to_owned().into_iter().collect();
255 let value = serde_qs::to_string(&kv).unwrap();
256 insert_custom_header(&mut headers, "x-oss-tagging", value);
257 }
258
259 if let Some(oss_meta) = &self.headers.oss_meta {
260 for (key, value) in oss_meta {
261 insert_custom_header(&mut headers, &format!("x-oss-meta-{}", key), value);
262 }
263 }
264 headers
265 }
266
267 pub async fn execute(&self) -> api::ApiResult<()> {
268 let res = format!("/{}/{}", self.client.bucket(), self.object);
269 let url = self.client.object_url(self.object);
270 let headers = self.headers();
271
272 let resp = self
273 .client
274 .request
275 .task()
276 .with_url(&url)
277 .with_method(http::Method::PUT)
278 .with_headers(headers)
279 .with_body(self.content.to_owned())
280 .with_resource(&res)
281 .execute_timeout(self.timeout.unwrap_or(self.client.timeout()))
282 .await?;
283 Ok(ApiResponseFrom(resp).to_empty().await)
284 }
285 }
286
287 #[derive(Debug, Default, Clone)]
288 struct CopyObjectBuilderHeaders<'a> {
289 copy_source: Option<&'a str>,
290 source_version_id: Option<&'a str>,
291 version_id: Option<&'a str>,
292 forbid_overwrite: Option<bool>,
293 if_match: Option<&'a str>,
294 if_none_match: Option<&'a str>,
295 if_unmodified_since: Option<DateTime<Utc>>,
296 if_modified_since: Option<DateTime<Utc>>,
297 metadata_directive: Option<MetadataDirective>,
298 encryption: Option<ServerSideEncryption>,
299 enc_key_id: Option<&'a str>,
300 object_acl: Option<ObjectACL>,
301 storage_class: Option<StorageClass>,
302 oss_tagging: Option<Vec<(&'a str, &'a str)>>,
303 tagging_directive: Option<TaggingDirective>,
304 }
305
306 #[derive(Debug, Clone)]
307 pub struct CopyObjectBuilder<'a> {
308 client: &'a oss::Client<'a>,
309 object: &'a str,
310 headers: CopyObjectBuilderHeaders<'a>,
311 }
312
313 impl<'a> CopyObjectBuilder<'a> {
314 pub(crate) fn new(client: &'a oss::Client, object: &'a str) -> Self {
315 Self {
316 client,
317 object,
318 headers: CopyObjectBuilderHeaders::default(),
319 }
320 }
321
322 pub fn with_forbid_overwrite(mut self, value: bool) -> Self {
326 self.headers.forbid_overwrite = Some(value);
327 self
328 }
329
330 pub fn with_copy_source(mut self, value: &'a str) -> Self {
332 self.headers.copy_source = Some(value);
333 self
334 }
335
336 pub fn with_source_version_id(mut self, value: &'a str) -> Self {
337 self.headers.source_version_id = Some(value);
338 self
339 }
340
341 pub fn with_version_id(mut self, value: &'a str) -> Self {
342 self.headers.version_id = Some(value);
343 self
344 }
345
346 pub fn with_if_match(mut self, value: &'a str) -> Self {
348 self.headers.if_match = Some(value);
349 self
350 }
351
352 pub fn with_if_none_match(mut self, value: &'a str) -> Self {
353 self.headers.if_none_match = Some(value);
354 self
355 }
356
357 pub fn with_if_unmodified_since(mut self, value: DateTime<Utc>) -> Self {
358 self.headers.if_unmodified_since = Some(value);
359 self
360 }
361
362 pub fn with_if_modified_since(mut self, value: DateTime<Utc>) -> Self {
363 self.headers.if_modified_since = Some(value);
364 self
365 }
366
367 pub fn with_metadata_directive(mut self, value: MetadataDirective) -> Self {
368 self.headers.metadata_directive = Some(value);
369 self
370 }
371
372 pub fn with_encryption(mut self, value: ServerSideEncryption) -> Self {
373 self.headers.encryption = Some(value);
374 self
375 }
376
377 pub fn with_enc_key_id(mut self, value: &'a str) -> Self {
378 self.headers.enc_key_id = Some(value);
379 self
380 }
381
382 pub fn with_object_acl(mut self, value: ObjectACL) -> Self {
383 self.headers.object_acl = Some(value);
384 self
385 }
386
387 pub fn with_storage_class(mut self, value: StorageClass) -> Self {
388 self.headers.storage_class = Some(value);
389 self
390 }
391
392 pub fn with_oss_tagging(mut self, value: Vec<(&'a str, &'a str)>) -> Self {
393 self.headers.oss_tagging = Some(value);
394 self
395 }
396
397 pub fn with_tagging_directive(mut self, value: TaggingDirective) -> Self {
398 self.headers.tagging_directive = Some(value);
399 self
400 }
401
402 fn headers(&self) -> HeaderMap {
403 let mut headers = HeaderMap::new();
404 if let Some(true) = self.headers.forbid_overwrite {
405 insert_custom_header(&mut headers, "x-oss-forbid-overwrite", "true");
406 }
407
408 if let Some(copy_source) = self.headers.copy_source {
409 let value = if let Some(source_version_id) = self.headers.source_version_id {
410 format!("{}?versionId={}", copy_source, source_version_id)
411 } else {
412 copy_source.to_string()
413 };
414 let key = "x-oss-copy-source";
415 insert_custom_header(&mut headers, key, value);
416 }
417
418 if let Some(value) = self.headers.if_match {
419 let key = "x-oss-copy-source-if-match";
420 insert_custom_header(&mut headers, key, value);
421 }
422
423 if let Some(value) = self.headers.if_none_match {
424 let key = "x-oss-copy-source-if-none-match";
425 insert_custom_header(&mut headers, key, value);
426 }
427
428 if let Some(value) = &self.headers.if_unmodified_since {
429 let key = "x-oss-copy-source-if-unmodified-since";
430 insert_custom_header(
431 &mut headers,
432 key,
433 value.format(oss::GMT_DATE_FMT).to_string(),
434 )
435 }
436
437 if let Some(value) = &self.headers.if_modified_since {
438 let key = "x-oss-copy-source-if-modified-since";
439 insert_custom_header(
440 &mut headers,
441 key,
442 value.format(oss::GMT_DATE_FMT).to_string(),
443 )
444 }
445
446 if let Some(value) = &self.headers.metadata_directive {
447 let key = "x-oss-metadata-directive";
448 insert_custom_header(&mut headers, key, value.to_string())
449 }
450
451 if let Some(value) = &self.headers.encryption {
452 let key = "x-oss-server-side-encryption";
453 insert_custom_header(&mut headers, key, value.to_string())
454 }
455
456 if let Some(value) = self.headers.enc_key_id {
457 let key = "x-oss-server-side-encryption-key-id";
458 insert_custom_header(&mut headers, key, value)
459 }
460
461 if let Some(value) = &self.headers.object_acl {
462 let key = "x-oss-object-acl";
463 insert_custom_header(&mut headers, key, value.to_string())
464 }
465
466 if let Some(value) = &self.headers.storage_class {
467 let key = "x-oss-storage-class";
468 insert_custom_header(&mut headers, key, value.to_string())
469 }
470
471 if let Some(tags) = &self.headers.oss_tagging {
472 let kv: HashMap<&str, &str> = tags.to_owned().into_iter().collect();
473 let value = serde_qs::to_string(&kv).unwrap();
474 insert_custom_header(&mut headers, "x-oss-tagging", value);
475 }
476
477 if let Some(value) = &self.headers.tagging_directive {
478 let key = "x-oss-tagging-directive";
479 insert_custom_header(&mut headers, key, value.to_string())
480 }
481
482 headers
483 }
484
485 pub async fn execute(&self) -> api::ApiResult<CopyObjectResult> {
486 let res = format!("/{}/{}", self.client.bucket(), self.object);
487 let url = self.client.object_url(self.object);
488 let headers = self.headers();
489 let resp = self
490 .client
491 .request
492 .task()
493 .with_url(&url)
494 .with_method(http::Method::PUT)
495 .with_headers(headers)
496 .with_resource(&res)
497 .execute_timeout(self.client.timeout())
498 .await?;
499 Ok(ApiResponseFrom(resp).to_type().await)
500 }
501 }
502
503 #[derive(Debug, Default)]
504 struct AppendObjectBuilderHeaders<'a> {
505 cache_control: Option<http::CacheControl>,
506 content_disposition: Option<http::ContentDisposition>,
507 content_encoding: Option<http::ContentEncoding>,
508 content_md5: Option<&'a str>,
509 expires: Option<DateTime<Utc>>,
510 encryption: Option<ServerSideEncryption>,
511 object_acl: Option<ObjectACL>,
512 storage_class: Option<StorageClass>,
513 oss_meta: Option<Vec<(&'a str, &'a str)>>,
514 oss_tagging: Option<Vec<(&'a str, &'a str)>>,
515 }
516
517 pub struct AppendObjectBuilder<'a> {
518 client: &'a oss::Client<'a>,
519 object: String,
520 position: usize,
521 content: oss::Bytes,
522 headers: AppendObjectBuilderHeaders<'a>,
523 }
524
525 impl<'a> AppendObjectBuilder<'a> {
526 pub(crate) fn new(client: &'a oss::Client, object: &'a str) -> Self {
527 Self {
528 client,
529 object: object.to_string(),
530 position: 0,
531 content: oss::Bytes::new(),
532 headers: AppendObjectBuilderHeaders::default(),
533 }
534 }
535
536 pub fn with_position(mut self, value: usize) -> Self {
537 self.position = value;
538 self
539 }
540
541 pub fn with_content(mut self, value: oss::Bytes) -> Self {
542 self.content = value;
543 self
544 }
545
546 pub fn with_cache_control(mut self, value: CacheControl) -> Self {
547 self.headers.cache_control = Some(value);
548 self
549 }
550 pub fn with_content_disposition(mut self, value: ContentDisposition) -> Self {
551 self.headers.content_disposition = Some(value);
552 self
553 }
554 pub fn with_content_encoding(mut self, value: ContentEncoding) -> Self {
555 self.headers.content_encoding = Some(value);
556 self
557 }
558
559 pub fn with_expires(mut self, value: DateTime<Utc>) -> Self {
560 self.headers.expires = Some(value);
561 self
562 }
563
564 pub fn with_encryption(mut self, value: ServerSideEncryption) -> Self {
565 self.headers.encryption = Some(value);
566 self
567 }
568
569 pub fn with_object_acl(mut self, value: ObjectACL) -> Self {
570 self.headers.object_acl = Some(value);
571 self
572 }
573
574 pub fn with_storage_class(mut self, value: StorageClass) -> Self {
575 self.headers.storage_class = Some(value);
576 self
577 }
578
579 pub fn with_content_md5(mut self, value: &'a str) -> Self {
580 self.headers.content_md5 = Some(value);
581 self
582 }
583
584 pub fn with_oss_tagging(mut self, value: Vec<(&'a str, &'a str)>) -> Self {
585 self.headers.oss_tagging = Some(value);
586 self
587 }
588
589 pub fn with_oss_meta(mut self, value: Vec<(&'a str, &'a str)>) -> Self {
590 self.headers.oss_meta = Some(value);
591 self
592 }
593
594 #[allow(unused)]
595 fn headers(&self) -> http::HeaderMap {
596 let mut headers = http::HeaderMap::new();
597
598 if let Some(cache_control) = &self.headers.cache_control {
599 insert_header(&mut headers, CACHE_CONTROL, cache_control);
600 }
601
602 if let Some(content_disposition) = &self.headers.content_disposition {
603 insert_header(&mut headers, CONTENT_DISPOSITION, content_disposition);
604 }
605
606 if let Some(content_encoding) = &self.headers.content_encoding {
607 insert_header(&mut headers, CONTENT_ENCODING, content_encoding);
608 }
609
610 if let Some(content_md5) = &self.headers.content_md5 {
611 headers.insert("Content-MD5", content_md5.parse().unwrap());
612 }
613
614 if let Some(expires) = &self.headers.expires {
615 insert_header(&mut headers, EXPIRES, expires.format(oss::GMT_DATE_FMT));
616 }
617
618 if let Some(encryption) = &self.headers.encryption {
619 insert_custom_header(&mut headers, "x-oss-server-side-encryption", encryption);
620 }
621
622 if let Some(object_acl) = &self.headers.object_acl {
623 insert_custom_header(&mut headers, "x-oss-object-acl", object_acl);
624 }
625
626 if let Some(storage_class) = &self.headers.storage_class {
627 insert_custom_header(&mut headers, "x-oss-storage-class", storage_class);
628 }
629
630 if let Some(tags) = &self.headers.oss_tagging {
631 let kv: HashMap<&str, &str> = tags.to_owned().into_iter().collect();
632 let value = serde_qs::to_string(&kv).unwrap();
633 insert_custom_header(&mut headers, "x-oss-tagging", value);
634 }
635
636 if let Some(oss_meta) = &self.headers.oss_meta {
637 for (key, value) in oss_meta {
638 insert_custom_header(&mut headers, &format!("x-oss-meta-{}", key), value);
639 }
640 }
641 headers
642 }
643
644 pub async fn execute(&self) -> api::ApiResult {
645 let res = format!(
646 "/{}/{}?append&position={}",
647 self.client.bucket(),
648 &self.object,
649 self.position
650 );
651 let url = format!(
652 "{}?append&position={}",
653 self.client.object_url(&self.object),
654 self.position
655 );
656
657 let mut headers = self.headers();
658 headers.insert(CONTENT_LENGTH, self.content.len().into());
659 let resp = self
662 .client
663 .request
664 .task()
665 .with_url(&url)
666 .with_headers(headers)
667 .with_resource(&res)
668 .with_body(self.content.to_owned())
669 .with_method(http::Method::POST)
670 .execute()
671 .await?;
672 Ok(ApiResponseFrom(resp).to_empty().await)
673 }
674 }
675
676 #[derive(Debug, Default, Serialize, Deserialize)]
677 pub(crate) struct GetObjectBuilderQuery<'a> {
678 #[serde(
679 rename = "response-cache-control",
680 skip_serializing_if = "Option::is_none"
681 )]
682 cache_control: Option<&'a str>,
683 #[serde(
684 rename = "response-content-disposition",
685 skip_serializing_if = "Option::is_none"
686 )]
687 content_disposition: Option<&'a str>,
688 #[serde(
689 rename = "response-content-encoding",
690 skip_serializing_if = "Option::is_none"
691 )]
692 content_encoding: Option<&'a str>,
693 #[serde(
694 rename = "response-content-language",
695 skip_serializing_if = "Option::is_none"
696 )]
697 content_language: Option<&'a str>,
698 #[serde(
699 rename = "response-content-type",
700 skip_serializing_if = "Option::is_none"
701 )]
702 content_type: Option<&'a str>,
703 #[serde(rename = "response-expires", skip_serializing_if = "Option::is_none")]
704 expires: Option<&'a str>,
705 #[serde(rename = "versionId", skip_serializing_if = "Option::is_none")]
706 version_id: Option<&'a str>,
707 }
708
709 #[derive(Debug)]
710 pub struct GetObjectBuilder<'a> {
711 client: &'a oss::Client<'a>,
712 object: &'a str,
713 range: Option<ByteRange>,
714 modified_since: Option<DateTime<Utc>>,
715 unmodified_since: Option<DateTime<Utc>>,
716 r#match: Option<&'a str>,
717 none_match: Option<&'a str>,
718 accept_encoding: Option<&'a str>,
719 query: GetObjectBuilderQuery<'a>,
720 timeout: Option<u64>,
721 }
722
723 impl<'a> GetObjectBuilder<'a> {
724 pub(crate) fn new(client: &'a oss::Client, object: &'a str) -> Self {
725 Self {
726 client,
727 object,
728 range: None,
729 r#match: None,
730 modified_since: None,
731 unmodified_since: None,
732 none_match: None,
733 accept_encoding: None,
734 query: GetObjectBuilderQuery::default(),
735 timeout: None,
736 }
737 }
738
739 pub fn with_version_id(mut self, value: &'a str) -> Self {
740 self.query.version_id = Some(value);
741 self
742 }
743
744 pub fn with_content_type(mut self, value: &'a str) -> Self {
745 self.query.content_type = Some(value);
746 self
747 }
748
749 pub fn with_content_language(mut self, value: &'a str) -> Self {
750 self.query.content_language = Some(value);
751 self
752 }
753
754 pub fn with_expires(mut self, value: &'a str) -> Self {
755 self.query.expires = Some(value);
756 self
757 }
758
759 pub fn with_cache_control(mut self, value: &'a str) -> Self {
760 self.query.cache_control = Some(value);
761 self
762 }
763
764 pub fn with_content_disposition(mut self, value: &'a str) -> Self {
765 self.query.content_disposition = Some(value);
766 self
767 }
768
769 pub fn with_content_encoding(mut self, value: &'a str) -> Self {
770 self.query.content_encoding = Some(value);
771 self
772 }
773
774 pub fn with_range(mut self, value: ByteRange) -> Self {
775 self.range = Some(value);
776 self
777 }
778
779 pub fn with_modified_since(mut self, value: DateTime<Utc>) -> Self {
780 self.modified_since = Some(value);
781 self
782 }
783
784 pub fn with_unmodified_since(mut self, value: DateTime<Utc>) -> Self {
785 self.unmodified_since = Some(value);
786 self
787 }
788
789 pub fn with_match(mut self, value: &'a str) -> Self {
790 self.r#match = Some(value);
791 self
792 }
793
794 pub fn with_none_match(mut self, value: &'a str) -> Self {
795 self.none_match = Some(value);
796 self
797 }
798
799 pub fn with_accept_encoding(mut self, value: &'a str) -> Self {
800 self.accept_encoding = Some(value);
801 self
802 }
803
804 pub fn with_timeout(mut self, value: u64) -> Self {
805 self.timeout = Some(value);
806 self
807 }
808
809 pub(crate) fn query(&self) -> String {
810 serde_qs::to_string(&self.query).unwrap()
811 }
812
813 pub(crate) fn headers(&self) -> http::HeaderMap {
814 let mut headers = http::HeaderMap::new();
815 if let Some(range) = &self.range {
816 insert_header(&mut headers, RANGE, range.to_string());
817 }
818 if let Some(modified_since) = &self.modified_since {
819 insert_header(&mut headers, IF_MODIFIED_SINCE, modified_since);
820 }
821 if let Some(unmodified_since) = &self.unmodified_since {
822 let dt = unmodified_since.format(oss::GMT_DATE_FMT).to_string();
823 insert_header(&mut headers, IF_UNMODIFIED_SINCE, dt);
824 }
825 if let Some(r#match) = &self.r#match {
826 insert_header(&mut headers, IF_MATCH, r#match);
827 }
828 if let Some(none_match) = &self.none_match {
829 insert_header(&mut headers, IF_NONE_MATCH, none_match);
830 }
831 if let Some(accept_encoding) = &self.accept_encoding {
832 insert_header(&mut headers, ACCEPT_ENCODING, accept_encoding);
833 }
834 headers
835 }
836
837 pub async fn execute(&self) -> api::ApiResult<Bytes> {
838 let mut res = format!("/{}/{}", self.client.bucket(), self.object);
839 let mut url = self.client.object_url(self.object);
840 let query = self.query();
841 if !query.is_empty() {
843 res = format!("{}?{}", res, query);
844 url = format!("{}?{}", url, query)
845 }
846
847 let headers = self.headers();
848 let resp = self
849 .client
850 .request
851 .task()
852 .with_url(&url)
853 .with_headers(headers)
854 .with_resource(&res)
855 .execute_timeout(self.timeout.unwrap_or(self.client.timeout()))
856 .await?;
857
858 Ok(ApiResponseFrom(resp).to_bytes().await)
859 }
860 }
861
862 #[derive(Debug)]
863 pub struct DeleteObjectBuilder<'a> {
864 client: &'a oss::Client<'a>,
865 object: &'a str,
866 version_id: Option<&'a str>,
867 }
868
869 impl<'a> DeleteObjectBuilder<'a> {
870 pub fn new(client: &'a oss::Client, object: &'a str) -> Self {
871 Self {
872 client,
873 object,
874 version_id: None,
875 }
876 }
877
878 pub fn with_version_id(mut self, value: &'a str) -> Self {
879 self.version_id = Some(value);
880 self
881 }
882
883 pub async fn execute(&self) -> api::ApiResult<()> {
884 let mut res = format!("/{}/{}", self.client.bucket(), self.object);
885 let mut url = self.client.object_url(self.object);
886 if let Some(version_id) = self.version_id {
887 res = format!("{}?versionId={}", res, version_id);
888 url = format!("{}?versionId={}", url, version_id);
889 }
890
891 let resp = self
892 .client
893 .request
894 .task()
895 .with_url(&url)
896 .with_resource(&res)
897 .with_method(http::Method::DELETE)
898 .execute()
899 .await?;
900
901 Ok(ApiResponseFrom(resp).to_empty().await)
902 }
903 }
904
905 #[allow(unused)]
906 pub struct DeleteMultipleObjectsBuilder<'a> {
907 client: &'a oss::Client<'a>,
908 quiet: Option<bool>,
909 encoding_type: Option<&'a str>,
910 deletes: Vec<(&'a str, &'a str)>,
911 content_length: Option<u64>,
912 content_md5: Option<&'a str>,
913 }
914
915 impl<'a> DeleteMultipleObjectsBuilder<'a> {
916 pub fn new(client: &'a oss::Client) -> Self {
917 Self {
918 client,
919 quiet: Some(false),
920 deletes: Vec::new(),
921 encoding_type: None,
922 content_length: None,
923 content_md5: None,
924 }
925 }
926
927 pub fn with_deletes(mut self, value: Vec<(&'a str, &'a str)>) -> Self {
930 self.deletes = value;
931 self
932 }
933
934 pub fn with_quiet(mut self, value: bool) -> Self {
935 self.quiet = Some(value);
936 self
937 }
938
939 pub fn with_encoding_type(mut self, value: &'a str) -> Self {
940 self.encoding_type = Some(value);
941 self
942 }
943
944 fn content(&self) -> Delete {
945 Delete {
946 quiet: self.quiet,
947 object: self
948 .deletes
949 .iter()
950 .map(|item| Object {
951 key: item.0.to_string(),
952 version_id: if item.1.is_empty() {
953 None
954 } else {
955 Some(item.1.to_string())
956 },
957 })
958 .collect(),
959 }
960 }
961
962 pub async fn execute(&self) -> api::ApiResult<DeleteResult> {
963 let resp = self.inner_execute(false).await?;
964 Ok(ApiResponseFrom(resp).to_type().await)
965 }
966
967 pub async fn execute_quiet(&self) -> api::ApiResult {
968 let resp = self.inner_execute(true).await?;
969 Ok(ApiResponseFrom(resp).to_empty().await)
970 }
971
972 async fn inner_execute(&self, quiet: bool) -> oss::Result<Response> {
973 let res = format!("/{}/?{}", self.client.bucket(), "delete");
974 let url = format!("{}?{}", self.client.base_url(), "delete");
975 let mut content = self.content();
976 content.quiet = Some(quiet);
977 let content = quick_xml::se::to_string(&content).unwrap();
978 let content = oss::Bytes::from(content);
979
980 let mut headers = http::header::HeaderMap::new();
981 headers.insert(CONTENT_LENGTH, content.len().into());
982 let content_md5 = oss_md5(&content).unwrap();
983 headers.insert("Content-MD5", content_md5.parse().unwrap());
984 if let Some(encoding_type) = self.encoding_type {
985 headers.insert("Encoding-type", encoding_type.parse().unwrap());
986 }
987
988 self.client
989 .request
990 .task()
991 .with_url(&url)
992 .with_method(http::Method::POST)
993 .with_headers(headers)
994 .with_resource(&res)
995 .with_body(content)
996 .execute_timeout(self.client.timeout())
997 .await
998 }
999 }
1000
1001 pub struct HeadObjectBuilder<'a> {
1002 client: &'a oss::Client<'a>,
1003 object: &'a str,
1004 version_id: Option<&'a str>,
1005 modified_since: Option<DateTime<Utc>>,
1006 unmodified_since: Option<DateTime<Utc>>,
1007 r#match: Option<&'a str>,
1008 none_match: Option<&'a str>,
1009 }
1010
1011 impl<'a> HeadObjectBuilder<'a> {
1012 pub(crate) fn new(client: &'a oss::Client, object: &'a str) -> Self {
1013 Self {
1014 client,
1015 object,
1016 version_id: None,
1017 modified_since: None,
1018 unmodified_since: None,
1019 r#match: None,
1020 none_match: None,
1021 }
1022 }
1023
1024 pub fn with_version_id(mut self, version_id: &'a str) -> Self {
1025 self.version_id = Some(version_id);
1026 self
1027 }
1028
1029 pub fn with_modified_since(mut self, value: DateTime<Utc>) -> Self {
1030 self.modified_since = Some(value);
1031 self
1032 }
1033
1034 pub fn with_unmodified_since(mut self, value: DateTime<Utc>) -> Self {
1035 self.unmodified_since = Some(value);
1036 self
1037 }
1038
1039 pub fn with_match(mut self, value: &'a str) -> Self {
1040 self.r#match = Some(value);
1041 self
1042 }
1043
1044 pub fn with_none_match(mut self, value: &'a str) -> Self {
1045 self.none_match = Some(value);
1046 self
1047 }
1048
1049 fn headers(&self) -> http::HeaderMap {
1050 let mut headers = http::HeaderMap::new();
1051 if let Some(modified_since) = self.modified_since {
1052 insert_header(
1053 &mut headers,
1054 IF_MODIFIED_SINCE,
1055 modified_since.format(oss::GMT_DATE_FMT).to_string(),
1056 );
1057 }
1058
1059 if let Some(unmodified_since) = self.unmodified_since {
1060 insert_header(
1061 &mut headers,
1062 IF_UNMODIFIED_SINCE,
1063 unmodified_since.format(oss::GMT_DATE_FMT).to_string(),
1064 );
1065 }
1066 if let Some(r#match) = self.r#match {
1067 insert_header(&mut headers, IF_MATCH, r#match);
1068 }
1069 if let Some(none_match) = self.none_match {
1070 insert_header(&mut headers, IF_NONE_MATCH, none_match);
1071 }
1072 headers
1073 }
1074
1075 pub async fn execute(&self) -> api::ApiResult {
1076 let mut res = format!("/{}/{}", self.client.bucket(), self.object);
1077 let mut url = self.client.object_url(self.object);
1078 if let Some(version_id) = self.version_id {
1079 res = format!("{}?versionId={}", res, version_id);
1080 url = format!("{}?versionId={}", url, version_id);
1081 };
1082
1083 let resp = self
1084 .client
1085 .request
1086 .task()
1087 .with_url(&url)
1088 .with_method(http::Method::HEAD)
1089 .with_headers(self.headers())
1090 .with_resource(&res)
1091 .execute_timeout(self.client.timeout())
1092 .await?;
1093
1094 Ok(ApiResponseFrom(resp).to_empty().await)
1095 }
1096 }
1097
1098 pub struct GetObjectMetaBuilder<'a> {
1099 client: &'a oss::Client<'a>,
1100 object: &'a str,
1101 version_id: Option<&'a str>,
1102 }
1103
1104 impl<'a> GetObjectMetaBuilder<'a> {
1105 pub(crate) fn new(client: &'a oss::Client, object: &'a str) -> Self {
1106 Self {
1107 client,
1108 object,
1109 version_id: None,
1110 }
1111 }
1112
1113 pub fn with_version_id(mut self, version_id: &'a str) -> Self {
1114 self.version_id = Some(version_id);
1115 self
1116 }
1117
1118 pub async fn execute(&self) -> api::ApiResult<()> {
1119 let mut res = format!(
1120 "/{}/{}?{}",
1121 self.client.options.bucket, self.object, "objectMeta"
1122 );
1123
1124 let mut url = format!("{}?{}", self.client.object_url(self.object), "objectMeta");
1125 if let Some(version_id) = self.version_id {
1128 res = format!("{}&versionId={}", res, version_id);
1129 url = format!("{}&versionId={}", url, version_id);
1130 }
1131
1132 let resp = self
1133 .client
1134 .request
1135 .task()
1136 .with_url(&url)
1137 .with_resource(&res)
1138 .execute()
1139 .await?;
1140
1141 Ok(ApiResponseFrom(resp).to_empty().await)
1142 }
1143 }
1144
1145 pub struct RestoreObjectBuilder<'a> {
1146 client: &'a oss::Client<'a>,
1147 object: &'a str,
1148 version_id: Option<&'a str>,
1149 days: Option<u8>,
1150 tier: Option<Tier>,
1151 }
1152
1153 impl<'a> RestoreObjectBuilder<'a> {
1154 pub fn new(client: &'a oss::Client, object: &'a str) -> Self {
1155 Self {
1156 client,
1157 object,
1158 version_id: None,
1159 days: None,
1160 tier: None,
1161 }
1162 }
1163
1164 pub fn with_days(mut self, days: u8) -> Self {
1165 self.days = Some(days);
1166 self
1167 }
1168
1169 pub fn with_tier(mut self, tier: Tier) -> Self {
1170 self.tier = Some(tier);
1171 self
1172 }
1173
1174 fn config(&self) -> Option<String> {
1175 let days = self.days?;
1176 let request = RestoreRequest {
1177 days,
1178 job_parameters: self
1179 .tier
1180 .as_ref()
1181 .map(|tier| JobParameters { tier: tier.clone() }),
1182 };
1183 quick_xml::se::to_string(&request).ok()
1184 }
1185
1186 pub async fn execute(&self) -> api::ApiResult<()> {
1187 let mut res = format!("/{}/{}?{}", self.client.bucket(), self.object, "restore");
1188 let mut url = format!("{}?{}", self.client.object_url(self.object), "restore");
1189 if let Some(version_id) = self.version_id {
1190 res = format!("{}&versionId={}", res, version_id);
1191 url = format!("{}&versionId={}", url, version_id);
1192 };
1193
1194 let config = Bytes::from(self.config().unwrap_or("".to_string()));
1195
1196 let resp = self
1197 .client
1198 .request
1199 .task()
1200 .with_url(&url)
1201 .with_method(http::Method::POST)
1202 .with_body(config)
1203 .with_resource(&res)
1204 .execute()
1205 .await?;
1206
1207 Ok(ApiResponseFrom(resp).to_empty().await)
1208 }
1209 }
1210}
1211
1212#[allow(non_snake_case)]
1214impl<'a> oss::Client<'a> {
1215 pub fn PutObject(&self, object: &'a str) -> PutObjectBuilder {
1220 PutObjectBuilder::new(self, object)
1221 }
1222
1223 pub fn GetObject(&self, object: &'a str) -> GetObjectBuilder {
1228 GetObjectBuilder::new(self, object)
1229 }
1230
1231 pub fn CopyObject(&self, object: &'a str) -> CopyObjectBuilder {
1236 CopyObjectBuilder::new(self, object)
1237 }
1238
1239 pub fn AppendObject(&self, object: &'a str) -> AppendObjectBuilder {
1244 AppendObjectBuilder::new(self, object)
1245 }
1246
1247 pub fn DeleteObject(&self, object: &'a str) -> DeleteObjectBuilder {
1252 DeleteObjectBuilder::new(self, object)
1253 }
1254
1255 pub fn DeleteMultipleObjects(&self) -> DeleteMultipleObjectsBuilder {
1260 DeleteMultipleObjectsBuilder::new(self)
1261 }
1262
1263 pub fn HeadObject(&self, object: &'a str) -> HeadObjectBuilder {
1268 HeadObjectBuilder::new(self, object)
1269 }
1270
1271 pub fn GetObjectMeta(&self, object: &'a str) -> GetObjectMetaBuilder {
1277 GetObjectMetaBuilder::new(self, object)
1278 }
1279
1280 pub fn RestoreObject(&self, object: &'a str) -> RestoreObjectBuilder {
1285 RestoreObjectBuilder::new(self, object)
1286 }
1287}
1288
1289#[cfg(test)]
1290mod tests {
1291 use super::*;
1292 use crate::oss::{self, http::ContentDisposition};
1293 use crate::util::ByteRange;
1294 use chrono::Utc;
1295 #[test]
1296 fn get_object_builder_arugments() {
1297 let option = oss::Options::default();
1298 let client = oss::Client::new(option);
1299 let filename = Some("测试.txt".to_string());
1300 let content_disposition = ContentDisposition::ATTACHMENT(filename).to_string();
1301
1302 let builder = GetObjectBuilder::new(&client, "example/ex1.txt")
1303 .with_version_id("version123")
1304 .with_content_type("text/plain")
1305 .with_content_language("zh-CN")
1306 .with_expires("expires")
1307 .with_cache_control("cache")
1308 .with_content_disposition(content_disposition.as_str())
1309 .with_content_encoding("GZIP")
1310 .with_range(ByteRange::new().with_start(500).with_amount(1000))
1311 .with_modified_since(Utc::now())
1312 .with_unmodified_since(Utc::now())
1313 .with_match("etag")
1314 .with_none_match("etag")
1315 .with_accept_encoding("text/plain");
1316
1317 let left = r#"response-cache-control=cache&response-content-disposition=attachment%3Bfilename%3D%22%E6%B5%8B%E8%AF%95.txt%22&response-content-encoding=GZIP&response-content-language=zh-CN&response-content-type=text%2Fplain&response-expires=expires&versionId=version123"#;
1318
1319 assert_eq!(left, builder.query());
1320 }
1321}