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

tu6ge / oss-rs / 5791781892

pending completion
5791781892

push

github

web-flow
feat(decode)!: remove init object fn, and add InitObject trait (#25)

* feat(decode)!: change init object fn

* feat(blocking)

* style(doc)

* feat(decode)!: change init object fn

* feat(object)!: change get_next_base

change get_next_base return type , when has not next page condition
return `None`, or try get next page data, if success
return `Some(Ok(_))`, failed return `Some(Err(_))`

* feat(object): merge error type

merge object_init error and object item error

* feat(decode)!: change init_object

before return `T`, now return `Option<T>`

* fix

* fix

* feat(object)!: create InitObject trait

通过实现 InitObject trait 来初始化 object 类型 (自定义类型)

* fix

* fix

* feat(bucket)!: support InitObject

* style

* feat(bucket)!: change base_bucket_info

58 of 58 new or added lines in 5 files covered. (100.0%)

6200 of 6443 relevant lines covered (96.23%)

9.31 hits per line

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

89.11
/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::object::ObjectPathInner;
72
use crate::types::{
73
    core::SetOssQuery,
74
    object::{
75
        CommonPrefixes, InvalidObjectDir, InvalidObjectPath, ObjectBase, ObjectDir, ObjectPath,
76
    },
77
    CanonicalizedResource, Query, QueryKey, QueryValue, CONTINUATION_TOKEN,
78
};
79
use crate::{BucketName, Client, EndPoint, KeyId, KeySecret};
80
use async_stream::try_stream;
81
use chrono::{DateTime, NaiveDateTime, Utc};
82
use futures_core::stream::Stream;
83
use http::Method;
84
use oss_derive::oss_gen_rc;
85
use url::Url;
86

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

97
// pub mod content;
98

99
#[cfg(test)]
100
mod test;
101

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

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

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

138
/// 异步的 Object struct
139
pub type ObjectArc = Object<ArcPointer>;
140

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

320
/// # 初始化 object 项目的接口
321
///
322
/// 根据 object 列表初始化一个 object 数据
323
pub trait InitObject<Target> {
324
    /// 具体的过程
325
    fn init_object(&mut self) -> Option<Target>;
326
}
327

328
impl InitObject<Object<ArcPointer>> for ObjectList<ArcPointer, Object<ArcPointer>> {
329
    fn init_object(&mut self) -> Option<Object<ArcPointer>> {
4✔
330
        Some(Object::from_bucket(Arc::new(self.bucket.clone())))
4✔
331
    }
4✔
332
}
333

334
#[cfg(feature = "blocking")]
335
impl InitObject<Object<RcPointer>> for ObjectList<RcPointer, Object<RcPointer>> {
336
    fn init_object(&mut self) -> Option<Object<RcPointer>> {
3✔
337
        Some(Object::<RcPointer>::from_bucket(Rc::new(
3✔
338
            self.bucket.clone(),
3✔
339
        )))
340
    }
3✔
341
}
342

343
impl ObjectList<ArcPointer> {
344
    /// 异步获取下一页的数据
345
    /// TODO 改为 unstable
346
    pub async fn get_next_list(&self) -> Result<ObjectList<ArcPointer>, ExtractListError> {
×
347
        match self.next_query() {
348
            None => Err(ExtractListError {
349
                kind: ExtractListErrorKind::NoMoreFile,
350
            }),
351
            Some(query) => {
352
                let mut url = self.bucket.to_url();
353
                url.set_oss_query(&query);
354

355
                let canonicalized = CanonicalizedResource::from_bucket_query(&self.bucket, &query);
356

357
                let response = self
358
                    .builder(Method::GET, url, canonicalized)?
359
                    .send_adjust_error()
360
                    .await?;
361

362
                let mut list = ObjectList::<ArcPointer> {
363
                    client: self.client(),
364
                    bucket: self.bucket.clone(),
365
                    object_list: Vec::with_capacity(query.get_max_keys()),
366
                    ..Default::default()
367
                };
368

369
                list.decode(&response.text().await?, Self::init_object)?;
370

371
                list.set_search_query(query);
372
                Ok(list)
373
            }
374
        }
375
    }
×
376

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

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

440
#[cfg(feature = "blocking")]
441
impl ObjectList<RcPointer> {
442
    /// 从 OSS 获取 object 列表信息
443
    pub fn get_object_list(&self) -> Result<Self, ExtractListError> {
1✔
444
        let mut list = ObjectList::<RcPointer>::clone_base(self);
1✔
445

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

448
        let response = self
1✔
449
            .builder(Method::GET, bucket_url, resource)?
1✔
450
            .send_adjust_error()?;
×
451

452
        list.decode(&response.text()?, ObjectList::<RcPointer>::init_object)
1✔
453
            .map_err(ExtractListError::from)?;
1✔
454

455
        Ok(list)
1✔
456
    }
1✔
457
}
458

459
impl<T: PointerFamily, Item> ObjectList<T, Item> {
460
    /// 设置查询条件
461
    #[inline]
462
    pub fn set_search_query(&mut self, search_query: Query) {
4✔
463
        self.search_query = search_query;
4✔
464
    }
4✔
465

466
    /// 设置 bucket 元信息
467
    pub fn set_bucket(&mut self, bucket: BucketBase) {
1✔
468
        self.bucket = bucket;
1✔
469
    }
1✔
470

471
    /// 获取 bucket 名称
472
    pub fn bucket_name(&self) -> &str {
1✔
473
        self.bucket.name()
1✔
474
    }
1✔
475

476
    /// 返回 object 的 Vec 集合
477
    pub fn to_vec(self) -> Vec<Item> {
478
        self.object_list
479
    }
480

481
    /// 返回文件数量
482
    pub fn len(&self) -> usize {
483
        self.object_list.len()
484
    }
485

486
    /// 返回是否存在文件
487
    pub fn is_empty(&self) -> bool {
488
        self.object_list.is_empty()
489
    }
490
}
491

492
impl<T: PointerFamily> Default for Object<T> {
493
    fn default() -> Self {
20✔
494
        Object {
20✔
495
            base: ObjectBase::<T>::default(),
20✔
496
            last_modified: DateTime::<Utc>::from_utc(
20✔
497
                #[allow(clippy::unwrap_used)]
498
                NaiveDateTime::from_timestamp_opt(0, 0).unwrap(),
20✔
499
                Utc,
500
            ),
501
            etag: String::default(),
20✔
502
            _type: String::default(),
20✔
503
            size: 0,
504
            storage_class: StorageClass::default(),
20✔
505
        }
506
    }
20✔
507
}
508

509
impl<T: PointerFamily> AsRef<ObjectPath> for Object<T> {
510
    fn as_ref(&self) -> &ObjectPath {
1✔
511
        self.base.as_ref()
1✔
512
    }
1✔
513
}
514

515
impl<T: PointerFamily> AsRef<DateTime<Utc>> for Object<T> {
516
    fn as_ref(&self) -> &DateTime<Utc> {
517
        &self.last_modified
518
    }
519
}
520

521
impl<T: PointerFamily> AsRef<StorageClass> for Object<T> {
522
    fn as_ref(&self) -> &StorageClass {
523
        &self.storage_class
524
    }
525
}
526

527
impl<T: PointerFamily> Object<T> {
528
    /// 初始化 Object 结构体
529
    pub fn new(
12✔
530
        bucket: T::Bucket,
531
        path: ObjectPath,
532
        last_modified: DateTime<Utc>,
533
        etag: String,
534
        _type: String,
535
        size: u64,
536
        storage_class: StorageClass,
537
    ) -> Self {
538
        let base = ObjectBase::<T>::new2(bucket, path);
12✔
539
        Self {
12✔
540
            base,
12✔
541
            last_modified,
542
            etag,
543
            _type,
544
            size,
545
            storage_class,
546
        }
547
    }
12✔
548

549
    pub(crate) fn from_bucket(bucket: T::Bucket) -> Self {
8✔
550
        Self {
8✔
551
            base: ObjectBase::<T>::init_with_bucket(bucket),
8✔
552
            ..Default::default()
8✔
553
        }
554
    }
8✔
555

556
    /// 读取 Object 元信息
557
    #[inline]
558
    pub fn base(&self) -> &ObjectBase<T> {
559
        &self.base
560
    }
561

562
    /// 设置 Object 元信息
563
    #[inline]
564
    pub fn set_base(&mut self, base: ObjectBase<T>) {
1✔
565
        self.base = base;
1✔
566
    }
1✔
567

568
    /// 读取最后修改时间
569
    #[inline]
570
    pub fn last_modified(&self) -> &DateTime<Utc> {
571
        &self.last_modified
572
    }
573

574
    /// 设置最后修改时间
575
    #[inline]
576
    pub fn set_last_modified(&mut self, last_modified: DateTime<Utc>) {
577
        self.last_modified = last_modified;
578
    }
579

580
    /// 读取 etag 信息
581
    #[inline]
582
    pub fn etag(&self) -> &String {
583
        &self.etag
584
    }
585

586
    /// 设置 etag
587
    #[inline]
588
    pub fn set_etag(&mut self, etag: String) {
589
        self.etag = etag
590
    }
591

592
    /// 读取 type
593
    #[inline]
594
    pub fn get_type_string(&self) -> &String {
595
        &self._type
596
    }
597

598
    /// 设置 type
599
    #[inline]
600
    pub fn set_type_string(&mut self, _type: String) {
601
        self._type = _type;
602
    }
603

604
    /// 读取文件 size
605
    #[inline]
606
    pub fn size(&self) -> u64 {
607
        self.size
608
    }
609

610
    /// 设置文件 size
611
    #[inline]
612
    pub fn set_size(&mut self, size: u64) {
613
        self.size = size;
614
    }
615

616
    /// 读取 storage_class
617
    #[inline]
618
    pub fn storage_class(&self) -> &StorageClass {
619
        &self.storage_class
620
    }
621

622
    /// 设置 storage_class
623
    #[inline]
624
    pub fn set_storage_class(&mut self, storage_class: StorageClass) {
625
        self.storage_class = storage_class;
626
    }
627

628
    /// 获取一部分数据
629
    pub fn pieces(
630
        self,
631
    ) -> (
632
        ObjectBase<T>,
633
        DateTime<Utc>,
634
        String,
635
        String,
636
        u64,
637
        StorageClass,
638
    ) {
639
        (
640
            self.base,
641
            self.last_modified,
642
            self.etag,
643
            self._type,
644
            self.size,
645
            self.storage_class,
646
        )
647
    }
648

649
    /// 读取 文件路径
650
    pub fn path(&self) -> ObjectPath {
651
        self.base.path()
652
    }
653

654
    #[doc(hidden)]
655
    pub fn path_string(&self) -> String {
656
        self.base.path().to_string()
657
    }
658
}
659

660
impl Object<ArcPointer> {
661
    #[cfg(test)]
662
    pub fn test_path(path: &'static str) -> Self {
1✔
663
        let mut object = Self::default();
1✔
664
        object.set_base(ObjectBase::<ArcPointer>::new2(
1✔
665
            Arc::new(BucketBase::default()),
1✔
666
            path.try_into().unwrap(),
1✔
667
        ));
668
        object
669
    }
1✔
670
}
671

672
impl<T: PointerFamily> From<Object<T>> for ObjectPathInner<'static> {
673
    #[inline]
674
    fn from(obj: Object<T>) -> Self {
675
        obj.base.path
676
    }
677
}
678

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

709
    /// 带签名的 Url 链接
710
    pub fn to_sign_url(&self, key: &KeyId, secret: &KeySecret, expires: i64) -> Url {
1✔
711
        self.base.to_sign_url(key, secret, expires)
1✔
712
    }
1✔
713
}
714

715
/// Object 结构体的构建器
716
pub struct ObjectBuilder<T: PointerFamily = ArcPointer> {
717
    object: Object<T>,
718
}
719

720
impl<T: PointerFamily> ObjectBuilder<T> {
721
    /// 初始化 Object 构建器
722
    pub fn new(bucket: T::Bucket, path: ObjectPath) -> Self {
5✔
723
        let base = ObjectBase::<T>::new2(bucket, path);
5✔
724
        Self {
5✔
725
            object: Object {
5✔
726
                base,
5✔
727
                last_modified: DateTime::<Utc>::from_utc(
5✔
728
                    #[allow(clippy::unwrap_used)]
729
                    NaiveDateTime::from_timestamp_opt(0, 0).unwrap(),
5✔
730
                    Utc,
731
                ),
732
                ..Default::default()
5✔
733
            },
734
        }
735
    }
5✔
736

737
    /// 设置元信息
738
    pub fn bucket(&mut self, bucket: T::Bucket) -> &mut Self {
1✔
739
        self.object.base.set_bucket(bucket);
1✔
740
        self
741
    }
1✔
742

743
    /// 设置 last_modified
744
    pub fn last_modified(&mut self, date: DateTime<Utc>) -> &mut Self {
1✔
745
        self.object.last_modified = date;
1✔
746
        self
747
    }
1✔
748

749
    /// 设置 etag
750
    pub fn etag(&mut self, etag: String) -> &mut Self {
1✔
751
        self.object.etag = etag;
1✔
752
        self
753
    }
1✔
754

755
    /// 设置 type
756
    pub fn set_type(&mut self, _type: String) -> &mut Self {
1✔
757
        self.object._type = _type;
1✔
758
        self
759
    }
1✔
760

761
    /// 设置 size
762
    pub fn size(&mut self, size: u64) -> &mut Self {
1✔
763
        self.object.size = size;
1✔
764
        self
765
    }
1✔
766

767
    /// 设置 storage_class
768
    pub fn storage_class(&mut self, storage_class: StorageClass) -> &mut Self {
1✔
769
        self.object.storage_class = storage_class;
1✔
770
        self
771
    }
1✔
772

773
    /// 返回 object
774
    pub fn build(self) -> Object<T> {
3✔
775
        self.object
3✔
776
    }
3✔
777
}
778

779
#[oss_gen_rc]
×
780
impl ObjectBuilder<ArcPointer> {
781
    /// 设置元信息
782
    pub fn bucket_base(&mut self, base: BucketBase) -> &mut Self {
4✔
783
        self.object.base.set_bucket(Arc::new(base));
4✔
784
        self
785
    }
4✔
786
}
787

788
impl<T: PointerFamily> RefineObject<BuildInItemError> for Object<T> {
789
    #[inline]
790
    fn set_key(&mut self, key: &str) -> Result<(), BuildInItemError> {
8✔
791
        self.base
24✔
792
            .set_path(key.to_owned())
8✔
793
            .map_err(|e| BuildInItemError {
10✔
794
                source: key.to_string(),
1✔
795
                kind: BuildInItemErrorKind::BasePath(e),
1✔
796
            })
1✔
797
    }
8✔
798

799
    #[inline]
800
    fn set_last_modified(&mut self, value: &str) -> Result<(), BuildInItemError> {
8✔
801
        self.last_modified = value.parse().map_err(|e| BuildInItemError {
10✔
802
            source: value.to_string(),
1✔
803
            kind: BuildInItemErrorKind::LastModified(e),
1✔
804
        })?;
2✔
805
        Ok(())
7✔
806
    }
8✔
807

808
    #[inline]
809
    fn set_etag(&mut self, value: &str) -> Result<(), BuildInItemError> {
7✔
810
        self.etag = value.to_string();
7✔
811
        Ok(())
7✔
812
    }
7✔
813

814
    #[inline]
815
    fn set_type(&mut self, value: &str) -> Result<(), BuildInItemError> {
7✔
816
        self._type = value.to_string();
7✔
817
        Ok(())
7✔
818
    }
7✔
819

820
    #[inline]
821
    fn set_size(&mut self, size: &str) -> Result<(), BuildInItemError> {
8✔
822
        self.size = size.parse().map_err(|e| BuildInItemError {
12✔
823
            source: size.to_string(),
2✔
824
            kind: BuildInItemErrorKind::Size(e),
2✔
825
        })?;
4✔
826
        Ok(())
6✔
827
    }
8✔
828

829
    #[inline]
830
    fn set_storage_class(&mut self, storage_class: &str) -> Result<(), BuildInItemError> {
8✔
831
        self.storage_class = StorageClass::new(storage_class).ok_or(BuildInItemError {
16✔
832
            source: storage_class.to_string(),
8✔
833
            kind: BuildInItemErrorKind::InvalidStorageClass,
8✔
834
        })?;
1✔
835
        Ok(())
7✔
836
    }
8✔
837
}
838

839
/// Xml 转化为内置 Object 时的错误集合
840
#[derive(Debug)]
10✔
841
#[non_exhaustive]
842
pub struct BuildInItemError {
843
    source: String,
844
    kind: BuildInItemErrorKind,
5✔
845
}
846

847
impl BuildInItemError {
848
    #[cfg(test)]
849
    pub(crate) fn test_new() -> Self {
2✔
850
        Self {
2✔
851
            source: "foo".to_string(),
2✔
852
            kind: BuildInItemErrorKind::InvalidStorageClass,
2✔
853
        }
854
    }
2✔
855
}
856

857
impl Display for BuildInItemError {
858
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
6✔
859
        use BuildInItemErrorKind::*;
860
        let kind = match &self.kind {
6✔
861
            Size(_) => "size",
2✔
862
            BasePath(_) => "base-path",
1✔
863
            LastModified(_) => "last-modified",
1✔
864
            InvalidStorageClass => "storage-class",
2✔
865
        };
866
        write!(f, "parse {kind} failed, gived str: {}", self.source)
6✔
867
    }
6✔
868
}
869

870
impl Error for BuildInItemError {
871
    fn source(&self) -> Option<&(dyn Error + 'static)> {
4✔
872
        use BuildInItemErrorKind::*;
873
        match &self.kind {
4✔
874
            Size(e) => Some(e),
1✔
875
            BasePath(e) => Some(e),
1✔
876
            LastModified(e) => Some(e),
1✔
877
            InvalidStorageClass => None,
1✔
878
        }
879
    }
4✔
880
}
881

882
/// Xml 转化为内置 Object 时的错误集合
883
#[derive(Debug)]
5✔
884
#[non_exhaustive]
885
enum BuildInItemErrorKind {
886
    /// 转换数字类型的错误
887
    Size(ParseIntError),
1✔
888

889
    /// 转换为 ObjectPath 时的错误
890
    BasePath(InvalidObjectPath),
1✔
891

892
    /// 转换日期格式的错误
893
    LastModified(chrono::ParseError),
1✔
894

895
    // /// 接收 Xml 转换时的错误
896
    // Xml(quick_xml::Error),
897
    /// 非法的 StorageClass
898
    InvalidStorageClass,
899
}
900

901
impl<P: PointerFamily, Item: RefineObject<E>, E: Error + 'static>
902
    RefineObjectList<Item, ObjectListError, E> for ObjectList<P, Item>
903
{
904
    #[inline]
905
    fn set_key_count(&mut self, key_count: &str) -> Result<(), ObjectListError> {
7✔
906
        self.key_count = key_count.parse().map_err(|e| ObjectListError {
11✔
907
            source: key_count.to_owned(),
2✔
908
            kind: ObjectListErrorKind::KeyCount(e),
2✔
909
        })?;
4✔
910
        Ok(())
5✔
911
    }
7✔
912

913
    #[inline]
914
    fn set_prefix(&mut self, prefix: &str) -> Result<(), ObjectListError> {
9✔
915
        if prefix.is_empty() {
9✔
916
            self.prefix = None;
7✔
917
        } else {
918
            let mut string = String::from(prefix);
2✔
919
            string += "/";
2✔
920
            self.prefix = Some(string.parse().map_err(|e| ObjectListError {
4✔
921
                source: prefix.to_owned(),
1✔
922
                kind: ObjectListErrorKind::Prefix(e),
1✔
923
            })?)
2✔
924
        }
2✔
925
        Ok(())
8✔
926
    }
9✔
927

928
    #[inline]
929
    fn set_common_prefix(
2✔
930
        &mut self,
931
        list: &[std::borrow::Cow<'_, str>],
932
    ) -> Result<(), ObjectListError> {
933
        self.common_prefixes = Vec::with_capacity(list.len());
2✔
934
        for val in list.iter() {
2✔
935
            self.common_prefixes
1✔
936
                .push(val.parse().map_err(|e| ObjectListError {
3✔
937
                    source: val.to_string(),
1✔
938
                    kind: ObjectListErrorKind::CommonPrefix(e),
1✔
939
                })?);
2✔
940
        }
941
        Ok(())
1✔
942
    }
2✔
943

944
    #[inline]
945
    fn set_max_keys(&mut self, max_keys: &str) -> Result<(), ObjectListError> {
9✔
946
        self.max_keys = max_keys.parse().map_err(|e| ObjectListError {
13✔
947
            source: max_keys.to_string(),
2✔
948
            kind: ObjectListErrorKind::MaxKeys(e),
2✔
949
        })?;
4✔
950
        Ok(())
7✔
951
    }
9✔
952

953
    #[inline]
954
    fn set_next_continuation_token_str(&mut self, token: &str) -> Result<(), ObjectListError> {
1✔
955
        self.next_continuation_token = token.to_owned();
1✔
956
        Ok(())
1✔
957
    }
1✔
958

959
    #[inline]
960
    fn set_list(&mut self, list: Vec<Item>) -> Result<(), ObjectListError> {
5✔
961
        self.object_list = list;
5✔
962
        Ok(())
5✔
963
    }
5✔
964
}
965

966
/// decode xml to object list error collection
967
#[derive(Debug)]
10✔
968
#[non_exhaustive]
969
pub struct ObjectListError {
970
    source: String,
971
    kind: ObjectListErrorKind,
5✔
972
}
973

974
impl ObjectListError {
975
    #[cfg(test)]
976
    pub(crate) fn test_new() -> Self {
1✔
977
        Self {
1✔
978
            source: "foo".to_string(),
1✔
979
            kind: ObjectListErrorKind::Bar,
1✔
980
        }
981
    }
1✔
982
}
983

984
impl Display for ObjectListError {
985
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
7✔
986
        use ObjectListErrorKind::*;
987
        let kind: &str = match &self.kind {
7✔
988
            KeyCount(_) => "key-count",
2✔
989
            Prefix(_) => "prefix",
1✔
990
            CommonPrefix(_) => "common-prefix",
1✔
991
            MaxKeys(_) => "max-keys",
2✔
992
            #[cfg(test)]
993
            Bar => "bar",
1✔
994
        };
995
        write!(f, "parse {kind} failed, gived str: {}", self.source)
7✔
996
    }
7✔
997
}
998

999
impl Error for ObjectListError {
1000
    fn source(&self) -> Option<&(dyn Error + 'static)> {
4✔
1001
        use ObjectListErrorKind::*;
1002
        match &self.kind {
4✔
1003
            KeyCount(e) | MaxKeys(e) => Some(e),
2✔
1004
            Prefix(e) | CommonPrefix(e) => Some(e),
2✔
1005
            #[cfg(test)]
1006
            Bar => None,
×
1007
        }
1008
    }
4✔
1009
}
1010

1011
impl ListError for ObjectListError {}
1012

1013
/// decode xml to object list error collection
1014
#[derive(Debug)]
5✔
1015
#[non_exhaustive]
1016
enum ObjectListErrorKind {
1017
    /// when covert key_count failed ,return this error
1018
    KeyCount(ParseIntError),
1✔
1019
    /// when covert prefix failed ,return this error
1020
    Prefix(InvalidObjectDir),
1✔
1021
    /// when covert common_prefix failed ,return this error
1022
    CommonPrefix(InvalidObjectDir),
1✔
1023
    /// when covert max_keys failed ,return this error
1024
    MaxKeys(ParseIntError),
1✔
1025
    #[cfg(test)]
1026
    Bar,
1027
}
1028

1029
impl Client {
1030
    /// 查询默认 bucket 的文件列表
1031
    ///
1032
    /// 查询条件参数有多种方式,具体参考 [`get_object_list`] 文档
1033
    ///
1034
    /// [`get_object_list`]: crate::bucket::Bucket::get_object_list
1035
    #[inline(always)]
1036
    pub async fn get_object_list<Q: IntoIterator<Item = (QueryKey, QueryValue)>>(
3✔
1037
        &self,
3✔
1038
        query: Q,
3✔
1039
    ) -> Result<ObjectList, ExtractListError> {
6✔
1040
        self.get_object_list2(Query::from_iter(query)).await
3✔
1041
    }
6✔
1042

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

1047
        let (bucket_url, resource) = bucket.get_url_resource(&query);
3✔
1048

1049
        let mut list = ObjectList::<ArcPointer> {
3✔
1050
            object_list: Vec::with_capacity(query.get_max_keys()),
3✔
1051
            bucket,
3✔
1052
            ..Default::default()
3✔
1053
        };
3✔
1054

1055
        let response = self.builder(Method::GET, bucket_url, resource)?;
3✔
1056
        let content = response.send_adjust_error().await?;
3✔
1057

1058
        list.decode(
6✔
1059
            &content.text().await?,
3✔
1060
            ObjectList::<ArcPointer>::init_object,
1061
        )?;
5✔
1062

1063
        list.set_client(Arc::new(self.clone()));
1✔
1064
        list.set_search_query(query);
1✔
1065

1066
        Ok(list)
1✔
1067
    }
7✔
1068

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

1169
        self.base_object_list2(&query, list).await
1170
    }
1171

1172
    /// # 可将 object 列表导出到外部类型(关注性能)
1173
    ///
1174
    /// 从 Client 中的默认 bucket 中获取,如需获取其他 bucket 的,可调用 `set_bucket` 更改后调用
1175
    ///
1176
    /// 也可以通过调用 `set_endpoint` 更改可用区
1177
    pub async fn base_object_list2<List, Item, E: ListError, ItemErr: Error + 'static>(
1178
        &self,
1179
        query: &Query,
1180
        list: &mut List,
1181
    ) -> Result<(), ExtractListError>
1182
    where
1183
        List: RefineObjectList<Item, E, ItemErr> + InitObject<Item>,
1184
        Item: RefineObject<ItemErr>,
1185
    {
1186
        let bucket = self.get_bucket_base();
1187
        let (bucket_url, resource) = bucket.get_url_resource(query);
1188

1189
        let response = self.builder(Method::GET, bucket_url, resource)?;
1190
        let content = response.send_adjust_error().await?;
1191

1192
        list.decode(&content.text().await?, List::init_object)?;
1193

1194
        Ok(())
1195
    }
1196

1197
    /// # 获取包含自定义类型的 object 集合
1198
    /// 其包含在 [`ObjectList`] 对象中
1199
    ///
1200
    /// [`ObjectList`]: crate::object::ObjectList
1201
    pub async fn get_custom_object<Item, ItemErr>(
1202
        &self,
1203
        query: &Query,
1204
    ) -> Result<Objects<Item>, ExtractListError>
1205
    where
1206
        Item: RefineObject<ItemErr>,
1207
        Objects<Item>: InitObject<Item>,
1208
        ItemErr: Error + 'static,
1209
    {
1210
        let mut list = Objects::<Item>::default();
1211

1212
        self.base_object_list2(query, &mut list).await?;
1213

1214
        Ok(list)
1215
    }
1216
}
1217

1218
/// 为 [`base_object_list`] 方法,返回一个统一的 Error
1219
///
1220
/// [`base_object_list`]: crate::client::Client::base_object_list
1221
#[derive(Debug)]
8✔
1222
#[non_exhaustive]
1223
pub struct ExtractListError {
1224
    pub(crate) kind: ExtractListErrorKind,
4✔
1225
}
1226

1227
impl ExtractListError {
1228
    /// 判断 Error 类型是否为 "没有更多信息"
1229
    pub fn is_no_more(&self) -> bool {
×
1230
        matches!(self.kind, ExtractListErrorKind::NoMoreFile)
×
1231
    }
×
1232
}
1233

1234
/// [`ExtractListError`] 类型的枚举
1235
///
1236
/// [`ExtractListError`]: crate::object::ExtractListError
1237
#[derive(Debug)]
4✔
1238
#[non_exhaustive]
1239
pub(crate) enum ExtractListErrorKind {
1240
    #[doc(hidden)]
1241
    Builder(BuilderError),
3✔
1242

1243
    #[doc(hidden)]
1244
    Reqwest(reqwest::Error),
×
1245

1246
    /// 解析 xml 错误
1247
    Decode(InnerListError),
×
1248

1249
    /// 用于 Stream
1250
    NoMoreFile,
1251
}
1252

1253
impl From<InnerListError> for ExtractListError {
1254
    fn from(value: InnerListError) -> Self {
4✔
1255
        use ExtractListErrorKind::*;
1256
        Self {
4✔
1257
            kind: Decode(value),
4✔
1258
        }
1259
    }
4✔
1260
}
1261
impl From<BuilderError> for ExtractListError {
1262
    fn from(value: BuilderError) -> Self {
5✔
1263
        use ExtractListErrorKind::*;
1264
        Self {
5✔
1265
            kind: Builder(value),
5✔
1266
        }
1267
    }
5✔
1268
}
1269
impl From<reqwest::Error> for ExtractListError {
1270
    fn from(value: reqwest::Error) -> Self {
1✔
1271
        use ExtractListErrorKind::*;
1272
        Self {
1✔
1273
            kind: Reqwest(value),
1✔
1274
        }
1275
    }
1✔
1276
}
1277
impl Display for ExtractListError {
1278
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
8✔
1279
        use ExtractListErrorKind::*;
1280
        match &self.kind {
8✔
1281
            Builder(_) => "builder error".fmt(f),
1✔
1282
            Reqwest(_) => "reqwest error".fmt(f),
1✔
1283
            Decode(_) => "decode xml failed".fmt(f),
4✔
1284
            NoMoreFile => "no more file".fmt(f),
2✔
1285
        }
1286
    }
8✔
1287
}
1288
impl Error for ExtractListError {
1289
    fn source(&self) -> Option<&(dyn Error + 'static)> {
7✔
1290
        use ExtractListErrorKind::*;
1291
        match &self.kind {
7✔
1292
            Builder(e) => Some(e),
1✔
1293
            Reqwest(e) => Some(e),
1✔
1294
            Decode(e) => e.get_source(),
4✔
1295
            NoMoreFile => None,
1✔
1296
        }
1297
    }
7✔
1298
}
1299

1300
#[cfg(feature = "blocking")]
1301
impl ClientRc {
1302
    /// 查询默认 bucket 的文件列表
1303
    ///
1304
    /// 查询条件参数有多种方式,具体参考 [`get_object_list`](../bucket/struct.Bucket.html#method.get_object_list) 文档
1305
    pub fn get_object_list<Q: IntoIterator<Item = (QueryKey, QueryValue)>>(
1✔
1306
        self,
1307
        query: Q,
1308
    ) -> Result<ObjectList<RcPointer>, ExtractListError> {
1309
        let name = self.get_bucket_name();
1✔
1310
        let bucket = BucketBase::new(name.clone(), self.get_endpoint().to_owned());
1✔
1311

1312
        let mut list = ObjectList::<RcPointer>::default();
1✔
1313
        list.set_bucket(bucket.clone());
1✔
1314

1315
        let bucket_arc = Rc::new(bucket);
1✔
1316

1317
        let query = Query::from_iter(query);
1✔
1318

1319
        let (bucket_url, resource) = bucket_arc.get_url_resource(&query);
1✔
1320

1321
        let response = self.builder(Method::GET, bucket_url, resource)?;
1✔
1322
        let content = response.send_adjust_error()?;
1✔
1323

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

1326
        list.set_client(Rc::new(self));
1✔
1327
        list.set_search_query(query);
1✔
1328

1329
        Ok(list)
1✔
1330
    }
1✔
1331

1332
    /// 可将 object 列表导出到外部 struct
1333
    #[inline]
1334
    pub fn base_object_list<
1335
        Q: IntoIterator<Item = (QueryKey, QueryValue)>,
1336
        List,
1337
        Item,
1338
        F,
1339
        E: ListError,
1340
        ItemErr: Error + 'static,
1341
    >(
1342
        &self,
1343
        query: Q,
1344
        list: &mut List,
1345
        init_object: F,
1346
    ) -> Result<(), ExtractListError>
1347
    where
1348
        List: RefineObjectList<Item, E, ItemErr>,
1349
        Item: RefineObject<ItemErr>,
1350
        F: Fn(&mut List) -> Option<Item>,
1351
    {
1352
        let bucket = BucketBase::new(self.bucket.clone(), self.get_endpoint().to_owned());
1353

1354
        let query = Query::from_iter(query);
1355
        let (bucket_url, resource) = bucket.get_url_resource(&query);
1356

1357
        let response = self.builder(Method::GET, bucket_url, resource)?;
1358
        let content = response.send_adjust_error()?;
1359

1360
        list.decode(&content.text()?, init_object)?;
1361

1362
        Ok(())
1363
    }
1364
}
1365

1366
#[cfg(feature = "blocking")]
1367
impl Iterator for ObjectList<RcPointer> {
1368
    type Item = ObjectList<RcPointer>;
1369
    fn next(&mut self) -> Option<Self> {
×
1370
        if !self.next_continuation_token.is_empty() {
×
1371
            self.search_query
×
1372
                .insert(CONTINUATION_TOKEN, self.next_continuation_token.to_owned());
×
1373
            self.get_object_list().ok()
×
1374
        } else {
1375
            None
×
1376
        }
1377
    }
×
1378
}
1379

1380
// use std::task::Poll::{self, Ready};
1381

1382
// impl Stream for ObjectList<ArcPointer> {
1383
//     type Item = ObjectList<ArcPointer>;
1384

1385
//     fn poll_next(
1386
//         self: std::pin::Pin<&mut Self>,
1387
//         cx: &mut std::task::Context<'_>,
1388
//     ) -> Poll<Option<Self::Item>> {
1389
//         match self.next_query() {
1390
//             Some(query) => {
1391
//                 let mut url = self.bucket.to_url();
1392
//                 url.set_search_query(&query);
1393

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

1396
//                 let builder = self.builder(Method::GET, url, canonicalized);
1397
//                 match builder {
1398
//                     Err(err) => Ready(None),
1399
//                     Ok(builder) => {
1400
//                         let waker = cx.waker().clone();
1401

1402
//                         std::thread::spawn(move || {
1403
//                             let response = builder.send_adjust_error();
1404

1405
//                             let response = futures::executor::block_on(response);
1406
//                             let text = response.unwrap().text();
1407
//                             let text = futures::executor::block_on(text);
1408

1409
//                             let text = text.unwrap();
1410

1411
//                             let bucket_arc = Arc::new(self.bucket);
1412

1413
//                             let init_object = || {
1414
//                                 let object = Object::<ArcPointer>::default();
1415
//                                 object.base.set_bucket(bucket_arc.clone());
1416
//                                 object
1417
//                             };
1418

1419
//                             self.decode(&text, init_object).unwrap();
1420

1421
//                             self.set_search_query(query);
1422

1423
//                             waker.wake();
1424
//                         });
1425

1426
//                         Poll::Pending
1427
//                     }
1428
//                 }
1429
//             }
1430
//             None => Ready(None),
1431
//         }
1432
//     }
1433
// }
1434

1435
#[oss_gen_rc]
1436
impl PartialEq<Object<ArcPointer>> for Object<ArcPointer> {
1437
    #[inline]
1438
    fn eq(&self, other: &Object<ArcPointer>) -> bool {
8✔
1439
        self.base == other.base
8✔
1440
            && self.last_modified == other.last_modified
6✔
1441
            && self.etag == other.etag
5✔
1442
            && self._type == other._type
4✔
1443
            && self.size == other.size
3✔
1444
            && self.storage_class == other.storage_class
2✔
1445
    }
8✔
1446
}
1447

1448
impl<T: PointerFamily> PartialEq<DateTime<Utc>> for Object<T> {
1449
    #[inline]
1450
    fn eq(&self, other: &DateTime<Utc>) -> bool {
1451
        &self.last_modified == other
1452
    }
1453
}
1454

1455
impl<T: PointerFamily> PartialEq<u64> for Object<T> {
1456
    #[inline]
1457
    fn eq(&self, other: &u64) -> bool {
1458
        &self.size == other
1459
    }
1460
}
1461

1462
#[oss_gen_rc]
1463
impl PartialEq<ObjectBase<ArcPointer>> for Object<ArcPointer> {
1464
    #[inline]
1465
    fn eq(&self, other: &ObjectBase<ArcPointer>) -> bool {
×
1466
        &self.base == other
×
1467
    }
×
1468
}
1469

1470
/// 未来计划支持的功能
1471
#[derive(Default)]
×
1472
#[doc(hidden)]
1473
pub struct PutObject<'a> {
1474
    pub forbid_overwrite: bool,
×
1475
    pub server_side_encryption: Option<Encryption>,
×
1476
    pub server_side_data_encryption: Option<Encryption>,
×
1477
    pub server_side_encryption_key_id: Option<&'a str>,
×
1478
    pub object_acl: ObjectAcl,
×
1479
    pub storage_class: StorageClass,
×
1480
    pub tagging: Option<&'a str>,
×
1481
}
1482

1483
/// 未来计划支持的功能
1484
#[derive(Default)]
×
1485
#[doc(hidden)]
1486
pub enum Encryption {
1487
    #[default]
1488
    Aes256,
1489
    Kms,
1490
    Sm4,
1491
}
1492

1493
/// 未来计划支持的功能
1494
#[derive(Default)]
×
1495
#[doc(hidden)]
1496
pub enum ObjectAcl {
1497
    #[default]
1498
    Default,
1499
    Private,
1500
    PublicRead,
1501
    PublicReadWrite,
1502
}
1503

1504
/// 存储类型
1505
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
72✔
1506
#[non_exhaustive]
1507
pub struct StorageClass {
1508
    kind: StorageClassKind,
36✔
1509
}
1510

1511
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
44✔
1512
#[non_exhaustive]
1513
enum StorageClassKind {
1514
    /// Standard 默认
1515
    #[default]
1516
    Standard,
1517
    /// IA
1518
    IA,
1519
    /// Archive
1520
    Archive,
1521
    /// ColdArchive
1522
    ColdArchive,
1523
}
1524

1525
impl StorageClass {
1526
    /// Archive
1527
    pub const ARCHIVE: Self = Self {
1528
        kind: StorageClassKind::Archive,
1529
    };
1530
    /// IA
1531
    pub const IA: Self = Self {
1532
        kind: StorageClassKind::IA,
1533
    };
1534
    /// Standard
1535
    pub const STANDARD: Self = Self {
1536
        kind: StorageClassKind::Standard,
1537
    };
1538
    /// ColdArchive
1539
    pub const COLD_ARCHIVE: Self = Self {
1540
        kind: StorageClassKind::ColdArchive,
1541
    };
1542

1543
    /// init StorageClass
1544
    pub fn new(s: &str) -> Option<StorageClass> {
23✔
1545
        let start_char = s.chars().next()?;
23✔
1546

1547
        let kind = match start_char {
22✔
1548
            'a' | 'A' => StorageClassKind::Archive,
4✔
1549
            'i' | 'I' => StorageClassKind::IA,
2✔
1550
            's' | 'S' => StorageClassKind::Standard,
10✔
1551
            'c' | 'C' => StorageClassKind::ColdArchive,
2✔
1552
            _ => return None,
4✔
1553
        };
1554
        Some(Self { kind })
18✔
1555
    }
23✔
1556
}
1557

1558
/// 未来计划支持的功能
1559
#[derive(Default)]
×
1560
#[doc(hidden)]
1561
pub struct CopyObject<'a> {
1562
    pub forbid_overwrite: bool,
×
1563
    pub copy_source: &'a str,
×
1564
    pub copy_source_if_match: Option<&'a str>,
×
1565
    pub copy_source_if_none_match: Option<&'a str>,
×
1566
    pub copy_source_if_unmodified_since: Option<&'a str>,
×
1567
    pub copy_source_if_modified_since: Option<&'a str>,
×
1568
    pub metadata_directive: CopyDirective,
×
1569
    pub server_side_encryption: Option<Encryption>,
×
1570
    pub server_side_encryption_key_id: Option<&'a str>,
×
1571
    pub object_acl: ObjectAcl,
×
1572
    pub storage_class: StorageClass,
×
1573
    pub tagging: Option<&'a str>,
×
1574
    pub tagging_directive: CopyDirective,
×
1575
}
1576

1577
/// 未来计划支持的功能
1578
#[derive(Default)]
×
1579
#[doc(hidden)]
1580
pub enum CopyDirective {
1581
    #[default]
1582
    Copy,
1583
    Replace,
1584
}
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