• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tu6ge / oss-rs / 5911409565

19 Aug 2023 12:34PM UTC coverage: 94.821% (-0.1%) from 94.939%
5911409565

push

github

tu6ge
fix(test)

7268 of 7665 relevant lines covered (94.82%)

9.46 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.47
/src/object.rs
1
//! # Object 相关功能
4✔
2
//! `ObjectList` 对应文件列表,`Object` 对应的是单个文件对象
3
//!
4
//! `ObjectList` 也可以支持自定义的类型存储单个文件对象,例如 [issue 12] 提到的,有些时候,
5
//! Oss 接口不仅返回文件路径,还会返回目录路径,可以使用如下例子进行适配
6
//!
7
//! ```rust,no_run
8
//! use aliyun_oss_client::{
9
//!     decode::RefineObject,
10
//!     object::{Objects, InitObject},
11
//!     types::object::{InvalidObjectDir, ObjectDir, ObjectPath},
12
//!     BucketName, Client,
13
//! };
14
//! use dotenv::dotenv;
15
//!
16
//! #[derive(Debug)]
17
//! enum MyObject {
18
//!     File(ObjectPath),
19
//!     Dir(ObjectDir<'static>),
20
//! }
21
//!
22
//! impl RefineObject<InvalidObjectDir> for MyObject {
23
//!     fn set_key(&mut self, key: &str) -> Result<(), InvalidObjectDir> {
24
//!         *self = match key.parse() {
25
//!             Ok(file) => MyObject::File(file),
26
//!             _ => MyObject::Dir(key.parse()?),
27
//!         };
28
//!
29
//!         Ok(())
30
//!     }
31
//! }
32
//!
33
//! type MyList = Objects<MyObject>;
34
//!
35
//! // 可以根据传入的列表信息,为元素添加更多能力
36
//! impl InitObject<MyObject> for MyList {
37
//!     fn init_object(&mut self) -> Option<MyObject> {
38
//!         Some(MyObject::File(ObjectPath::default()))
39
//!     }
40
//! }
41
//!
42
//! #[tokio::main]
43
//! async fn main() {
44
//!     dotenv().ok();
45
//!
46
//!     let client = Client::from_env().unwrap();
47
//!
48
//!     let mut list = MyList::default();
49
//!
50
//!     let _ = client.base_object_list((), &mut list).await;
51
//!     // 第二页数据
52
//!     let second = list.get_next_base().await;
53
//!
54
//!     println!("list: {:?}", list.to_vec());
55
//! }
56
//! ```
57
//! [issue 12]: https://github.com/tu6ge/oss-rs/issues/12
58

59
use crate::bucket::Bucket;
60
#[cfg(feature = "blocking")]
61
use crate::builder::RcPointer;
62
use crate::builder::{ArcPointer, BuilderError, PointerFamily};
63
use crate::client::ClientArc;
64
#[cfg(feature = "blocking")]
65
use crate::client::ClientRc;
66
use crate::config::BucketBase;
67
use crate::decode::{InnerListError, ListError, RefineObject, RefineObjectList};
68
#[cfg(feature = "blocking")]
69
use crate::file::blocking::AlignBuilder as BlockingAlignBuilder;
70
use crate::file::AlignBuilder;
71
use crate::types::core::IntoQuery;
72
use crate::types::object::ObjectPathInner;
73
use crate::types::{
74
    core::SetOssQuery,
75
    object::{
76
        CommonPrefixes, InvalidObjectDir, InvalidObjectPath, ObjectBase, ObjectDir, ObjectPath,
77
    },
78
    CanonicalizedResource, Query, CONTINUATION_TOKEN,
79
};
80
use crate::{BucketName, Client, EndPoint, KeyId, KeySecret};
81
use async_stream::try_stream;
82
use chrono::{DateTime, NaiveDateTime, Utc};
83
use futures_core::stream::Stream;
84
use http::Method;
85
use oss_derive::oss_gen_rc;
86
use url::Url;
87

88
#[cfg(feature = "blocking")]
89
use std::rc::Rc;
90
use std::{
91
    error::Error,
92
    fmt::{self, Display},
93
    num::ParseIntError,
94
    sync::Arc,
95
    vec::IntoIter,
96
};
97

98
pub mod content;
99
pub use content::Content;
100

101
#[cfg(test)]
102
mod test;
103

104
/// # 存放对象列表的结构体
105
/// before name is `ObjectList`
106
/// TODO impl core::ops::Index
107
#[derive(Clone)]
108
#[non_exhaustive]
109
pub struct ObjectList<P: PointerFamily = ArcPointer, Item = Object<P>> {
110
    pub(crate) bucket: BucketBase,
111
    prefix: Option<ObjectDir<'static>>,
112
    max_keys: u32,
113
    key_count: u64,
114
    /// 存放单个文件对象的 Vec 集合
115
    object_list: Vec<Item>,
116
    next_continuation_token: String,
117
    common_prefixes: CommonPrefixes,
118
    client: P::PointerType,
119
    search_query: Query,
120
}
121

122
/// sync ObjectList alias
123
pub type Objects<Item = Object<ArcPointer>> = ObjectList<ArcPointer, Item>;
124
/// blocking ObjectList alias
125
#[cfg(feature = "blocking")]
126
pub type ObjectsBlocking<Item = Object<RcPointer>> = ObjectList<RcPointer, Item>;
127

128
/// 存放单个对象的结构体
129
#[derive(Clone, Debug)]
130
#[non_exhaustive]
131
pub struct Object<PointerSel: PointerFamily = ArcPointer> {
132
    pub(crate) base: ObjectBase<PointerSel>,
133
    last_modified: DateTime<Utc>,
134
    etag: String,
135
    _type: String,
136
    size: u64,
137
    storage_class: StorageClass,
138
}
139

140
/// 异步的 Object struct
141
pub type ObjectArc = Object<ArcPointer>;
142

143
impl<T: PointerFamily, Item> fmt::Debug for ObjectList<T, Item> {
144
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1✔
145
        f.debug_struct("ObjectList")
7✔
146
            .field("bucket", &self.bucket)
1✔
147
            .field("prefix", &self.prefix)
148
            .field("max_keys", &self.max_keys)
1✔
149
            .field("key_count", &self.key_count)
1✔
150
            .field("next_continuation_token", &self.next_continuation_token)
1✔
151
            .field("common_prefixes", &self.common_prefixes)
1✔
152
            .field("search_query", &self.search_query)
1✔
153
            .finish()
154
    }
1✔
155
}
156

157
impl<P: PointerFamily, Item> Default for ObjectList<P, Item> {
158
    fn default() -> Self {
17✔
159
        Self {
17✔
160
            bucket: BucketBase::default(),
17✔
161
            prefix: Option::default(),
17✔
162
            max_keys: u32::default(),
17✔
163
            key_count: u64::default(),
17✔
164
            object_list: Vec::new(),
17✔
165
            next_continuation_token: String::default(),
17✔
166
            common_prefixes: CommonPrefixes::default(),
17✔
167
            client: P::PointerType::default(),
17✔
168
            search_query: Query::default(),
17✔
169
            //init_fn: Box::default(),
170
        }
171
    }
17✔
172
}
173

174
impl<T: PointerFamily, Item> AsMut<Query> for ObjectList<T, Item> {
175
    fn as_mut(&mut self) -> &mut Query {
176
        &mut self.search_query
177
    }
178
}
179

180
impl<T: PointerFamily, Item> AsRef<BucketBase> for ObjectList<T, Item> {
181
    fn as_ref(&self) -> &BucketBase {
182
        &self.bucket
183
    }
184
}
185

186
impl<T: PointerFamily, Item> AsRef<BucketName> for ObjectList<T, Item> {
187
    fn as_ref(&self) -> &BucketName {
188
        self.bucket.as_ref()
189
    }
190
}
191

192
impl<T: PointerFamily, Item> AsRef<EndPoint> for ObjectList<T, Item> {
193
    fn as_ref(&self) -> &EndPoint {
194
        self.bucket.as_ref()
195
    }
196
}
197

198
impl<T: PointerFamily, Item> ObjectList<T, Item> {
199
    /// 文件列表的初始化方法
200
    #[allow(clippy::too_many_arguments)]
201
    pub fn new<Q: IntoQuery>(
8✔
202
        bucket: BucketBase,
203
        prefix: Option<ObjectDir<'static>>,
204
        max_keys: u32,
205
        key_count: u64,
206
        object_list: Vec<Item>,
207
        next_continuation_token: Option<String>,
208
        client: T::PointerType,
209
        search_query: Q,
210
    ) -> Self {
211
        Self {
8✔
212
            bucket,
213
            prefix,
214
            max_keys,
215
            key_count,
216
            object_list,
217
            next_continuation_token: next_continuation_token.unwrap_or_default(),
8✔
218
            common_prefixes: CommonPrefixes::default(),
8✔
219
            client,
220
            search_query: search_query.into_query(),
8✔
221
            //init_fn: Box::default(),
222
        }
223
    }
8✔
224

225
    /// 返回 bucket 元信息的引用
226
    pub fn bucket(&self) -> &BucketBase {
11✔
227
        &self.bucket
11✔
228
    }
11✔
229

230
    /// 返回 prefix 的引用
231
    pub fn prefix(&self) -> &Option<ObjectDir<'static>> {
6✔
232
        &self.prefix
233
    }
6✔
234

235
    /// 获取文件夹下的子文件夹名,子文件夹下递归的所有文件和文件夹不包含在这里。
236
    pub fn common_prefixes(&self) -> &CommonPrefixes {
7✔
237
        &self.common_prefixes
7✔
238
    }
7✔
239

240
    /// 设置 common_prefixes 信息
241
    pub fn set_common_prefixes<P: IntoIterator<Item = ObjectDir<'static>>>(&mut self, prefixes: P) {
1✔
242
        self.common_prefixes = CommonPrefixes::from_iter(prefixes);
1✔
243
    }
1✔
244

245
    /// 返回 max_keys
246
    pub fn max_keys(&self) -> &u32 {
7✔
247
        &self.max_keys
7✔
248
    }
7✔
249

250
    /// 返回 key_count
251
    pub fn key_count(&self) -> &u64 {
5✔
252
        &self.key_count
5✔
253
    }
5✔
254

255
    /// # 返回下一个 continuation_token
256
    /// 用于翻页使用
257
    pub fn next_continuation_token_str(&self) -> &String {
7✔
258
        &self.next_continuation_token
7✔
259
    }
7✔
260

261
    /// 返回查询条件
262
    pub fn search_query(&self) -> &Query {
5✔
263
        &self.search_query
5✔
264
    }
5✔
265

266
    /// # 下一页的查询条件
267
    ///
268
    /// 如果有下一页,返回 Some(Query)
269
    /// 如果没有下一页,则返回 None
270
    pub fn next_query(&self) -> Option<Query> {
2✔
271
        if !self.next_continuation_token.is_empty() {
2✔
272
            let mut search_query = self.search_query.clone();
1✔
273
            search_query.insert(CONTINUATION_TOKEN, self.next_continuation_token.to_owned());
1✔
274
            Some(search_query)
1✔
275
        } else {
276
            None
1✔
277
        }
278
    }
2✔
279

280
    /// 将 object 列表转化为迭代器
281
    pub fn object_iter(self) -> IntoIter<Item> {
1✔
282
        self.object_list.into_iter()
1✔
283
    }
1✔
284
}
285

286
#[oss_gen_rc]
4✔
287
impl<Item> ObjectList<ArcPointer, Item> {
288
    /// 设置 Client
289
    pub(crate) fn set_client(&mut self, client: Arc<ClientArc>) {
4✔
290
        self.client = client;
4✔
291
    }
4✔
292

293
    pub(crate) fn from_bucket(
4✔
294
        bucket: &Bucket<ArcPointer>,
295
        capacity: usize,
296
    ) -> ObjectList<ArcPointer> {
297
        ObjectList::<ArcPointer> {
4✔
298
            bucket: bucket.base.clone(),
4✔
299
            client: Arc::clone(&bucket.client),
3✔
300
            object_list: Vec::with_capacity(capacity),
4✔
301
            ..Default::default()
4✔
302
        }
303
    }
4✔
304

305
    /// 获取 Client 引用
306
    pub(crate) fn client(&self) -> Arc<ClientArc> {
3✔
307
        Arc::clone(&self.client)
3✔
308
    }
3✔
309

310
    fn clone_base(&self) -> Self {
1✔
311
        Self {
1✔
312
            client: Arc::clone(&self.client),
1✔
313
            bucket: self.bucket.clone(),
1✔
314
            search_query: self.search_query.clone(),
1✔
315
            max_keys: self.max_keys,
1✔
316
            object_list: Vec::with_capacity(self.max_keys as usize),
1✔
317
            ..Default::default()
1✔
318
        }
319
    }
1✔
320
}
321

322
/// # 初始化 object 项目的接口
323
///
324
/// 根据 object 列表类型初始化一个 object 数据
325
///
326
/// 当对 OSS xml 数据进行解析时,每解析一个 object 时,
327
/// 会先调用此 trait 中的 init_object 初始化 object 类型,再解析 xml 数据
328
///
329
/// Target 为 object 的具体类型
330
pub trait InitObject<Target> {
331
    /// 初始化 object 的类型
332
    ///
333
    /// 当返回 None 时,解析 OSS xml 数据时,会抛出 "init_object failed" 错误
334
    fn init_object(&mut self) -> Option<Target>;
335
}
336

337
impl InitObject<Object<ArcPointer>> for ObjectList<ArcPointer, Object<ArcPointer>> {
338
    fn init_object(&mut self) -> Option<Object<ArcPointer>> {
4✔
339
        Some(Object::from_bucket(Arc::new(self.bucket.clone())))
4✔
340
    }
4✔
341
}
342

343
#[cfg(feature = "blocking")]
344
impl InitObject<Object<RcPointer>> for ObjectList<RcPointer, Object<RcPointer>> {
345
    fn init_object(&mut self) -> Option<Object<RcPointer>> {
3✔
346
        Some(Object::<RcPointer>::from_bucket(Rc::new(
3✔
347
            self.bucket.clone(),
3✔
348
        )))
349
    }
3✔
350
}
351

352
impl ObjectList<ArcPointer> {
353
    /// 异步获取下一页的数据
354
    /// TODO 改为 unstable
355
    pub async fn get_next_list(&self) -> Result<ObjectList<ArcPointer>, ExtractListError> {
×
356
        match self.next_query() {
357
            None => Err(ExtractListError {
358
                kind: ExtractListErrorKind::NoMoreFile,
359
            }),
360
            Some(query) => {
361
                let mut url = self.bucket.to_url();
362
                url.set_oss_query(&query);
363

364
                let canonicalized = CanonicalizedResource::from_bucket_query(&self.bucket, &query);
365

366
                let response = self
367
                    .builder(Method::GET, url, canonicalized)?
368
                    .send_adjust_error()
369
                    .await?;
370

371
                let mut list = ObjectList::<ArcPointer> {
372
                    client: self.client(),
373
                    bucket: self.bucket.clone(),
374
                    object_list: Vec::with_capacity(query.get_max_keys()),
375
                    ..Default::default()
376
                };
377

378
                list.decode(&response.text().await?, Self::init_object)?;
379

380
                list.set_search_query(query);
381
                Ok(list)
382
            }
383
        }
384
    }
×
385

386
    /// # 将 object_list 转化为 stream, 返回第二页,第三页... 的内容
387
    ///
388
    /// *不够完善,最后一次迭代返回的是 `Some(Err(OssError::WithoutMore))`,而不是 `None`*
389
    ///
390
    /// ## 用法
391
    ///
392
    /// 1. 添加依赖
393
    /// ```toml
394
    /// [dependencies]
395
    /// futures="0.3"
396
    /// ```
397
    /// 2. 将返回结果 pin 住
398
    /// ```no_run
399
    /// # use dotenv::dotenv;
400
    /// # use aliyun_oss_client::Client;
401
    /// # #[tokio::main]
402
    /// # async fn main() {
403
    /// # dotenv().ok();
404
    /// use futures::{pin_mut, StreamExt};
405
    /// # let client = Client::from_env().unwrap();
406
    /// # let query = [("max-keys", 100u8)];
407
    /// # let object_list = client.get_object_list(query).await.unwrap();
408
    /// let stream = object_list.into_stream();
409
    /// pin_mut!(stream);
410
    ///
411
    /// let second_list = stream.next().await;
412
    /// let third_list = stream.next().await;
413
    /// println!("second_list: {:?}", second_list);
414
    /// println!("third_list: {:?}", third_list);
415
    /// # }
416
    /// ```
417
    pub fn into_stream(self) -> impl Stream<Item = Result<Self, ExtractListError>> {
×
418
        try_stream! {
×
419
            let result = self.get_next_list().await?;
420
            yield result;
421
        }
422
    }
×
423
}
424

425
impl<Item> ObjectList<ArcPointer, Item>
426
where
427
    Self: InitObject<Item>,
428
{
429
    /// # 自定义 Item 时,获取下一页数据
430
    /// 当没有下一页查询条件时 返回 `None`
431
    /// 否则尝试获取下一页数据,成功返回 `Some(Ok(_))`, 失败返回 `Some(Err(_))`
432
    pub async fn get_next_base<E>(&mut self) -> Option<Result<Self, ExtractListError>>
433
    where
434
        Item: RefineObject<E>,
435
        E: Error + 'static,
436
    {
437
        match self.next_query() {
438
            None => None,
439
            Some(query) => {
440
                let mut list = self.clone_base();
441
                list.search_query = query.clone();
442
                let res = self.client().base_object_list(query, &mut list).await;
443
                Some(res.map(|_| list))
444
            }
445
        }
446
    }
447
}
448

449
#[cfg(feature = "blocking")]
450
impl ObjectList<RcPointer> {
451
    /// 从 OSS 获取 object 列表信息
452
    pub fn get_object_list(&self) -> Result<Self, ExtractListError> {
1✔
453
        let mut list = ObjectList::<RcPointer>::clone_base(self);
1✔
454

455
        let (bucket_url, resource) = self.bucket.get_url_resource(&self.search_query);
1✔
456

457
        let response = self
1✔
458
            .builder(Method::GET, bucket_url, resource)?
1✔
459
            .send_adjust_error()?;
×
460

461
        list.decode(&response.text()?, ObjectList::<RcPointer>::init_object)
1✔
462
            .map_err(ExtractListError::from)?;
1✔
463

464
        Ok(list)
1✔
465
    }
1✔
466
}
467

468
impl<T: PointerFamily, Item> ObjectList<T, Item> {
469
    /// 设置查询条件
470
    #[inline]
471
    pub fn set_search_query(&mut self, search_query: Query) {
4✔
472
        self.search_query = search_query;
4✔
473
    }
4✔
474

475
    /// 设置 bucket 元信息
476
    pub fn set_bucket(&mut self, bucket: BucketBase) {
477
        self.bucket = bucket;
478
    }
479

480
    /// 获取 bucket 名称
481
    pub fn bucket_name(&self) -> &str {
1✔
482
        self.bucket.name()
1✔
483
    }
1✔
484

485
    /// 返回 object 的 Vec 集合
486
    pub fn to_vec(self) -> Vec<Item> {
487
        self.object_list
488
    }
489

490
    /// 返回文件数量
491
    pub fn len(&self) -> usize {
492
        self.object_list.len()
493
    }
494

495
    /// 返回是否存在文件
496
    pub fn is_empty(&self) -> bool {
497
        self.object_list.is_empty()
498
    }
499
}
500

501
impl<T: PointerFamily> Default for Object<T> {
502
    fn default() -> Self {
20✔
503
        Object {
20✔
504
            base: ObjectBase::<T>::default(),
20✔
505
            last_modified: DateTime::<Utc>::from_utc(
20✔
506
                #[allow(clippy::unwrap_used)]
507
                NaiveDateTime::from_timestamp_opt(0, 0).unwrap(),
20✔
508
                Utc,
509
            ),
510
            etag: String::default(),
20✔
511
            _type: String::default(),
20✔
512
            size: 0,
513
            storage_class: StorageClass::default(),
20✔
514
        }
515
    }
20✔
516
}
517

518
impl<T: PointerFamily> AsRef<ObjectPath> for Object<T> {
519
    fn as_ref(&self) -> &ObjectPath {
1✔
520
        self.base.as_ref()
1✔
521
    }
1✔
522
}
523

524
impl<T: PointerFamily> AsRef<DateTime<Utc>> for Object<T> {
525
    fn as_ref(&self) -> &DateTime<Utc> {
526
        &self.last_modified
527
    }
528
}
529

530
impl<T: PointerFamily> AsRef<StorageClass> for Object<T> {
531
    fn as_ref(&self) -> &StorageClass {
532
        &self.storage_class
533
    }
534
}
535

536
impl<T: PointerFamily> Object<T> {
537
    /// 初始化 Object 结构体
538
    pub fn new(
12✔
539
        bucket: T::Bucket,
540
        path: ObjectPath,
541
        last_modified: DateTime<Utc>,
542
        etag: String,
543
        _type: String,
544
        size: u64,
545
        storage_class: StorageClass,
546
    ) -> Self {
547
        let base = ObjectBase::<T>::new2(bucket, path);
12✔
548
        Self {
12✔
549
            base,
12✔
550
            last_modified,
551
            etag,
552
            _type,
553
            size,
554
            storage_class,
555
        }
556
    }
12✔
557

558
    pub(crate) fn from_bucket(bucket: T::Bucket) -> Self {
8✔
559
        Self {
8✔
560
            base: ObjectBase::<T>::init_with_bucket(bucket),
8✔
561
            ..Default::default()
8✔
562
        }
563
    }
8✔
564

565
    /// 读取 Object 元信息
566
    #[inline]
567
    pub fn base(&self) -> &ObjectBase<T> {
568
        &self.base
569
    }
570

571
    /// 设置 Object 元信息
572
    #[inline]
573
    pub fn set_base(&mut self, base: ObjectBase<T>) {
1✔
574
        self.base = base;
1✔
575
    }
1✔
576

577
    /// 读取最后修改时间
578
    #[inline]
579
    pub fn last_modified(&self) -> &DateTime<Utc> {
580
        &self.last_modified
581
    }
582

583
    /// 设置最后修改时间
584
    #[inline]
585
    pub fn set_last_modified(&mut self, last_modified: DateTime<Utc>) {
586
        self.last_modified = last_modified;
587
    }
588

589
    /// 读取 etag 信息
590
    #[inline]
591
    pub fn etag(&self) -> &String {
592
        &self.etag
593
    }
594

595
    /// 设置 etag
596
    #[inline]
597
    pub fn set_etag(&mut self, etag: String) {
598
        self.etag = etag
599
    }
600

601
    /// 读取 type
602
    #[inline]
603
    pub fn get_type_string(&self) -> &String {
604
        &self._type
605
    }
606

607
    /// 设置 type
608
    #[inline]
609
    pub fn set_type_string(&mut self, _type: String) {
610
        self._type = _type;
611
    }
612

613
    /// 读取文件 size
614
    #[inline]
615
    pub fn size(&self) -> u64 {
616
        self.size
617
    }
618

619
    /// 设置文件 size
620
    #[inline]
621
    pub fn set_size(&mut self, size: u64) {
622
        self.size = size;
623
    }
624

625
    /// 读取 storage_class
626
    #[inline]
627
    pub fn storage_class(&self) -> &StorageClass {
628
        &self.storage_class
629
    }
630

631
    /// 设置 storage_class
632
    #[inline]
633
    pub fn set_storage_class(&mut self, storage_class: StorageClass) {
634
        self.storage_class = storage_class;
635
    }
636

637
    /// 获取一部分数据
638
    pub fn pieces(
639
        self,
640
    ) -> (
641
        ObjectBase<T>,
642
        DateTime<Utc>,
643
        String,
644
        String,
645
        u64,
646
        StorageClass,
647
    ) {
648
        (
649
            self.base,
650
            self.last_modified,
651
            self.etag,
652
            self._type,
653
            self.size,
654
            self.storage_class,
655
        )
656
    }
657

658
    /// 读取 文件路径
659
    pub fn path(&self) -> ObjectPath {
660
        self.base.path()
661
    }
662

663
    #[doc(hidden)]
664
    pub fn path_string(&self) -> String {
665
        self.base.path().to_string()
666
    }
667
}
668

669
impl Object<ArcPointer> {
670
    #[cfg(test)]
671
    pub fn test_path(path: &'static str) -> Self {
1✔
672
        let mut object = Self::default();
1✔
673
        object.set_base(ObjectBase::<ArcPointer>::new2(
1✔
674
            Arc::new(BucketBase::default()),
1✔
675
            path.try_into().unwrap(),
1✔
676
        ));
677
        object
678
    }
1✔
679
}
680

681
impl<T: PointerFamily> From<Object<T>> for ObjectPathInner<'static> {
682
    #[inline]
683
    fn from(obj: Object<T>) -> Self {
684
        obj.base.path
685
    }
686
}
687

688
#[oss_gen_rc]
×
689
impl Object<ArcPointer> {
690
    /// # Object 构建器
691
    /// 用例
692
    /// ```
693
    /// # use aliyun_oss_client::{config::BucketBase, ObjectPath, object::{ObjectArc, StorageClass},EndPoint};
694
    /// # use chrono::{DateTime, NaiveDateTime, Utc};
695
    /// let bucket = BucketBase::new(
696
    ///     "bucket-name".parse().unwrap(),
697
    ///     EndPoint::CN_QINGDAO,
698
    /// );
699
    /// let mut builder = ObjectArc::builder("abc".parse::<ObjectPath>().unwrap());
700
    ///
701
    /// builder
702
    ///     .bucket_base(bucket)
703
    ///     .last_modified(DateTime::<Utc>::from_utc(
704
    ///         NaiveDateTime::from_timestamp_opt(123000, 0).unwrap(),
705
    ///         Utc,
706
    ///     ))
707
    ///     .etag("foo1".to_owned())
708
    ///     .set_type("foo2".to_owned())
709
    ///     .size(123)
710
    ///     .storage_class(StorageClass::IA);
711
    ///
712
    /// let object = builder.build();
713
    /// ```
714
    pub fn builder(path: ObjectPath) -> ObjectBuilder<ArcPointer> {
5✔
715
        ObjectBuilder::<ArcPointer>::new(Arc::default(), path)
5✔
716
    }
5✔
717

718
    /// 带签名的 Url 链接
719
    pub fn to_sign_url(&self, key: &KeyId, secret: &KeySecret, expires: i64) -> Url {
1✔
720
        self.base.to_sign_url(key, secret, expires)
1✔
721
    }
1✔
722
}
723

724
/// Object 结构体的构建器
725
pub struct ObjectBuilder<T: PointerFamily = ArcPointer> {
726
    object: Object<T>,
727
}
728

729
impl<T: PointerFamily> ObjectBuilder<T> {
730
    /// 初始化 Object 构建器
731
    pub fn new(bucket: T::Bucket, path: ObjectPath) -> Self {
5✔
732
        let base = ObjectBase::<T>::new2(bucket, path);
5✔
733
        Self {
5✔
734
            object: Object {
5✔
735
                base,
5✔
736
                last_modified: DateTime::<Utc>::from_utc(
5✔
737
                    #[allow(clippy::unwrap_used)]
738
                    NaiveDateTime::from_timestamp_opt(0, 0).unwrap(),
5✔
739
                    Utc,
740
                ),
741
                ..Default::default()
5✔
742
            },
743
        }
744
    }
5✔
745

746
    /// 设置元信息
747
    pub fn bucket(&mut self, bucket: T::Bucket) -> &mut Self {
1✔
748
        self.object.base.set_bucket(bucket);
1✔
749
        self
750
    }
1✔
751

752
    /// 设置 last_modified
753
    pub fn last_modified(&mut self, date: DateTime<Utc>) -> &mut Self {
1✔
754
        self.object.last_modified = date;
1✔
755
        self
756
    }
1✔
757

758
    /// 设置 etag
759
    pub fn etag(&mut self, etag: String) -> &mut Self {
1✔
760
        self.object.etag = etag;
1✔
761
        self
762
    }
1✔
763

764
    /// 设置 type
765
    pub fn set_type(&mut self, _type: String) -> &mut Self {
1✔
766
        self.object._type = _type;
1✔
767
        self
768
    }
1✔
769

770
    /// 设置 size
771
    pub fn size(&mut self, size: u64) -> &mut Self {
1✔
772
        self.object.size = size;
1✔
773
        self
774
    }
1✔
775

776
    /// 设置 storage_class
777
    pub fn storage_class(&mut self, storage_class: StorageClass) -> &mut Self {
1✔
778
        self.object.storage_class = storage_class;
1✔
779
        self
780
    }
1✔
781

782
    /// 返回 object
783
    pub fn build(self) -> Object<T> {
3✔
784
        self.object
3✔
785
    }
3✔
786
}
787

788
#[oss_gen_rc]
×
789
impl ObjectBuilder<ArcPointer> {
790
    /// 设置元信息
791
    pub fn bucket_base(&mut self, base: BucketBase) -> &mut Self {
4✔
792
        self.object.base.set_bucket(Arc::new(base));
4✔
793
        self
794
    }
4✔
795
}
796

797
impl<T: PointerFamily> RefineObject<BuildInItemError> for Object<T> {
798
    #[inline]
799
    fn set_key(&mut self, key: &str) -> Result<(), BuildInItemError> {
8✔
800
        self.base
24✔
801
            .set_path(key.to_owned())
8✔
802
            .map_err(|e| BuildInItemError {
10✔
803
                source: key.to_string(),
1✔
804
                kind: BuildInItemErrorKind::BasePath(e),
1✔
805
            })
1✔
806
    }
8✔
807

808
    #[inline]
809
    fn set_last_modified(&mut self, value: &str) -> Result<(), BuildInItemError> {
8✔
810
        self.last_modified = value.parse().map_err(|e| BuildInItemError {
10✔
811
            source: value.to_string(),
1✔
812
            kind: BuildInItemErrorKind::LastModified(e),
1✔
813
        })?;
2✔
814
        Ok(())
7✔
815
    }
8✔
816

817
    #[inline]
818
    fn set_etag(&mut self, value: &str) -> Result<(), BuildInItemError> {
7✔
819
        self.etag = value.to_string();
7✔
820
        Ok(())
7✔
821
    }
7✔
822

823
    #[inline]
824
    fn set_type(&mut self, value: &str) -> Result<(), BuildInItemError> {
7✔
825
        self._type = value.to_string();
7✔
826
        Ok(())
7✔
827
    }
7✔
828

829
    #[inline]
830
    fn set_size(&mut self, size: &str) -> Result<(), BuildInItemError> {
8✔
831
        self.size = size.parse().map_err(|e| BuildInItemError {
12✔
832
            source: size.to_string(),
2✔
833
            kind: BuildInItemErrorKind::Size(e),
2✔
834
        })?;
4✔
835
        Ok(())
6✔
836
    }
8✔
837

838
    #[inline]
839
    fn set_storage_class(&mut self, storage_class: &str) -> Result<(), BuildInItemError> {
8✔
840
        self.storage_class = StorageClass::new(storage_class).ok_or(BuildInItemError {
16✔
841
            source: storage_class.to_string(),
8✔
842
            kind: BuildInItemErrorKind::InvalidStorageClass,
8✔
843
        })?;
1✔
844
        Ok(())
7✔
845
    }
8✔
846
}
847

848
/// Xml 转化为内置 Object 时的错误集合
849
#[derive(Debug)]
10✔
850
#[non_exhaustive]
851
pub struct BuildInItemError {
852
    source: String,
853
    kind: BuildInItemErrorKind,
5✔
854
}
855

856
impl BuildInItemError {
857
    #[cfg(test)]
858
    pub(crate) fn test_new() -> Self {
2✔
859
        Self {
2✔
860
            source: "foo".to_string(),
2✔
861
            kind: BuildInItemErrorKind::InvalidStorageClass,
2✔
862
        }
863
    }
2✔
864

865
    pub(crate) fn new<K: Into<BuildInItemErrorKind>>(kind: K, source: &str) -> Self {
866
        Self {
867
            source: source.to_owned(),
868
            kind: kind.into(),
869
        }
870
    }
871
}
872

873
impl Display for BuildInItemError {
874
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
6✔
875
        use BuildInItemErrorKind::*;
876
        let kind = match &self.kind {
6✔
877
            Size(_) => "size",
2✔
878
            BasePath(_) => "base-path",
1✔
879
            LastModified(_) => "last-modified",
1✔
880
            InvalidStorageClass => "storage-class",
2✔
881
        };
882
        write!(f, "parse {kind} failed, gived str: {}", self.source)
6✔
883
    }
6✔
884
}
885

886
impl Error for BuildInItemError {
887
    fn source(&self) -> Option<&(dyn Error + 'static)> {
4✔
888
        use BuildInItemErrorKind::*;
889
        match &self.kind {
4✔
890
            Size(e) => Some(e),
1✔
891
            BasePath(e) => Some(e),
1✔
892
            LastModified(e) => Some(e),
1✔
893
            InvalidStorageClass => None,
1✔
894
        }
895
    }
4✔
896
}
897

898
/// Xml 转化为内置 Object 时的错误集合
899
#[derive(Debug)]
5✔
900
#[non_exhaustive]
901
pub(crate) enum BuildInItemErrorKind {
902
    /// 转换数字类型的错误
903
    Size(ParseIntError),
1✔
904

905
    /// 转换为 ObjectPath 时的错误
906
    BasePath(InvalidObjectPath),
1✔
907

908
    /// 转换日期格式的错误
909
    LastModified(chrono::ParseError),
1✔
910

911
    // /// 接收 Xml 转换时的错误
912
    // Xml(quick_xml::Error),
913
    /// 非法的 StorageClass
914
    InvalidStorageClass,
915
}
916

917
impl From<InvalidObjectPath> for BuildInItemErrorKind {
918
    fn from(value: InvalidObjectPath) -> Self {
×
919
        Self::BasePath(value)
×
920
    }
×
921
}
922

923
impl<P: PointerFamily, Item: RefineObject<E>, E: Error + 'static>
924
    RefineObjectList<Item, ObjectListError, E> for ObjectList<P, Item>
925
{
926
    #[inline]
927
    fn set_key_count(&mut self, key_count: &str) -> Result<(), ObjectListError> {
7✔
928
        self.key_count = key_count.parse().map_err(|e| ObjectListError {
11✔
929
            source: key_count.to_owned(),
2✔
930
            kind: ObjectListErrorKind::KeyCount(e),
2✔
931
        })?;
4✔
932
        Ok(())
5✔
933
    }
7✔
934

935
    #[inline]
936
    fn set_prefix(&mut self, prefix: &str) -> Result<(), ObjectListError> {
9✔
937
        if prefix.is_empty() {
9✔
938
            self.prefix = None;
7✔
939
        } else {
940
            let mut string = String::from(prefix);
2✔
941
            string += "/";
2✔
942
            self.prefix = Some(string.parse().map_err(|e| ObjectListError {
4✔
943
                source: prefix.to_owned(),
1✔
944
                kind: ObjectListErrorKind::Prefix(e),
1✔
945
            })?)
2✔
946
        }
2✔
947
        Ok(())
8✔
948
    }
9✔
949

950
    #[inline]
951
    fn set_common_prefix(
2✔
952
        &mut self,
953
        list: &[std::borrow::Cow<'_, str>],
954
    ) -> Result<(), ObjectListError> {
955
        self.common_prefixes = Vec::with_capacity(list.len());
2✔
956
        for val in list.iter() {
2✔
957
            self.common_prefixes
1✔
958
                .push(val.parse().map_err(|e| ObjectListError {
3✔
959
                    source: val.to_string(),
1✔
960
                    kind: ObjectListErrorKind::CommonPrefix(e),
1✔
961
                })?);
2✔
962
        }
963
        Ok(())
1✔
964
    }
2✔
965

966
    #[inline]
967
    fn set_max_keys(&mut self, max_keys: &str) -> Result<(), ObjectListError> {
9✔
968
        self.max_keys = max_keys.parse().map_err(|e| ObjectListError {
13✔
969
            source: max_keys.to_string(),
2✔
970
            kind: ObjectListErrorKind::MaxKeys(e),
2✔
971
        })?;
4✔
972
        Ok(())
7✔
973
    }
9✔
974

975
    #[inline]
976
    fn set_next_continuation_token_str(&mut self, token: &str) -> Result<(), ObjectListError> {
1✔
977
        self.next_continuation_token = token.to_owned();
1✔
978
        Ok(())
1✔
979
    }
1✔
980

981
    #[inline]
982
    fn set_list(&mut self, list: Vec<Item>) -> Result<(), ObjectListError> {
5✔
983
        self.object_list = list;
5✔
984
        Ok(())
5✔
985
    }
5✔
986
}
987

988
/// decode xml to object list error collection
989
#[derive(Debug)]
10✔
990
#[non_exhaustive]
991
pub struct ObjectListError {
992
    source: String,
993
    kind: ObjectListErrorKind,
5✔
994
}
995

996
impl ObjectListError {
997
    #[cfg(test)]
998
    pub(crate) fn test_new() -> Self {
1✔
999
        Self {
1✔
1000
            source: "foo".to_string(),
1✔
1001
            kind: ObjectListErrorKind::Bar,
1✔
1002
        }
1003
    }
1✔
1004
}
1005

1006
impl Display for ObjectListError {
1007
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
7✔
1008
        use ObjectListErrorKind::*;
1009
        let kind: &str = match &self.kind {
7✔
1010
            KeyCount(_) => "key-count",
2✔
1011
            Prefix(_) => "prefix",
1✔
1012
            CommonPrefix(_) => "common-prefix",
1✔
1013
            MaxKeys(_) => "max-keys",
2✔
1014
            #[cfg(test)]
1015
            Bar => "bar",
1✔
1016
        };
1017
        write!(f, "parse {kind} failed, gived str: {}", self.source)
7✔
1018
    }
7✔
1019
}
1020

1021
impl Error for ObjectListError {
1022
    fn source(&self) -> Option<&(dyn Error + 'static)> {
4✔
1023
        use ObjectListErrorKind::*;
1024
        match &self.kind {
4✔
1025
            KeyCount(e) | MaxKeys(e) => Some(e),
2✔
1026
            Prefix(e) | CommonPrefix(e) => Some(e),
2✔
1027
            #[cfg(test)]
1028
            Bar => None,
×
1029
        }
1030
    }
4✔
1031
}
1032

1033
impl ListError for ObjectListError {}
1034

1035
/// decode xml to object list error collection
1036
#[derive(Debug)]
5✔
1037
#[non_exhaustive]
1038
enum ObjectListErrorKind {
1039
    /// when covert key_count failed ,return this error
1040
    KeyCount(ParseIntError),
1✔
1041
    /// when covert prefix failed ,return this error
1042
    Prefix(InvalidObjectDir),
1✔
1043
    /// when covert common_prefix failed ,return this error
1044
    CommonPrefix(InvalidObjectDir),
1✔
1045
    /// when covert max_keys failed ,return this error
1046
    MaxKeys(ParseIntError),
1✔
1047
    #[cfg(test)]
1048
    Bar,
1049
}
1050

1051
impl Client {
1052
    /// 查询默认 bucket 的文件列表
1053
    ///
1054
    /// 查询条件参数有多种方式,具体参考 [`get_object_list`] 文档
1055
    ///
1056
    /// [`get_object_list`]: crate::bucket::Bucket::get_object_list
1057
    #[inline(always)]
1058
    pub async fn get_object_list<Q: IntoQuery>(
3✔
1059
        &self,
3✔
1060
        query: Q,
3✔
1061
    ) -> Result<ObjectList, ExtractListError> {
6✔
1062
        self.get_object_list2(query.into_query()).await
3✔
1063
    }
6✔
1064

1065
    /// 查询默认 bucket 的文件列表
1066
    pub async fn get_object_list2(&self, query: Query) -> Result<ObjectList, ExtractListError> {
10✔
1067
        let bucket = BucketBase::new(self.bucket.to_owned(), self.endpoint.to_owned());
3✔
1068

1069
        let (bucket_url, resource) = bucket.get_url_resource(&query);
3✔
1070

1071
        let mut list = ObjectList::<ArcPointer> {
3✔
1072
            object_list: Vec::with_capacity(query.get_max_keys()),
3✔
1073
            bucket,
3✔
1074
            ..Default::default()
3✔
1075
        };
3✔
1076

1077
        let response = self.builder(Method::GET, bucket_url, resource)?;
3✔
1078
        let content = response.send_adjust_error().await?;
3✔
1079

1080
        list.decode(
6✔
1081
            &content.text().await?,
3✔
1082
            ObjectList::<ArcPointer>::init_object,
1083
        )?;
5✔
1084

1085
        list.set_client(Arc::new(self.clone()));
1✔
1086
        list.set_search_query(query);
1✔
1087

1088
        Ok(list)
1✔
1089
    }
7✔
1090

1091
    /// # 可将 object 列表导出到外部类型(关注便捷性)
1092
    ///
1093
    /// 从 Client 中的默认 bucket 中获取,如需获取其他 bucket 的,可调用 `set_bucket` 更改后调用
1094
    ///
1095
    /// 也可以通过调用 `set_endpoint` 更改可用区
1096
    ///
1097
    /// 可以参考下面示例,或者项目中的 `examples/custom.rs`
1098
    /// ## 示例
1099
    /// ```rust
1100
    /// use aliyun_oss_client::{
1101
    ///     decode::{ListError, RefineObject, RefineObjectList},
1102
    ///     object::{ExtractListError, InitObject},
1103
    ///     Client,
1104
    /// };
1105
    /// use dotenv::dotenv;
1106
    /// use thiserror::Error;
1107
    ///
1108
    /// #[derive(Debug)]
1109
    /// struct MyFile {
1110
    ///     key: String,
1111
    ///     #[allow(dead_code)]
1112
    ///     other: String,
1113
    /// }
1114
    /// impl RefineObject<MyError> for MyFile {
1115
    ///     fn set_key(&mut self, key: &str) -> Result<(), MyError> {
1116
    ///         self.key = key.to_string();
1117
    ///         Ok(())
1118
    ///     }
1119
    /// }
1120
    ///
1121
    /// #[derive(Default, Debug)]
1122
    /// struct MyBucket {
1123
    ///     name: String,
1124
    ///     files: Vec<MyFile>,
1125
    /// }
1126
    ///
1127
    /// impl RefineObjectList<MyFile, MyError> for MyBucket {
1128
    ///     fn set_name(&mut self, name: &str) -> Result<(), MyError> {
1129
    ///         self.name = name.to_string();
1130
    ///         Ok(())
1131
    ///     }
1132
    ///     fn set_list(&mut self, list: Vec<MyFile>) -> Result<(), MyError> {
1133
    ///         self.files = list;
1134
    ///         Ok(())
1135
    ///     }
1136
    /// }
1137
    ///
1138
    /// #[derive(Debug, Error)]
1139
    /// #[error("my error")]
1140
    /// enum MyError {}
1141
    ///
1142
    /// impl ListError for MyError {}
1143
    ///
1144
    /// async fn run() -> Result<(), ExtractListError> {
1145
    ///     dotenv().ok();
1146
    ///     use aliyun_oss_client::BucketName;
1147
    ///
1148
    ///     let client = Client::from_env().unwrap();
1149
    ///
1150
    ///     // 除了设置Default 外,还可以做更多设置
1151
    ///     let mut bucket = MyBucket {
1152
    ///         name: "abc".to_string(),
1153
    ///         files: Vec::with_capacity(20),
1154
    ///     };
1155
    ///
1156
    ///     // 利用闭包对 MyFile 做一下初始化设置
1157
    ///     impl InitObject<MyFile> for MyBucket {
1158
    ///         fn init_object(&mut self) -> Option<MyFile> {
1159
    ///             Some(MyFile {
1160
    ///               key: String::default(),
1161
    ///               other: "abc".to_string(),
1162
    ///             })
1163
    ///         }
1164
    ///     }
1165
    ///
1166
    ///     client.base_object_list((), &mut bucket).await?;
1167
    ///
1168
    ///     println!("bucket: {:?}", bucket);
1169
    ///
1170
    ///     Ok(())
1171
    /// }
1172
    /// ```
1173
    #[inline]
1174
    pub async fn base_object_list<
1175
        Q: IntoQuery,
1176
        List,
1177
        Item,
1178
        E: ListError,
1179
        ItemErr: Error + 'static,
1180
    >(
1181
        &self,
1182
        query: Q,
1183
        list: &mut List,
1184
    ) -> Result<(), ExtractListError>
1185
    where
1186
        List: RefineObjectList<Item, E, ItemErr> + InitObject<Item>,
1187
        Item: RefineObject<ItemErr>,
1188
    {
1189
        let query = query.into_query();
1190

1191
        self.base_object_list2(&query, list).await
1192
    }
1193

1194
    /// # 可将 object 列表导出到外部类型(关注性能)
1195
    ///
1196
    /// 从 Client 中的默认 bucket 中获取,如需获取其他 bucket 的,可调用 `set_bucket` 更改后调用
1197
    ///
1198
    /// 也可以通过调用 `set_endpoint` 更改可用区
1199
    pub async fn base_object_list2<List, Item, E: ListError, ItemErr: Error + 'static>(
1200
        &self,
1201
        query: &Query,
1202
        list: &mut List,
1203
    ) -> Result<(), ExtractListError>
1204
    where
1205
        List: RefineObjectList<Item, E, ItemErr> + InitObject<Item>,
1206
        Item: RefineObject<ItemErr>,
1207
    {
1208
        let bucket = self.get_bucket_base();
1209
        let (bucket_url, resource) = bucket.get_url_resource(query);
1210

1211
        let response = self.builder(Method::GET, bucket_url, resource)?;
1212
        let content = response.send_adjust_error().await?;
1213

1214
        list.decode(&content.text().await?, List::init_object)?;
1215

1216
        Ok(())
1217
    }
1218

1219
    /// # 获取包含自定义类型的 object 集合
1220
    /// 其包含在 [`ObjectList`] 对象中
1221
    ///
1222
    /// [`ObjectList`]: crate::object::ObjectList
1223
    pub async fn get_custom_object<Item, ItemErr>(
1224
        &self,
1225
        query: &Query,
1226
    ) -> Result<Objects<Item>, ExtractListError>
1227
    where
1228
        Item: RefineObject<ItemErr>,
1229
        Objects<Item>: InitObject<Item>,
1230
        ItemErr: Error + 'static,
1231
    {
1232
        let mut list = Objects::<Item>::default();
1233

1234
        self.base_object_list2(query, &mut list).await?;
1235

1236
        Ok(list)
1237
    }
1238
}
1239

1240
/// 为 [`base_object_list`] 方法,返回一个统一的 Error
1241
///
1242
/// [`base_object_list`]: crate::client::Client::base_object_list
1243
#[derive(Debug)]
8✔
1244
#[non_exhaustive]
1245
pub struct ExtractListError {
1246
    pub(crate) kind: ExtractListErrorKind,
4✔
1247
}
1248

1249
impl ExtractListError {
1250
    /// 判断 Error 类型是否为 "没有更多信息"
1251
    pub fn is_no_more(&self) -> bool {
×
1252
        matches!(self.kind, ExtractListErrorKind::NoMoreFile)
×
1253
    }
×
1254
}
1255

1256
/// [`ExtractListError`] 类型的枚举
1257
///
1258
/// [`ExtractListError`]: crate::object::ExtractListError
1259
#[derive(Debug)]
4✔
1260
#[non_exhaustive]
1261
pub(crate) enum ExtractListErrorKind {
1262
    #[doc(hidden)]
1263
    Builder(BuilderError),
3✔
1264

1265
    #[doc(hidden)]
1266
    Reqwest(reqwest::Error),
×
1267

1268
    /// 解析 xml 错误
1269
    Decode(InnerListError),
×
1270

1271
    /// 用于 Stream
1272
    NoMoreFile,
1273
}
1274

1275
impl From<InnerListError> for ExtractListError {
1276
    fn from(value: InnerListError) -> Self {
4✔
1277
        use ExtractListErrorKind::*;
1278
        Self {
4✔
1279
            kind: Decode(value),
4✔
1280
        }
1281
    }
4✔
1282
}
1283
impl From<BuilderError> for ExtractListError {
1284
    fn from(value: BuilderError) -> Self {
5✔
1285
        use ExtractListErrorKind::*;
1286
        Self {
5✔
1287
            kind: Builder(value),
5✔
1288
        }
1289
    }
5✔
1290
}
1291
impl From<reqwest::Error> for ExtractListError {
1292
    fn from(value: reqwest::Error) -> Self {
1✔
1293
        use ExtractListErrorKind::*;
1294
        Self {
1✔
1295
            kind: Reqwest(value),
1✔
1296
        }
1297
    }
1✔
1298
}
1299
impl Display for ExtractListError {
1300
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
8✔
1301
        use ExtractListErrorKind::*;
1302
        match &self.kind {
8✔
1303
            Builder(_) => "builder error".fmt(f),
1✔
1304
            Reqwest(_) => "reqwest error".fmt(f),
1✔
1305
            Decode(_) => "decode xml failed".fmt(f),
4✔
1306
            NoMoreFile => "no more file".fmt(f),
2✔
1307
        }
1308
    }
8✔
1309
}
1310
impl Error for ExtractListError {
1311
    fn source(&self) -> Option<&(dyn Error + 'static)> {
7✔
1312
        use ExtractListErrorKind::*;
1313
        match &self.kind {
7✔
1314
            Builder(e) => Some(e),
1✔
1315
            Reqwest(e) => Some(e),
1✔
1316
            Decode(e) => e.get_source(),
4✔
1317
            NoMoreFile => None,
1✔
1318
        }
1319
    }
7✔
1320
}
1321

1322
#[cfg(feature = "blocking")]
1323
impl ClientRc {
1324
    /// 查询默认 bucket 的文件列表
1325
    ///
1326
    /// 查询条件参数有多种方式,具体参考 [`get_object_list`](../bucket/struct.Bucket.html#method.get_object_list) 文档
1327
    pub fn get_object_list<Q: IntoQuery>(
1✔
1328
        self,
1329
        query: Q,
1330
    ) -> Result<ObjectList<RcPointer>, ExtractListError> {
1331
        let query = query.into_query();
1✔
1332

1333
        let bucket = BucketBase::new(self.bucket.to_owned(), self.endpoint.to_owned());
1✔
1334

1335
        let (bucket_url, resource) = bucket.get_url_resource(&query);
1✔
1336

1337
        let mut list = ObjectList::<RcPointer> {
1✔
1338
            object_list: Vec::with_capacity(query.get_max_keys()),
1✔
1339
            bucket,
1✔
1340
            ..Default::default()
1✔
1341
        };
1✔
1342

1343
        let response = self.builder(Method::GET, bucket_url, resource)?;
1✔
1344
        let content = response.send_adjust_error()?;
1✔
1345

1346
        list.decode(&content.text()?, ObjectList::<RcPointer>::init_object)?;
1✔
1347

1348
        list.set_client(Rc::new(self));
1✔
1349
        list.set_search_query(query);
1✔
1350

1351
        Ok(list)
1✔
1352
    }
1✔
1353

1354
    /// 可将 object 列表导出到外部 struct
1355
    #[inline]
1356
    pub fn base_object_list<Q: IntoQuery, List, Item, F, E: ListError, ItemErr: Error + 'static>(
1357
        &self,
1358
        query: Q,
1359
        list: &mut List,
1360
        init_object: F,
1361
    ) -> Result<(), ExtractListError>
1362
    where
1363
        List: RefineObjectList<Item, E, ItemErr>,
1364
        Item: RefineObject<ItemErr>,
1365
        F: Fn(&mut List) -> Option<Item>,
1366
    {
1367
        let bucket = BucketBase::new(self.bucket.clone(), self.endpoint.to_owned());
1368

1369
        let query = query.into_query();
1370
        let (bucket_url, resource) = bucket.get_url_resource(&query);
1371

1372
        let response = self.builder(Method::GET, bucket_url, resource)?;
1373
        let content = response.send_adjust_error()?;
1374

1375
        list.decode(&content.text()?, init_object)?;
1376

1377
        Ok(())
1378
    }
1379
}
1380

1381
#[cfg(feature = "blocking")]
1382
impl Iterator for ObjectList<RcPointer> {
1383
    type Item = ObjectList<RcPointer>;
1384
    fn next(&mut self) -> Option<Self> {
×
1385
        if !self.next_continuation_token.is_empty() {
×
1386
            self.search_query
×
1387
                .insert(CONTINUATION_TOKEN, self.next_continuation_token.to_owned());
×
1388
            self.get_object_list().ok()
×
1389
        } else {
1390
            None
×
1391
        }
1392
    }
×
1393
}
1394

1395
// use std::task::Poll::{self, Ready};
1396

1397
// impl Stream for ObjectList<ArcPointer> {
1398
//     type Item = ObjectList<ArcPointer>;
1399

1400
//     fn poll_next(
1401
//         self: std::pin::Pin<&mut Self>,
1402
//         cx: &mut std::task::Context<'_>,
1403
//     ) -> Poll<Option<Self::Item>> {
1404
//         match self.next_query() {
1405
//             Some(query) => {
1406
//                 let mut url = self.bucket.to_url();
1407
//                 url.set_search_query(&query);
1408

1409
//                 let canonicalized = CanonicalizedResource::from_bucket_query(&self.bucket, &query);
1410

1411
//                 let builder = self.builder(Method::GET, url, canonicalized);
1412
//                 match builder {
1413
//                     Err(err) => Ready(None),
1414
//                     Ok(builder) => {
1415
//                         let waker = cx.waker().clone();
1416

1417
//                         std::thread::spawn(move || {
1418
//                             let response = builder.send_adjust_error();
1419

1420
//                             let response = futures::executor::block_on(response);
1421
//                             let text = response.unwrap().text();
1422
//                             let text = futures::executor::block_on(text);
1423

1424
//                             let text = text.unwrap();
1425

1426
//                             let bucket_arc = Arc::new(self.bucket);
1427

1428
//                             let init_object = || {
1429
//                                 let object = Object::<ArcPointer>::default();
1430
//                                 object.base.set_bucket(bucket_arc.clone());
1431
//                                 object
1432
//                             };
1433

1434
//                             self.decode(&text, init_object).unwrap();
1435

1436
//                             self.set_search_query(query);
1437

1438
//                             waker.wake();
1439
//                         });
1440

1441
//                         Poll::Pending
1442
//                     }
1443
//                 }
1444
//             }
1445
//             None => Ready(None),
1446
//         }
1447
//     }
1448
// }
1449

1450
#[oss_gen_rc]
1451
impl PartialEq<Object<ArcPointer>> for Object<ArcPointer> {
1452
    #[inline]
1453
    fn eq(&self, other: &Object<ArcPointer>) -> bool {
8✔
1454
        self.base == other.base
8✔
1455
            && self.last_modified == other.last_modified
6✔
1456
            && self.etag == other.etag
5✔
1457
            && self._type == other._type
4✔
1458
            && self.size == other.size
3✔
1459
            && self.storage_class == other.storage_class
2✔
1460
    }
8✔
1461
}
1462

1463
impl<T: PointerFamily> PartialEq<DateTime<Utc>> for Object<T> {
1464
    #[inline]
1465
    fn eq(&self, other: &DateTime<Utc>) -> bool {
1466
        &self.last_modified == other
1467
    }
1468
}
1469

1470
impl<T: PointerFamily> PartialEq<u64> for Object<T> {
1471
    #[inline]
1472
    fn eq(&self, other: &u64) -> bool {
1473
        &self.size == other
1474
    }
1475
}
1476

1477
#[oss_gen_rc]
1478
impl PartialEq<ObjectBase<ArcPointer>> for Object<ArcPointer> {
1479
    #[inline]
1480
    fn eq(&self, other: &ObjectBase<ArcPointer>) -> bool {
×
1481
        &self.base == other
×
1482
    }
×
1483
}
1484

1485
/// 未来计划支持的功能
1486
#[derive(Default)]
×
1487
#[doc(hidden)]
1488
pub struct PutObject<'a> {
1489
    pub forbid_overwrite: bool,
×
1490
    pub server_side_encryption: Option<Encryption>,
×
1491
    pub server_side_data_encryption: Option<Encryption>,
×
1492
    pub server_side_encryption_key_id: Option<&'a str>,
×
1493
    pub object_acl: ObjectAcl,
×
1494
    pub storage_class: StorageClass,
×
1495
    pub tagging: Option<&'a str>,
×
1496
}
1497

1498
/// 未来计划支持的功能
1499
#[derive(Default)]
×
1500
#[doc(hidden)]
1501
pub enum Encryption {
1502
    #[default]
1503
    Aes256,
1504
    Kms,
1505
    Sm4,
1506
}
1507

1508
/// 未来计划支持的功能
1509
#[derive(Default)]
×
1510
#[doc(hidden)]
1511
pub enum ObjectAcl {
1512
    #[default]
1513
    Default,
1514
    Private,
1515
    PublicRead,
1516
    PublicReadWrite,
1517
}
1518

1519
/// 存储类型
1520
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
72✔
1521
#[non_exhaustive]
1522
pub struct StorageClass {
1523
    kind: StorageClassKind,
36✔
1524
}
1525

1526
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
44✔
1527
#[non_exhaustive]
1528
enum StorageClassKind {
1529
    /// Standard 默认
1530
    #[default]
1531
    Standard,
1532
    /// IA
1533
    IA,
1534
    /// Archive
1535
    Archive,
1536
    /// ColdArchive
1537
    ColdArchive,
1538
}
1539

1540
impl StorageClass {
1541
    /// Archive
1542
    pub const ARCHIVE: Self = Self {
1543
        kind: StorageClassKind::Archive,
1544
    };
1545
    /// IA
1546
    pub const IA: Self = Self {
1547
        kind: StorageClassKind::IA,
1548
    };
1549
    /// Standard
1550
    pub const STANDARD: Self = Self {
1551
        kind: StorageClassKind::Standard,
1552
    };
1553
    /// ColdArchive
1554
    pub const COLD_ARCHIVE: Self = Self {
1555
        kind: StorageClassKind::ColdArchive,
1556
    };
1557

1558
    /// init StorageClass
1559
    pub fn new(s: &str) -> Option<StorageClass> {
23✔
1560
        let start_char = s.chars().next()?;
23✔
1561

1562
        let kind = match start_char {
22✔
1563
            'a' | 'A' => StorageClassKind::Archive,
4✔
1564
            'i' | 'I' => StorageClassKind::IA,
2✔
1565
            's' | 'S' => StorageClassKind::Standard,
10✔
1566
            'c' | 'C' => StorageClassKind::ColdArchive,
2✔
1567
            _ => return None,
4✔
1568
        };
1569
        Some(Self { kind })
18✔
1570
    }
23✔
1571
}
1572

1573
/// 未来计划支持的功能
1574
#[derive(Default)]
×
1575
#[doc(hidden)]
1576
pub struct CopyObject<'a> {
1577
    pub forbid_overwrite: bool,
×
1578
    pub copy_source: &'a str,
×
1579
    pub copy_source_if_match: Option<&'a str>,
×
1580
    pub copy_source_if_none_match: Option<&'a str>,
×
1581
    pub copy_source_if_unmodified_since: Option<&'a str>,
×
1582
    pub copy_source_if_modified_since: Option<&'a str>,
×
1583
    pub metadata_directive: CopyDirective,
×
1584
    pub server_side_encryption: Option<Encryption>,
×
1585
    pub server_side_encryption_key_id: Option<&'a str>,
×
1586
    pub object_acl: ObjectAcl,
×
1587
    pub storage_class: StorageClass,
×
1588
    pub tagging: Option<&'a str>,
×
1589
    pub tagging_directive: CopyDirective,
×
1590
}
1591

1592
/// 未来计划支持的功能
1593
#[derive(Default)]
×
1594
#[doc(hidden)]
1595
pub enum CopyDirective {
1596
    #[default]
1597
    Copy,
1598
    Replace,
1599
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc