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

tu6ge / oss-rs / 5829505807

pending completion
5829505807

push

github

tu6ge
Support std IO (#26)

* feat(decode)!: change init object fn

* todo

* feat(error): OssError add more info

when OssError code is SignatureDoesNotMatch ,show expect
 sign string

* feat(io): support write

* feat: blocking support

* feat: blocking read

* feat: 允许读取的数据于目标数组长度不一致

* feat: 分离 Rc 和内部数据

* feat: support Arc Object Content

* feat: 解决多次写入少量数据导致oss错误的问题

当多次写入少量数据,不符合分片的最小数量时,调用 oss 接口会导致报错

* refactor

* feat: 交互 arc 与 rc 的位置

* docs(io)

* docs(io)

* style

* chore: default close blocking

* fix

* style

* feat(io): change seek

* feat(io): change error type

* style

* feat(bucket)!: change base_bucket_info

* test(io)

* test(doc): remove deprecated

* test(io)

* test(io)

* test(io)

* style(io): clippy

* chore: support more derive

* refactor

* docs

1293 of 1293 new or added lines in 19 files covered. (100.0%)

7298 of 7685 relevant lines covered (94.96%)

9.62 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::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
pub use content::Content;
99

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1032
impl ListError for ObjectListError {}
1033

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1215
        Ok(())
1216
    }
1217

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

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

1235
        Ok(list)
1236
    }
1237
}
1238

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1375
        let query = Query::from_iter(query);
1376
        let (bucket_url, resource) = bucket.get_url_resource(&query);
1377

1378
        let response = self.builder(Method::GET, bucket_url, resource)?;
1379
        let content = response.send_adjust_error()?;
1380

1381
        list.decode(&content.text()?, init_object)?;
1382

1383
        Ok(())
1384
    }
1385
}
1386

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

1401
// use std::task::Poll::{self, Ready};
1402

1403
// impl Stream for ObjectList<ArcPointer> {
1404
//     type Item = ObjectList<ArcPointer>;
1405

1406
//     fn poll_next(
1407
//         self: std::pin::Pin<&mut Self>,
1408
//         cx: &mut std::task::Context<'_>,
1409
//     ) -> Poll<Option<Self::Item>> {
1410
//         match self.next_query() {
1411
//             Some(query) => {
1412
//                 let mut url = self.bucket.to_url();
1413
//                 url.set_search_query(&query);
1414

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

1417
//                 let builder = self.builder(Method::GET, url, canonicalized);
1418
//                 match builder {
1419
//                     Err(err) => Ready(None),
1420
//                     Ok(builder) => {
1421
//                         let waker = cx.waker().clone();
1422

1423
//                         std::thread::spawn(move || {
1424
//                             let response = builder.send_adjust_error();
1425

1426
//                             let response = futures::executor::block_on(response);
1427
//                             let text = response.unwrap().text();
1428
//                             let text = futures::executor::block_on(text);
1429

1430
//                             let text = text.unwrap();
1431

1432
//                             let bucket_arc = Arc::new(self.bucket);
1433

1434
//                             let init_object = || {
1435
//                                 let object = Object::<ArcPointer>::default();
1436
//                                 object.base.set_bucket(bucket_arc.clone());
1437
//                                 object
1438
//                             };
1439

1440
//                             self.decode(&text, init_object).unwrap();
1441

1442
//                             self.set_search_query(query);
1443

1444
//                             waker.wake();
1445
//                         });
1446

1447
//                         Poll::Pending
1448
//                     }
1449
//                 }
1450
//             }
1451
//             None => Ready(None),
1452
//         }
1453
//     }
1454
// }
1455

1456
#[oss_gen_rc]
1457
impl PartialEq<Object<ArcPointer>> for Object<ArcPointer> {
1458
    #[inline]
1459
    fn eq(&self, other: &Object<ArcPointer>) -> bool {
8✔
1460
        self.base == other.base
8✔
1461
            && self.last_modified == other.last_modified
6✔
1462
            && self.etag == other.etag
5✔
1463
            && self._type == other._type
4✔
1464
            && self.size == other.size
3✔
1465
            && self.storage_class == other.storage_class
2✔
1466
    }
8✔
1467
}
1468

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

1476
impl<T: PointerFamily> PartialEq<u64> for Object<T> {
1477
    #[inline]
1478
    fn eq(&self, other: &u64) -> bool {
1479
        &self.size == other
1480
    }
1481
}
1482

1483
#[oss_gen_rc]
1484
impl PartialEq<ObjectBase<ArcPointer>> for Object<ArcPointer> {
1485
    #[inline]
1486
    fn eq(&self, other: &ObjectBase<ArcPointer>) -> bool {
×
1487
        &self.base == other
×
1488
    }
×
1489
}
1490

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

1504
/// 未来计划支持的功能
1505
#[derive(Default)]
×
1506
#[doc(hidden)]
1507
pub enum Encryption {
1508
    #[default]
1509
    Aes256,
1510
    Kms,
1511
    Sm4,
1512
}
1513

1514
/// 未来计划支持的功能
1515
#[derive(Default)]
×
1516
#[doc(hidden)]
1517
pub enum ObjectAcl {
1518
    #[default]
1519
    Default,
1520
    Private,
1521
    PublicRead,
1522
    PublicReadWrite,
1523
}
1524

1525
/// 存储类型
1526
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
72✔
1527
#[non_exhaustive]
1528
pub struct StorageClass {
1529
    kind: StorageClassKind,
36✔
1530
}
1531

1532
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
44✔
1533
#[non_exhaustive]
1534
enum StorageClassKind {
1535
    /// Standard 默认
1536
    #[default]
1537
    Standard,
1538
    /// IA
1539
    IA,
1540
    /// Archive
1541
    Archive,
1542
    /// ColdArchive
1543
    ColdArchive,
1544
}
1545

1546
impl StorageClass {
1547
    /// Archive
1548
    pub const ARCHIVE: Self = Self {
1549
        kind: StorageClassKind::Archive,
1550
    };
1551
    /// IA
1552
    pub const IA: Self = Self {
1553
        kind: StorageClassKind::IA,
1554
    };
1555
    /// Standard
1556
    pub const STANDARD: Self = Self {
1557
        kind: StorageClassKind::Standard,
1558
    };
1559
    /// ColdArchive
1560
    pub const COLD_ARCHIVE: Self = Self {
1561
        kind: StorageClassKind::ColdArchive,
1562
    };
1563

1564
    /// init StorageClass
1565
    pub fn new(s: &str) -> Option<StorageClass> {
23✔
1566
        let start_char = s.chars().next()?;
23✔
1567

1568
        let kind = match start_char {
22✔
1569
            'a' | 'A' => StorageClassKind::Archive,
4✔
1570
            'i' | 'I' => StorageClassKind::IA,
2✔
1571
            's' | 'S' => StorageClassKind::Standard,
10✔
1572
            'c' | 'C' => StorageClassKind::ColdArchive,
2✔
1573
            _ => return None,
4✔
1574
        };
1575
        Some(Self { kind })
18✔
1576
    }
23✔
1577
}
1578

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

1598
/// 未来计划支持的功能
1599
#[derive(Default)]
×
1600
#[doc(hidden)]
1601
pub enum CopyDirective {
1602
    #[default]
1603
    Copy,
1604
    Replace,
1605
}
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