aliyun_oss_client/
decode.rs

1//! # 解析 aliyun OSS 接口返回的 xml 原始数据的 trait
2//! 开发者可利用该 trait 将 xml 高效地转化为 rust 的 struct 或者 enum 类型
3//!
4//! 本 trait 是零拷贝的,所以可以做到很高效
5//!
6//! ## 示例
7//! ```
8//! use aliyun_oss_client::decode::{RefineObject, RefineObjectList};
9//! use thiserror::Error;
10//!
11//! struct MyFile {
12//!     key: String,
13//!     #[allow(dead_code)]
14//!     other: String,
15//! }
16//! impl RefineObject<MyError> for MyFile {
17//!
18//!     fn set_key(&mut self, key: &str) -> Result<(), MyError> {
19//!         self.key = key.to_string();
20//!         Ok(())
21//!     }
22//! }
23//!
24//! #[derive(Default)]
25//! struct MyBucket {
26//!     name: String,
27//!     files: Vec<MyFile>,
28//! }
29//!
30//! impl RefineObjectList<MyFile, MyError> for MyBucket {
31//!
32//!     fn set_name(&mut self, name: &str) -> Result<(), MyError> {
33//!         self.name = name.to_string();
34//!         Ok(())
35//!     }
36//!     fn set_list(&mut self, list: Vec<MyFile>) -> Result<(), MyError> {
37//!         self.files = list;
38//!         Ok(())
39//!     }
40//! }
41//!
42//! use aliyun_oss_client::DecodeListError;
43//!
44//! // 自定义的 Error 需要实现这个 Trait,用于内部解析方法在调用时,统一处理异常
45//! #[derive(Debug, Error, DecodeListError)]
46//! #[error("my error")]
47//! struct MyError {}
48//!
49//! fn get_with_xml() -> Result<(), aliyun_oss_client::decode::InnerListError> {
50//!     // 这是阿里云接口返回的原始数据
51//!     let xml = r#"<?xml version="1.0" encoding="UTF-8"?>
52//!         <ListBucketResult>
53//!           <Name>foo_bucket</Name>
54//!           <Prefix></Prefix>
55//!           <MaxKeys>100</MaxKeys>
56//!           <Delimiter></Delimiter>
57//!           <IsTruncated>false</IsTruncated>
58//!           <NextContinuationToken>CiphcHBzL1RhdXJpIFB1Ymxpc2ggQXBwXzAuMS42X3g2NF9lbi1VUy5tc2kQAA--</NextContinuationToken>
59//!           <Contents>
60//!             <Key>9AB932LY.jpeg</Key>
61//!             <LastModified>2022-06-26T09:53:21.000Z</LastModified>
62//!             <ETag>"F75A15996D0857B16FA31A3B16624C26"</ETag>
63//!             <Type>Normal</Type>
64//!             <Size>18027</Size>
65//!             <StorageClass>Standard</StorageClass>
66//!           </Contents>
67//!           <KeyCount>3</KeyCount>
68//!         </ListBucketResult>"#;
69//!
70//!     // 除了设置Default 外,还可以做更多设置
71//!     let mut bucket = MyBucket::default();
72//!
73//!     // 利用闭包对 MyFile 做一下初始化设置
74//!     // 可以根据传入的列表信息,为元素添加更多能力
75//!     fn init_file(_list: &mut MyBucket) -> Option<MyFile> {
76//!         Some(MyFile {
77//!             key: String::default(),
78//!             other: "abc".to_string(),
79//!         })
80//!     }
81//!
82//!     bucket.decode(xml, init_file)?;
83//!
84//!     assert!(bucket.name == "foo_bucket");
85//!     assert!(bucket.files[0].key == "9AB932LY.jpeg");
86//!
87//!     Ok(())
88//! }
89//!
90//! let res = get_with_xml();
91//!
92//! if let Err(err) = res {
93//!     eprintln!("{}", err);
94//! }
95//! ```
96
97use std::borrow::Cow;
98use std::error::Error as StdError;
99use std::fmt::Display;
100use std::num::ParseIntError;
101
102use quick_xml::{events::Event, Reader};
103
104use crate::types::InvalidEndPoint;
105#[cfg(feature = "core")]
106use crate::{
107    errors::OssError,
108    types::object::{InvalidObjectDir, InvalidObjectPath},
109};
110
111#[cfg(test)]
112mod test;
113
114const PREFIX: &[u8] = b"Prefix";
115const COMMON_PREFIX: &[u8] = b"CommonPrefixes";
116const NAME: &[u8] = b"Name";
117const MAX_KEYS: &[u8] = b"MaxKeys";
118const KEY_COUNT: &[u8] = b"KeyCount";
119const IS_TRUNCATED: &[u8] = b"IsTruncated";
120const NEXT_CONTINUATION_TOKEN: &[u8] = b"NextContinuationToken";
121const KEY: &[u8] = b"Key";
122const LAST_MODIFIED: &[u8] = b"LastModified";
123const E_TAG: &[u8] = b"ETag";
124const TYPE: &[u8] = b"Type";
125const SIZE: &[u8] = b"Size";
126const STORAGE_CLASS: &[u8] = b"StorageClass";
127const BUCKET: &[u8] = b"Bucket";
128
129const CREATION_DATE: &[u8] = b"CreationDate";
130const EXTRANET_ENDPOINT: &[u8] = b"ExtranetEndpoint";
131const INTRANET_ENDPOINT: &[u8] = b"IntranetEndpoint";
132const LOCATION: &[u8] = b"Location";
133
134const MARKER: &[u8] = b"Marker";
135const NEXT_MARKER: &[u8] = b"NextMarker";
136const ID: &[u8] = b"ID";
137const DISPLAY_NAME: &[u8] = b"DisplayName";
138const CONTENTS: &[u8] = b"Contents";
139
140const TRUE: &str = "true";
141
142/// 将一个 object 的数据写入到 rust 类型
143pub trait RefineObject<Error: StdError + 'static> {
144    /// 提取 key
145    fn set_key(&mut self, _key: &str) -> Result<(), Error> {
146        Ok(())
147    }
148
149    /// 提取最后修改时间
150    fn set_last_modified(&mut self, _last_modified: &str) -> Result<(), Error> {
151        Ok(())
152    }
153
154    /// 提取 etag
155    fn set_etag(&mut self, _etag: &str) -> Result<(), Error> {
156        Ok(())
157    }
158
159    /// 提取 type
160    fn set_type(&mut self, _type: &str) -> Result<(), Error> {
161        Ok(())
162    }
163
164    /// 提取 size
165    fn set_size(&mut self, _size: &str) -> Result<(), Error> {
166        Ok(())
167    }
168
169    /// 提取 storage_class
170    fn set_storage_class(&mut self, _storage_class: &str) -> Result<(), Error> {
171        Ok(())
172    }
173
174    /// 对单个 objcet 部分的 xml 内容进行解析
175    fn decode(&mut self, xml: &str) -> Result<(), InnerItemError> {
176        let mut reader = Reader::from_str(xml);
177        let mut buf = Vec::with_capacity(xml.len());
178        loop {
179            match reader.read_event_into(&mut buf) {
180                Ok(Event::Start(e)) => match e.name().as_ref() {
181                    KEY => self.set_key(&reader.read_text(e.to_end().name())?)?,
182                    LAST_MODIFIED => {
183                        self.set_last_modified(&reader.read_text(e.to_end().name())?)?
184                    }
185                    E_TAG => {
186                        let tag = reader.read_text(e.to_end().name())?;
187                        self.set_etag(tag.trim_matches('"'))?;
188                    }
189                    TYPE => self.set_type(&reader.read_text(e.to_end().name())?)?,
190                    SIZE => {
191                        self.set_size(&reader.read_text(e.to_end().name())?)?;
192                    }
193                    STORAGE_CLASS => {
194                        self.set_storage_class(&reader.read_text(e.to_end().name())?)?;
195                    }
196                    _ => (),
197                },
198                Ok(Event::Eof) => {
199                    break;
200                } // exits the loop when reaching end of file
201                Err(e) => {
202                    return Err(InnerItemError::from(e));
203                }
204                _ => (), //
205            }
206            buf.clear();
207        }
208        Ok(())
209    }
210}
211
212/// 将 object 列表写入到 rust 类型
213pub trait RefineObjectList<T, Error, ItemErr = Error>
214where
215    T: RefineObject<ItemErr>,
216    Error: ListError,
217    ItemErr: StdError + 'static,
218{
219    /// 提取 bucket 名
220    fn set_name(&mut self, _name: &str) -> Result<(), Error> {
221        Ok(())
222    }
223
224    /// 提取前缀
225    fn set_prefix(&mut self, _prefix: &str) -> Result<(), Error> {
226        Ok(())
227    }
228
229    /// 提取文件目录
230    fn set_common_prefix(&mut self, _list: &[Cow<'_, str>]) -> Result<(), Error> {
231        Ok(())
232    }
233
234    /// 提取 max_keys
235    fn set_max_keys(&mut self, _max_keys: &str) -> Result<(), Error> {
236        Ok(())
237    }
238
239    /// 提取 key_count
240    fn set_key_count(&mut self, _key_count: &str) -> Result<(), Error> {
241        Ok(())
242    }
243
244    /// 提取翻页信息 token
245    fn set_next_continuation_token_str(&mut self, _token: &str) -> Result<(), Error> {
246        Ok(())
247    }
248
249    /// 提取 object 列表
250    fn set_list(&mut self, _list: Vec<T>) -> Result<(), Error> {
251        Ok(())
252    }
253
254    /// 用于解析 common prefix
255    fn decode_common_prefix(&mut self, xml: &str) -> Result<(), InnerListError> {
256        let mut reader = Reader::from_str(xml);
257        let mut buf = Vec::with_capacity(xml.len());
258        let mut prefix_vec = Vec::new();
259
260        loop {
261            match reader.read_event_into(&mut buf) {
262                Ok(Event::Start(e)) => {
263                    if e.name().as_ref() == PREFIX {
264                        prefix_vec.push(reader.read_text(e.to_end().name())?);
265                    }
266                }
267                Ok(Event::Eof) => {
268                    break;
269                } // exits the loop when reaching end of file
270                Err(e) => {
271                    return Err(InnerListError::from(e));
272                }
273                _ => (), // There are several other `Event`s we do not consider here
274            }
275            buf.clear();
276        }
277        self.set_common_prefix(&prefix_vec)?;
278
279        Ok(())
280    }
281
282    /// # 由 xml 转 struct 的底层实现
283    /// - `init_object` 用于初始化 object 结构体的方法
284    fn decode<F>(&mut self, xml: &str, init_object: F) -> Result<(), InnerListError>
285    where
286        F: for<'a> Fn(&'a mut Self) -> Option<T>,
287    {
288        //println!("from_xml: {:#}", xml);
289        let mut result = Vec::new();
290        let mut reader = Reader::from_str(xml);
291        reader.trim_text(true);
292        let mut buf = Vec::with_capacity(xml.len());
293
294        loop {
295            match reader.read_event_into(&mut buf) {
296                Ok(Event::Start(e)) => {
297                    match e.name().as_ref() {
298                        COMMON_PREFIX => {
299                            self.decode_common_prefix(&reader.read_text(e.to_end().name())?)?;
300                        }
301                        PREFIX => {
302                            self.set_prefix(&reader.read_text(e.to_end().name())?)?;
303                        }
304                        NAME => self.set_name(&reader.read_text(e.to_end().name())?)?,
305                        MAX_KEYS => self.set_max_keys(&reader.read_text(e.to_end().name())?)?,
306                        KEY_COUNT => self.set_key_count(&reader.read_text(e.to_end().name())?)?,
307                        IS_TRUNCATED => {
308                            //is_truncated = reader.read_text(e.to_end().name())?.to_string() == TRUE
309                        }
310                        NEXT_CONTINUATION_TOKEN => {
311                            self.set_next_continuation_token_str(
312                                &reader.read_text(e.to_end().name())?,
313                            )?;
314                        }
315                        CONTENTS => {
316                            // <Contents></Contents> 标签内部的数据对应单个 object 信息
317                            let mut object =
318                                init_object(self).ok_or(InnerListError::init_error(true))?;
319                            object.decode(&reader.read_text(e.to_end().name())?)?;
320                            result.push(object);
321                        }
322                        _ => (),
323                    }
324                }
325                Ok(Event::Eof) => {
326                    self.set_list(result)?;
327                    break;
328                } // exits the loop when reaching end of file
329                Err(e) => {
330                    return Err(InnerListError::from(e));
331                }
332                _ => (), // There are several other `Event`s we do not consider here
333            }
334            buf.clear();
335        }
336
337        Ok(())
338    }
339}
340
341/// 将一个 bucket 的数据写入到 rust 类型
342pub trait RefineBucket<Error: StdError + 'static> {
343    /// 提取 bucket name
344    fn set_name(&mut self, _name: &str) -> Result<(), Error> {
345        Ok(())
346    }
347
348    /// 提取 bucket 创建时间
349    fn set_creation_date(&mut self, _creation_date: &str) -> Result<(), Error> {
350        Ok(())
351    }
352
353    /// 提取 location
354    fn set_location(&mut self, _location: &str) -> Result<(), Error> {
355        Ok(())
356    }
357
358    /// 提取 extranet_endpoint
359    fn set_extranet_endpoint(&mut self, _extranet_endpoint: &str) -> Result<(), Error> {
360        Ok(())
361    }
362
363    /// 提取 intranet_endpoint
364    fn set_intranet_endpoint(&mut self, _intranet_endpoint: &str) -> Result<(), Error> {
365        Ok(())
366    }
367
368    /// 提取 storage_class
369    fn set_storage_class(&mut self, _storage_class: &str) -> Result<(), Error> {
370        Ok(())
371    }
372
373    /// 解析 OSS 接口返回的 xml 数据
374    fn decode(&mut self, xml: &str) -> Result<(), InnerItemError> {
375        //println!("from_xml: {:#}", xml);
376        let mut reader = Reader::from_str(xml);
377        reader.trim_text(true);
378        let mut buf = Vec::with_capacity(xml.len());
379
380        loop {
381            match reader.read_event_into(&mut buf) {
382                Ok(Event::Start(e)) => match e.name().as_ref() {
383                    NAME => self.set_name(&reader.read_text(e.to_end().name())?)?,
384                    CREATION_DATE => {
385                        self.set_creation_date(&reader.read_text(e.to_end().name())?)?
386                    }
387                    EXTRANET_ENDPOINT => {
388                        self.set_extranet_endpoint(&reader.read_text(e.to_end().name())?)?
389                    }
390                    INTRANET_ENDPOINT => {
391                        self.set_intranet_endpoint(&reader.read_text(e.to_end().name())?)?
392                    }
393                    LOCATION => self.set_location(&reader.read_text(e.to_end().name())?)?,
394                    STORAGE_CLASS => {
395                        self.set_storage_class(&reader.read_text(e.to_end().name())?)?
396                    }
397                    _ => (),
398                },
399                Ok(Event::Eof) => {
400                    break;
401                } // exits the loop when reaching end of file
402                Err(e) => {
403                    return Err(InnerItemError::from(e));
404                }
405                _ => (), // There are several other `Event`s we do not consider here
406            }
407            buf.clear();
408        }
409        Ok(())
410    }
411}
412
413/// 将 bucket 列表的数据写入到 rust 类型
414pub trait RefineBucketList<T: RefineBucket<ItemErr>, Error, ItemErr = Error>
415where
416    Error: ListError,
417    ItemErr: StdError + 'static,
418{
419    /// 提取 prefix
420    fn set_prefix(&mut self, _prefix: &str) -> Result<(), Error> {
421        Ok(())
422    }
423
424    /// 提取 marker
425    fn set_marker(&mut self, _marker: &str) -> Result<(), Error> {
426        Ok(())
427    }
428
429    /// 提取 max_keys
430    fn set_max_keys(&mut self, _max_keys: &str) -> Result<(), Error> {
431        Ok(())
432    }
433
434    /// 提取 is_truncated
435    fn set_is_truncated(&mut self, _is_truncated: bool) -> Result<(), Error> {
436        Ok(())
437    }
438
439    /// 提取 next_marker
440    fn set_next_marker(&mut self, _next_marker: &str) -> Result<(), Error> {
441        Ok(())
442    }
443
444    /// 提取 id
445    fn set_id(&mut self, _id: &str) -> Result<(), Error> {
446        Ok(())
447    }
448
449    /// 提取 display_name
450    fn set_display_name(&mut self, _display_name: &str) -> Result<(), Error> {
451        Ok(())
452    }
453
454    /// 提取 bucket 列表
455    fn set_list(&mut self, _list: Vec<T>) -> Result<(), Error> {
456        Ok(())
457    }
458
459    /// 解析 OSS 接口返回的 xml 数据
460    fn decode<F>(&mut self, xml: &str, init_bucket: F) -> Result<(), InnerListError>
461    where
462        F: for<'a> Fn(&'a mut Self) -> Option<T>,
463    {
464        let mut result = Vec::new();
465        let mut reader = Reader::from_str(xml);
466        reader.trim_text(true);
467        let mut buf = Vec::with_capacity(xml.len());
468
469        loop {
470            match reader.read_event_into(&mut buf) {
471                Ok(Event::Start(e)) => match e.name().as_ref() {
472                    PREFIX => self.set_prefix(&reader.read_text(e.to_end().name())?)?,
473                    MARKER => self.set_marker(&reader.read_text(e.to_end().name())?)?,
474                    MAX_KEYS => self.set_max_keys(&reader.read_text(e.to_end().name())?)?,
475                    IS_TRUNCATED => {
476                        self.set_is_truncated(reader.read_text(e.to_end().name())? == TRUE)?;
477                    }
478                    NEXT_MARKER => self.set_next_marker(&reader.read_text(e.to_end().name())?)?,
479                    ID => self.set_id(&reader.read_text(e.to_end().name())?)?,
480                    DISPLAY_NAME => self.set_display_name(&reader.read_text(e.to_end().name())?)?,
481                    BUCKET => {
482                        // <Bucket></Bucket> 标签内部的数据对应单个 bucket 信息
483                        let mut bucket =
484                            init_bucket(self).ok_or(InnerListError::init_error(false))?;
485                        bucket.decode(&reader.read_text(e.to_end().name())?)?;
486                        result.push(bucket);
487                    }
488                    _ => (),
489                },
490                Ok(Event::Eof) => {
491                    self.set_list(result)?;
492                    break;
493                } // exits the loop when reaching end of file
494                Err(e) => {
495                    return Err(InnerListError::from(e));
496                }
497                _ => (), // There are several other `Event`s we do not consider here
498            }
499            buf.clear();
500        }
501        Ok(())
502    }
503}
504
505/// # Object 的 Error 中间层
506/// 当外部实现 [`RefineObject`] 时,所使用的 Error ,可先转换为这个,
507/// 变成一个已知的 Error 类型
508///
509/// [`RefineObject`]: crate::decode::RefineObject
510#[derive(Debug)]
511#[doc(hidden)]
512#[non_exhaustive]
513pub struct InnerItemError(Box<dyn StdError + 'static>);
514
515impl<T: StdError + 'static> From<T> for InnerItemError {
516    fn from(err: T) -> Self {
517        Self(Box::new(err))
518    }
519}
520
521impl Display for InnerItemError {
522    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
523        write!(fmt, "{}", self.0)
524    }
525}
526
527impl InnerItemError {
528    #[cfg(test)]
529    pub(crate) fn new() -> Self {
530        #[derive(Debug)]
531        struct MyError;
532        impl Display for MyError {
533            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
534                "demo".fmt(f)
535            }
536        }
537        impl StdError for MyError {}
538
539        Self(Box::new(MyError {}))
540    }
541
542    pub fn get_source(&self) -> Option<&(dyn StdError + 'static)> {
543        Some(self.0.as_ref())
544    }
545}
546
547/// 当外部要实现 [`RefineObjectList`] 时,Error 类需要实现此 Trait
548///
549/// [`RefineObjectList`]: crate::decode::RefineObjectList
550pub trait ListError: StdError + 'static {}
551
552impl ListError for ParseIntError {}
553
554impl ListError for InvalidEndPoint {}
555
556#[cfg(feature = "core")]
557impl ListError for InvalidObjectPath {}
558#[cfg(feature = "core")]
559impl ListError for InvalidObjectDir {}
560#[cfg(feature = "core")]
561impl ListError for chrono::ParseError {}
562#[cfg(feature = "core")]
563impl ListError for OssError {}
564
565impl<T: ListError> From<T> for InnerListError {
566    fn from(err: T) -> InnerListError {
567        Self {
568            kind: ListErrorKind::Custom(Box::new(err)),
569        }
570    }
571}
572
573/// # ObjectList 的 Error 中间层
574/// 当外部实现 [`RefineObjectList`] 时,所使用的 Error ,可先转换为这个,
575/// 变成一个已知的 Error 类型
576///
577/// [`RefineObjectList`]: crate::decode::RefineObjectList
578#[derive(Debug)]
579#[non_exhaustive]
580pub struct InnerListError {
581    kind: ListErrorKind,
582}
583
584impl Display for InnerListError {
585    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
586        use ListErrorKind::*;
587        match &self.kind {
588            Item(item) => write!(fmt, "{}", item.0),
589            Xml(xml) => write!(fmt, "{xml}"),
590            Custom(out) => write!(fmt, "{out}"),
591            InitItemFailed(is_object) => {
592                if *is_object {
593                    write!(fmt, "init_object failed")
594                } else {
595                    write!(fmt, "init_bucket failed")
596                }
597            }
598        }
599    }
600}
601
602impl InnerListError {
603    #[cfg(test)]
604    #[allow(dead_code)]
605    pub(crate) fn from_xml() -> Self {
606        Self {
607            kind: ListErrorKind::Xml(Box::new(quick_xml::Error::TextNotFound)),
608        }
609    }
610
611    // fn custom<E: StdError + 'static>(err: E) -> Self {
612    //     Self {
613    //         kind: ListErrorKind::Custom(Box::new(err)),
614    //     }
615    // }
616
617    fn init_error(is_object: bool) -> Self {
618        Self {
619            kind: ListErrorKind::InitItemFailed(is_object),
620        }
621    }
622
623    #[cfg(test)]
624    #[allow(dead_code)]
625    pub(crate) fn from_custom() -> Self {
626        #[derive(Debug)]
627        struct MyError;
628        impl Display for MyError {
629            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
630                "custom".fmt(f)
631            }
632        }
633        impl StdError for MyError {}
634        Self {
635            kind: ListErrorKind::Custom(Box::new(MyError {})),
636        }
637    }
638
639    /// 获取更详细的错误信息
640    pub fn get_source(&self) -> Option<&(dyn StdError + 'static)> {
641        use ListErrorKind::*;
642        match &self.kind {
643            Item(item) => item.get_source(),
644            Xml(xml) => Some(xml),
645            Custom(out) => Some(out.as_ref()),
646            InitItemFailed(_) => None,
647        }
648    }
649}
650
651impl From<InnerItemError> for InnerListError {
652    fn from(value: InnerItemError) -> Self {
653        Self {
654            kind: ListErrorKind::Item(value),
655        }
656    }
657}
658
659impl From<quick_xml::Error> for InnerListError {
660    fn from(value: quick_xml::Error) -> Self {
661        Self {
662            kind: ListErrorKind::Xml(Box::new(value)),
663        }
664    }
665}
666
667#[doc(hidden)]
668#[derive(Debug)]
669#[non_exhaustive]
670enum ListErrorKind {
671    #[non_exhaustive]
672    Item(InnerItemError),
673
674    #[non_exhaustive]
675    Xml(Box<quick_xml::Error>),
676
677    #[non_exhaustive]
678    Custom(Box<dyn StdError + 'static>),
679
680    InitItemFailed(bool),
681}