Skip to main content

ali_oss_rs/
common.rs

1//! Common types: structs and enumerations
2use std::{collections::HashMap, fmt::Display};
3
4use quick_xml::events::Event;
5
6use crate::error::Error;
7use crate::Result;
8
9pub const VERSION: &str = "0.2.5";
10
11pub const MIME_TYPE_XML: &str = "application/xml";
12pub const DELETE_MULTIPLE_OBJECTS_LIMIT: usize = 1000;
13pub const SIGNATURE_VERSION: &str = "OSS4-HMAC-SHA256";
14pub const UNSIGNED_PAYLOAD: &str = "UNSIGNED-PAYLOAD";
15pub const MIN_BUCKET_NAME_LENGTH: usize = 3;
16pub const MAX_BUCKET_NAME_LENGTH: usize = 63;
17pub const MAX_LIST_OBJECTS_LIMIT: u32 = 1000;
18
19#[derive(Debug, Clone, Default)]
20#[cfg_attr(feature = "serde-support", derive(serde::Serialize, serde::Deserialize))]
21#[cfg_attr(feature = "serde-camelcase", serde(rename_all = "camelCase"))]
22pub struct Owner {
23    pub id: String,
24    pub display_name: String,
25}
26
27impl Owner {
28    pub(crate) fn from_xml_reader(reader: &mut quick_xml::Reader<&[u8]>) -> Result<Self> {
29        let mut current_tag = "".to_string();
30        let mut owner = Self::default();
31
32        loop {
33            match reader.read_event()? {
34                Event::Eof => break,
35
36                Event::Start(e) => {
37                    current_tag = String::from_utf8_lossy(e.local_name().as_ref()).into_owned();
38                }
39
40                Event::Text(e) => match current_tag.as_str() {
41                    "ID" => owner.id = e.unescape()?.trim().to_string(),
42                    "DisplayName" => owner.display_name = e.unescape()?.trim().to_string(),
43                    _ => {}
44                },
45
46                Event::End(e) => {
47                    current_tag.clear();
48                    if e.local_name().as_ref() == b"Owner" {
49                        break;
50                    }
51                }
52
53                _ => {}
54            }
55        }
56
57        Ok(owner)
58    }
59}
60
61/// Represents the storage class for an object in Aliyun OSS.
62#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
63#[cfg_attr(feature = "serde-support", derive(serde::Serialize, serde::Deserialize))]
64pub enum StorageClass {
65    /// 标准存储
66    #[default]
67    #[cfg_attr(feature = "serde-support", serde(rename = "Standard"))]
68    Standard,
69
70    /// 低频访问
71    #[cfg_attr(feature = "serde-support", serde(rename = "IA"))]
72    IA,
73
74    /// 归档
75    #[cfg_attr(feature = "serde-support", serde(rename = "Archive"))]
76    Archive,
77
78    /// 冷归档
79    #[cfg_attr(feature = "serde-support", serde(rename = "ColdArchive"))]
80    ColdArchive,
81
82    /// 深度冷归档
83    #[cfg_attr(feature = "serde-support", serde(rename = "DeepColdArchive"))]
84    DeepColdArchive,
85}
86
87impl StorageClass {
88    pub fn as_str(&self) -> &str {
89        match self {
90            StorageClass::Standard => "Standard",
91            StorageClass::IA => "IA",
92            StorageClass::Archive => "Archive",
93            StorageClass::ColdArchive => "ColdArchive",
94            StorageClass::DeepColdArchive => "DeepColdArchive",
95        }
96    }
97}
98
99impl Display for StorageClass {
100    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
101        match self {
102            StorageClass::Standard => write!(f, "Standard"),
103            StorageClass::IA => write!(f, "IA"),
104            StorageClass::Archive => write!(f, "Archive"),
105            StorageClass::ColdArchive => write!(f, "ColdArchive"),
106            StorageClass::DeepColdArchive => write!(f, "DeepColdArchive"),
107        }
108    }
109}
110
111impl AsRef<str> for StorageClass {
112    fn as_ref(&self) -> &str {
113        self.as_str()
114    }
115}
116
117impl TryFrom<&str> for StorageClass {
118    type Error = crate::error::Error;
119
120    fn try_from(s: &str) -> std::result::Result<Self, Self::Error> {
121        match s {
122            "Standard" => Ok(StorageClass::Standard),
123            "IA" => Ok(StorageClass::IA),
124            "Archive" => Ok(StorageClass::Archive),
125            "ColdArchive" => Ok(StorageClass::ColdArchive),
126            "DeepColdArchive" => Ok(StorageClass::DeepColdArchive),
127            _ => Err(Error::Other(format!("Invalid StorageClass value: {}", s))),
128        }
129    }
130}
131
132impl TryFrom<String> for StorageClass {
133    type Error = crate::error::Error;
134
135    fn try_from(s: String) -> std::result::Result<Self, Self::Error> {
136        Self::try_from(s.as_str())
137    }
138}
139
140impl TryFrom<&String> for StorageClass {
141    type Error = crate::error::Error;
142
143    fn try_from(s: &String) -> std::result::Result<Self, Self::Error> {
144        Self::try_from(s.as_str())
145    }
146}
147
148#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
149#[cfg_attr(feature = "serde-support", derive(serde::Serialize, serde::Deserialize))]
150pub enum DataRedundancyType {
151    #[default]
152    #[cfg_attr(feature = "serde-support", serde(rename = "LRS"))]
153    LRS,
154
155    #[cfg_attr(feature = "serde-support", serde(rename = "ZRS"))]
156    ZRS,
157}
158
159impl DataRedundancyType {
160    pub fn as_str(&self) -> &str {
161        match self {
162            DataRedundancyType::LRS => "LRS",
163            DataRedundancyType::ZRS => "ZRS",
164        }
165    }
166}
167
168impl Display for DataRedundancyType {
169    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
170        match self {
171            DataRedundancyType::LRS => write!(f, "LRS"),
172            DataRedundancyType::ZRS => write!(f, "ZRS"),
173        }
174    }
175}
176
177impl AsRef<str> for DataRedundancyType {
178    fn as_ref(&self) -> &str {
179        self.as_str()
180    }
181}
182
183impl TryFrom<&str> for DataRedundancyType {
184    type Error = crate::error::Error;
185
186    fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
187        match value {
188            "LRS" => Ok(DataRedundancyType::LRS),
189            "ZRS" => Ok(DataRedundancyType::ZRS),
190            _ => Err(Error::Other(format!("Invalid DataRedundancyType value: {}", value))),
191        }
192    }
193}
194
195impl TryFrom<String> for DataRedundancyType {
196    type Error = crate::error::Error;
197
198    fn try_from(value: String) -> std::result::Result<Self, Self::Error> {
199        Self::try_from(value.as_str())
200    }
201}
202
203impl TryFrom<&String> for DataRedundancyType {
204    type Error = crate::error::Error;
205
206    fn try_from(value: &String) -> std::result::Result<Self, Self::Error> {
207        Self::try_from(value.as_str())
208    }
209}
210
211pub struct KvPair {
212    pub key: String,
213    pub value: String,
214}
215
216///
217/// Many aliyun ON/OFF settings are represented as strings.
218///
219/// - `Enabled`
220/// - `Disabled`
221///
222#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
223#[cfg_attr(feature = "serde-support", derive(serde::Serialize, serde::Deserialize))]
224pub enum OnOff {
225    #[cfg_attr(feature = "serde-support", serde(rename = "Enabled"))]
226    Enabled,
227
228    #[default]
229    #[cfg_attr(feature = "serde-support", serde(rename = "Disabled"))]
230    Disabled,
231}
232
233impl OnOff {
234    pub fn as_str(&self) -> &str {
235        match self {
236            OnOff::Enabled => "Enabled",
237            OnOff::Disabled => "Disabled",
238        }
239    }
240}
241
242impl AsRef<str> for OnOff {
243    fn as_ref(&self) -> &str {
244        self.as_str()
245    }
246}
247
248impl Display for OnOff {
249    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
250        write!(f, "{}", self.as_str())
251    }
252}
253
254impl TryFrom<&str> for OnOff {
255    type Error = crate::error::Error;
256
257    fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
258        match value {
259            "Enabled" => Ok(OnOff::Enabled),
260            "Disabled" => Ok(OnOff::Disabled),
261            _ => Err(Error::Other(format!("Invalid CrossRegionReplication value: {}", value))),
262        }
263    }
264}
265
266impl TryFrom<String> for OnOff {
267    type Error = crate::error::Error;
268
269    fn try_from(value: String) -> std::result::Result<Self, Self::Error> {
270        Self::try_from(value.as_str())
271    }
272}
273
274impl TryFrom<&String> for OnOff {
275    type Error = crate::error::Error;
276
277    fn try_from(value: &String) -> std::result::Result<Self, Self::Error> {
278        Self::try_from(value.as_str())
279    }
280}
281
282/// Type aliases for some On/Off types
283pub type CrossRegionReplication = OnOff;
284pub type TransferAcceleration = OnOff;
285pub type AccessMonitor = OnOff;
286
287///
288/// Versioning enumeration
289///
290#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
291#[cfg_attr(feature = "serde-support", derive(serde::Serialize, serde::Deserialize))]
292pub enum Versioning {
293    #[cfg_attr(feature = "serde-support", serde(rename = "Enabled"))]
294    Enabled,
295
296    #[default]
297    #[cfg_attr(feature = "serde-support", serde(rename = "Suspended"))]
298    Suspended,
299}
300
301impl Versioning {
302    pub fn as_str(&self) -> &str {
303        match self {
304            Versioning::Enabled => "Enabled",
305            Versioning::Suspended => "Disabled",
306        }
307    }
308}
309
310impl AsRef<str> for Versioning {
311    fn as_ref(&self) -> &str {
312        self.as_str()
313    }
314}
315
316impl Display for Versioning {
317    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
318        write!(f, "{}", self.as_str())
319    }
320}
321
322impl TryFrom<&str> for Versioning {
323    type Error = crate::error::Error;
324
325    fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
326        match value {
327            "Enabled" => Ok(Versioning::Enabled),
328            "Disabled" => Ok(Versioning::Suspended),
329            _ => Err(Error::Other(format!("Invalid Versioning value: {}", value))),
330        }
331    }
332}
333
334impl TryFrom<String> for Versioning {
335    type Error = crate::error::Error;
336
337    fn try_from(value: String) -> std::result::Result<Self, Self::Error> {
338        Self::try_from(value.as_str())
339    }
340}
341
342impl TryFrom<&String> for Versioning {
343    type Error = crate::error::Error;
344
345    fn try_from(value: &String) -> std::result::Result<Self, Self::Error> {
346        Self::try_from(value.as_str())
347    }
348}
349
350#[derive(Debug, Clone, PartialEq, Eq, Default)]
351#[cfg_attr(feature = "serde-support", derive(serde::Serialize, serde::Deserialize))]
352pub enum ServerSideEncryptionAlgorithm {
353    #[default]
354    #[cfg_attr(feature = "serde-support", serde(rename = "KMS"))]
355    KMS,
356
357    #[cfg_attr(feature = "serde-support", serde(rename = "AES256"))]
358    AES256,
359
360    #[cfg_attr(feature = "serde-support", serde(rename = "SM4"))]
361    SM4,
362}
363
364impl ServerSideEncryptionAlgorithm {
365    pub fn as_str(&self) -> &str {
366        match self {
367            ServerSideEncryptionAlgorithm::KMS => "KMS",
368            ServerSideEncryptionAlgorithm::AES256 => "AES256",
369            ServerSideEncryptionAlgorithm::SM4 => "SM4",
370        }
371    }
372}
373
374impl AsRef<str> for ServerSideEncryptionAlgorithm {
375    fn as_ref(&self) -> &str {
376        self.as_str()
377    }
378}
379
380impl Display for ServerSideEncryptionAlgorithm {
381    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
382        write!(f, "{}", self.as_str())
383    }
384}
385
386impl TryFrom<&str> for ServerSideEncryptionAlgorithm {
387    type Error = crate::error::Error;
388
389    fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
390        match value {
391            "KMS" => Ok(ServerSideEncryptionAlgorithm::KMS),
392            "AES256" => Ok(ServerSideEncryptionAlgorithm::AES256),
393            "SM4" => Ok(ServerSideEncryptionAlgorithm::SM4),
394            _ => Err(Error::Other(format!("Invalid ServerSideEncryptionAlgorithm value: {}", value))),
395        }
396    }
397}
398
399impl TryFrom<String> for ServerSideEncryptionAlgorithm {
400    type Error = crate::error::Error;
401
402    fn try_from(value: String) -> std::result::Result<Self, Self::Error> {
403        Self::try_from(value.as_str())
404    }
405}
406
407impl TryFrom<&String> for ServerSideEncryptionAlgorithm {
408    type Error = crate::error::Error;
409
410    fn try_from(value: &String) -> std::result::Result<Self, Self::Error> {
411        Self::try_from(value.as_str())
412    }
413}
414
415#[derive(Debug, Clone, Default, Eq, PartialEq)]
416#[cfg_attr(feature = "serde-support", derive(serde::Serialize, serde::Deserialize))]
417#[cfg_attr(feature = "serde-camelcase", serde(rename_all = "camelCase"))]
418pub struct ServerSideEncryptionRule {
419    pub sse_algorithm: ServerSideEncryptionAlgorithm,
420
421    /// Only present when sse_algorithm is `KMS`
422    pub kms_master_key_id: Option<String>,
423    pub kms_data_encryption: Option<String>,
424}
425
426/// Object type enumeration
427#[derive(Debug, Clone, Default, Eq, PartialEq)]
428#[cfg_attr(feature = "serde-support", derive(serde::Serialize, serde::Deserialize))]
429pub enum ObjectType {
430    /// 通过简单上传生成的 Object
431    #[default]
432    #[cfg_attr(feature = "serde-support", serde(rename = "Normal"))]
433    Normal,
434
435    /// 通过分片上传生成的 Object
436    #[cfg_attr(feature = "serde-support", serde(rename = "Multipart"))]
437    Multipart,
438
439    /// 通过追加上传生成的 Object
440    #[cfg_attr(feature = "serde-support", serde(rename = "Appendable"))]
441    Appendable,
442
443    /// 符号链接
444    #[cfg_attr(feature = "serde-support", serde(rename = "Symlink"))]
445    Symlink,
446}
447
448impl ObjectType {
449    pub fn as_str(&self) -> &str {
450        match self {
451            ObjectType::Normal => "Normal",
452            ObjectType::Multipart => "Multipart",
453            ObjectType::Appendable => "Appendable",
454            ObjectType::Symlink => "Symlink",
455        }
456    }
457}
458
459impl AsRef<str> for ObjectType {
460    fn as_ref(&self) -> &str {
461        self.as_str()
462    }
463}
464
465impl TryFrom<&str> for ObjectType {
466    type Error = crate::error::Error;
467
468    fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
469        match value {
470            "Normal" => Ok(ObjectType::Normal),
471            "Multipart" => Ok(ObjectType::Multipart),
472            "Appendable" => Ok(ObjectType::Appendable),
473            "Symlink" => Ok(ObjectType::Symlink),
474            _ => Err(Error::Other(format!("Invalid ObjectType value: {}", value))),
475        }
476    }
477}
478
479impl TryFrom<String> for ObjectType {
480    type Error = crate::error::Error;
481
482    fn try_from(value: String) -> std::result::Result<Self, Self::Error> {
483        Self::try_from(value.as_str())
484    }
485}
486
487impl TryFrom<&String> for ObjectType {
488    type Error = crate::error::Error;
489
490    fn try_from(value: &String) -> std::result::Result<Self, Self::Error> {
491        Self::try_from(value.as_str())
492    }
493}
494
495/// How to apply metadata rule while coping object
496#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)]
497#[cfg_attr(feature = "serde-support", derive(serde::Serialize, serde::Deserialize))]
498pub enum MetadataDirective {
499    /// 复制源 Object 的元数据到目标 Object。
500    /// OSS 不会复制源 Object 的 `x-oss-server-side-encryption` 属性配置到目标 Object。
501    /// 目标 Object 的服务器端加密编码方式取决于当前拷贝操作是否指定了 `x-oss-server-side-encryption`。
502    #[default]
503    #[cfg_attr(feature = "serde-support", serde(rename = "COPY"))]
504    Copy,
505
506    /// 忽略源 Object 的元数据,直接采用请求中指定的元数据
507    #[cfg_attr(feature = "serde-support", serde(rename = "REPLACE"))]
508    Replace,
509}
510
511impl MetadataDirective {
512    pub fn as_str(&self) -> &str {
513        match self {
514            MetadataDirective::Copy => "COPY",
515            MetadataDirective::Replace => "REPLACE",
516        }
517    }
518}
519
520impl AsRef<str> for MetadataDirective {
521    fn as_ref(&self) -> &str {
522        self.as_str()
523    }
524}
525
526impl Display for MetadataDirective {
527    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
528        match self {
529            MetadataDirective::Copy => write!(f, "COPY"),
530            MetadataDirective::Replace => write!(f, "REPLACE"),
531        }
532    }
533}
534
535impl TryFrom<&str> for MetadataDirective {
536    type Error = crate::error::Error;
537
538    fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
539        match value {
540            "COPY" => Ok(MetadataDirective::Copy),
541            "REPLACE" => Ok(MetadataDirective::Replace),
542            _ => Err(Error::Other(format!("Invalid MetadataDirective value: {}", value))),
543        }
544    }
545}
546
547impl TryFrom<String> for MetadataDirective {
548    type Error = crate::error::Error;
549
550    fn try_from(value: String) -> std::result::Result<Self, Self::Error> {
551        Self::try_from(value.as_str())
552    }
553}
554
555impl TryFrom<&String> for MetadataDirective {
556    type Error = crate::error::Error;
557
558    fn try_from(value: &String) -> std::result::Result<Self, Self::Error> {
559        Self::try_from(value.as_str())
560    }
561}
562
563/// How to apply taggings rule while coping object
564#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
565#[cfg_attr(feature = "serde-support", derive(serde::Serialize, serde::Deserialize))]
566pub enum TagDirective {
567    /// 复制源 Object 的标签数据到目标 Object。
568    #[default]
569    #[cfg_attr(feature = "serde-support", serde(rename = "Copy"))]
570    Copy,
571
572    /// 忽略源 Object 的对象标签,直接采用请求中指定的对象标签。
573    #[cfg_attr(feature = "serde-support", serde(rename = "Replace"))]
574    Replace,
575}
576
577impl TagDirective {
578    pub fn as_str(&self) -> &str {
579        match self {
580            TagDirective::Copy => "Copy",
581            TagDirective::Replace => "Replace",
582        }
583    }
584}
585
586impl AsRef<str> for TagDirective {
587    fn as_ref(&self) -> &str {
588        self.as_str()
589    }
590}
591
592impl Display for TagDirective {
593    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
594        match self {
595            TagDirective::Copy => write!(f, "Copy"),
596            TagDirective::Replace => write!(f, "Replace"),
597        }
598    }
599}
600
601impl TryFrom<&str> for TagDirective {
602    type Error = crate::error::Error;
603
604    fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
605        match value {
606            "Copy" => Ok(TagDirective::Copy),
607            "Replace" => Ok(TagDirective::Replace),
608            _ => Err(Error::Other(format!("Invalid MetadataDirective value: {}", value))),
609        }
610    }
611}
612
613impl TryFrom<String> for TagDirective {
614    type Error = crate::error::Error;
615
616    fn try_from(value: String) -> std::result::Result<Self, Self::Error> {
617        Self::try_from(value.as_str())
618    }
619}
620
621impl TryFrom<&String> for TagDirective {
622    type Error = crate::error::Error;
623
624    fn try_from(value: &String) -> std::result::Result<Self, Self::Error> {
625        Self::try_from(value.as_str())
626    }
627}
628
629#[derive(Debug, Clone, Default)]
630#[cfg_attr(feature = "serde-support", derive(serde::Serialize, serde::Deserialize))]
631#[cfg_attr(feature = "serde-camelcase", serde(rename_all = "camelCase"))]
632pub struct VersionIdOnlyOptions {
633    pub version_id: Option<String>,
634}
635
636/// Build tags string
637pub(crate) fn build_tag_string(tags: &HashMap<String, String>) -> String {
638    tags.iter()
639        .map(|(k, v)| {
640            if v.is_empty() {
641                urlencoding::encode(k).to_string()
642            } else {
643                format!("{}={}", urlencoding::encode(k), urlencoding::encode(v))
644            }
645        })
646        .collect::<Vec<_>>()
647        .join("&")
648}