use crate::bucket::Bucket;
#[cfg(feature = "blocking")]
use crate::builder::RcPointer;
use crate::builder::{ArcPointer, BuilderError, PointerFamily};
use crate::client::ClientArc;
#[cfg(feature = "blocking")]
use crate::client::ClientRc;
use crate::config::{get_url_resource_with_bucket, BucketBase};
use crate::decode::{InnerListError, ListError, RefineObject, RefineObjectList};
#[cfg(feature = "blocking")]
use crate::file::blocking::AlignBuilder as BlockingAlignBuilder;
use crate::file::AlignBuilder;
use crate::types::object::ObjectPathInner;
use crate::types::{
core::SetOssQuery,
object::{
CommonPrefixes, InvalidObjectDir, InvalidObjectPath, ObjectBase, ObjectDir, ObjectPath,
},
CanonicalizedResource, Query, QueryKey, QueryValue, CONTINUATION_TOKEN,
};
use crate::{BucketName, Client, EndPoint, KeyId, KeySecret};
use async_stream::try_stream;
use chrono::{DateTime, NaiveDateTime, Utc};
use futures_core::stream::Stream;
use http::Method;
use oss_derive::oss_gen_rc;
use url::Url;
#[cfg(feature = "blocking")]
use std::rc::Rc;
use std::{
error::Error,
fmt::{self, Display},
marker::PhantomData,
num::ParseIntError,
slice::{Iter, IterMut},
sync::Arc,
vec::IntoIter,
};
#[cfg(test)]
mod test;
#[derive(Clone)]
#[non_exhaustive]
pub struct ObjectList<
P: PointerFamily = ArcPointer,
Item: RefineObject<E> = Object<P>,
E: Error + 'static = BuildInItemError,
> {
pub(crate) bucket: BucketBase,
prefix: Option<ObjectDir<'static>>,
max_keys: u32,
key_count: u64,
object_list: Vec<Item>,
next_continuation_token: String,
common_prefixes: CommonPrefixes,
client: P::PointerType,
search_query: Query,
ph_err: PhantomData<E>,
}
pub type Objects<Item = Object<ArcPointer>, Error = BuildInItemError> =
ObjectList<ArcPointer, Item, Error>;
#[cfg(feature = "blocking")]
pub type ObjectsBlocking<Item = Object<RcPointer>, Error = BuildInItemError> =
ObjectList<RcPointer, Item, Error>;
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct Object<PointerSel: PointerFamily = ArcPointer> {
pub(crate) base: ObjectBase<PointerSel>,
last_modified: DateTime<Utc>,
etag: String,
_type: String,
size: u64,
storage_class: StorageClass,
}
pub type ObjectArc = Object<ArcPointer>;
impl<T: PointerFamily, Item: RefineObject<E>, E: Error> fmt::Debug for ObjectList<T, Item, E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("ObjectList")
.field("bucket", &self.bucket)
.field("prefix", &self.prefix)
.field("max_keys", &self.max_keys)
.field("key_count", &self.key_count)
.field("next_continuation_token", &self.next_continuation_token)
.field("common_prefixes", &self.common_prefixes)
.field("search_query", &self.search_query)
.finish()
}
}
#[oss_gen_rc]
impl<Item: RefineObject<E>, E: Error> Default for ObjectList<ArcPointer, Item, E> {
fn default() -> Self {
Self {
bucket: BucketBase::default(),
prefix: Option::default(),
max_keys: u32::default(),
key_count: u64::default(),
object_list: Vec::new(),
next_continuation_token: String::default(),
common_prefixes: CommonPrefixes::default(),
client: Arc::new(ClientArc::default()),
search_query: Query::default(),
ph_err: PhantomData,
}
}
}
impl<T: PointerFamily, Item: RefineObject<E>, E: Error> AsMut<Query> for ObjectList<T, Item, E> {
fn as_mut(&mut self) -> &mut Query {
&mut self.search_query
}
}
impl<T: PointerFamily, Item: RefineObject<E>, E: Error> AsRef<BucketBase>
for ObjectList<T, Item, E>
{
fn as_ref(&self) -> &BucketBase {
&self.bucket
}
}
impl<T: PointerFamily, Item: RefineObject<E>, E: Error> AsRef<BucketName>
for ObjectList<T, Item, E>
{
fn as_ref(&self) -> &BucketName {
self.bucket.as_ref()
}
}
impl<T: PointerFamily, Item: RefineObject<E>, E: Error> AsRef<EndPoint> for ObjectList<T, Item, E> {
fn as_ref(&self) -> &EndPoint {
self.bucket.as_ref()
}
}
impl<T: PointerFamily, Item: RefineObject<E>, E: Error> ObjectList<T, Item, E> {
#[allow(clippy::too_many_arguments)]
pub fn new<Q: IntoIterator<Item = (QueryKey, QueryValue)>>(
bucket: BucketBase,
prefix: Option<ObjectDir<'static>>,
max_keys: u32,
key_count: u64,
object_list: Vec<Item>,
next_continuation_token: Option<String>,
client: T::PointerType,
search_query: Q,
) -> Self {
Self {
bucket,
prefix,
max_keys,
key_count,
object_list,
next_continuation_token: next_continuation_token.unwrap_or_default(),
common_prefixes: CommonPrefixes::default(),
client,
search_query: Query::from_iter(search_query),
ph_err: PhantomData,
}
}
pub fn bucket(&self) -> &BucketBase {
&self.bucket
}
pub fn prefix(&self) -> &Option<ObjectDir<'static>> {
&self.prefix
}
pub fn common_prefixes(&self) -> &CommonPrefixes {
&self.common_prefixes
}
pub fn set_common_prefixes<P: IntoIterator<Item = ObjectDir<'static>>>(&mut self, prefixes: P) {
self.common_prefixes = CommonPrefixes::from_iter(prefixes);
}
pub fn max_keys(&self) -> &u32 {
&self.max_keys
}
pub fn key_count(&self) -> &u64 {
&self.key_count
}
pub fn next_continuation_token_str(&self) -> &String {
&self.next_continuation_token
}
pub fn search_query(&self) -> &Query {
&self.search_query
}
pub fn next_query(&self) -> Option<Query> {
if !self.next_continuation_token.is_empty() {
let mut search_query = self.search_query.clone();
search_query.insert(CONTINUATION_TOKEN, self.next_continuation_token.to_owned());
Some(search_query)
} else {
None
}
}
pub fn object_iter(self) -> IntoIter<Item> {
self.object_list.into_iter()
}
pub fn object_into_iter(self) -> IntoIter<Item> {
self.object_list.into_iter()
}
pub fn object_iter2(&self) -> Iter<Item> {
self.object_list.iter()
}
pub fn object_iter_mut(&mut self) -> IterMut<Item> {
self.object_list.iter_mut()
}
}
#[oss_gen_rc]
impl<Item: RefineObject<E>, E: Error> ObjectList<ArcPointer, Item, E> {
pub(crate) fn set_client(&mut self, client: Arc<ClientArc>) {
self.client = client;
}
pub(crate) fn from_bucket(
bucket: &Bucket<ArcPointer>,
capacity: usize,
) -> ObjectList<ArcPointer> {
ObjectList::<ArcPointer> {
bucket: bucket.base.clone(),
client: Arc::clone(&bucket.client),
object_list: Vec::with_capacity(capacity),
..Default::default()
}
}
pub(crate) fn client(&self) -> Arc<ClientArc> {
Arc::clone(&self.client)
}
}
impl ObjectList<ArcPointer> {
pub async fn get_next_list(&self) -> Result<ObjectList<ArcPointer>, ExtractListError> {
match self.next_query() {
None => Err(ExtractListError {
kind: ExtractListErrorKind::NoMoreFile,
}),
Some(query) => {
let mut url = self.bucket.to_url();
url.set_oss_query(&query);
let canonicalized = CanonicalizedResource::from_bucket_query(&self.bucket, &query);
let response = self
.builder(Method::GET, url, canonicalized)?
.send_adjust_error()
.await?;
let mut list = ObjectList::<ArcPointer> {
client: self.client(),
bucket: self.bucket.clone(),
object_list: Vec::with_capacity(query.get_max_keys()),
..Default::default()
};
list.decode(&response.text().await?, || {
Object::from_bucket(Arc::new(self.bucket.clone()))
})?;
list.set_search_query(query);
Ok(list)
}
}
}
pub fn into_stream(self) -> impl Stream<Item = Result<Self, ExtractListError>> {
try_stream! {
let result = self.get_next_list().await?;
yield result;
}
}
}
impl<Item: RefineObject<E>, E: Error + 'static> ObjectList<ArcPointer, Item, E> {
pub async fn get_next_base<F>(&self, init_object: F) -> Result<Self, ExtractListError>
where
F: FnMut() -> Item,
{
match self.next_query() {
None => Err(ExtractListError {
kind: ExtractListErrorKind::NoMoreFile,
}),
Some(query) => {
let mut list = Self::default();
let name = self.bucket.get_name().clone();
self.client()
.base_object_list(name, query, &mut list, init_object)
.await?;
Ok(list)
}
}
}
}
#[cfg(feature = "blocking")]
impl ObjectList<RcPointer> {
fn clone_base(&self) -> Self {
Self {
client: Rc::clone(&self.client),
bucket: self.bucket.clone(),
search_query: self.search_query.clone(),
max_keys: self.max_keys,
object_list: Vec::with_capacity(self.max_keys as usize),
..Default::default()
}
}
pub fn get_object_list(&mut self) -> Result<Self, ExtractListError> {
let name = self.bucket.get_name();
let client = self.client();
let mut list = ObjectList::<RcPointer>::clone_base(self);
let init_object = || Object::<RcPointer>::from_bucket(Rc::new(self.bucket.clone()));
client
.base_object_list(
name.to_owned(),
self.search_query.clone(),
&mut list,
init_object,
)
.map_err(ExtractListError::from)?;
Ok(list)
}
}
impl<T: PointerFamily, Item: RefineObject<E>, E: Error + 'static> ObjectList<T, Item, E> {
#[inline]
pub fn set_search_query(&mut self, search_query: Query) {
self.search_query = search_query;
}
pub fn set_bucket(&mut self, bucket: BucketBase) {
self.bucket = bucket;
}
pub fn bucket_name(&self) -> &str {
self.bucket.name()
}
pub fn to_vec(self) -> Vec<Item> {
self.object_list
}
pub fn len(&self) -> usize {
self.object_list.len()
}
pub fn is_empty(&self) -> bool {
self.object_list.is_empty()
}
}
impl<T: PointerFamily> Default for Object<T> {
fn default() -> Self {
Object {
base: ObjectBase::<T>::default(),
last_modified: DateTime::<Utc>::from_utc(
#[allow(clippy::unwrap_used)]
NaiveDateTime::from_timestamp_opt(0, 0).unwrap(),
Utc,
),
etag: String::default(),
_type: String::default(),
size: 0,
storage_class: StorageClass::default(),
}
}
}
impl<T: PointerFamily> AsRef<ObjectPath> for Object<T> {
fn as_ref(&self) -> &ObjectPath {
self.base.as_ref()
}
}
impl<T: PointerFamily> AsRef<DateTime<Utc>> for Object<T> {
fn as_ref(&self) -> &DateTime<Utc> {
&self.last_modified
}
}
impl<T: PointerFamily> AsRef<StorageClass> for Object<T> {
fn as_ref(&self) -> &StorageClass {
&self.storage_class
}
}
impl<T: PointerFamily> Object<T> {
pub fn new(
bucket: T::Bucket,
path: ObjectPath,
last_modified: DateTime<Utc>,
etag: String,
_type: String,
size: u64,
storage_class: StorageClass,
) -> Self {
let base = ObjectBase::<T>::new2(bucket, path);
Self {
base,
last_modified,
etag,
_type,
size,
storage_class,
}
}
pub(crate) fn from_bucket(bucket: T::Bucket) -> Self {
Self {
base: ObjectBase::<T>::init_with_bucket(bucket),
..Default::default()
}
}
#[inline]
pub fn base(&self) -> &ObjectBase<T> {
&self.base
}
#[inline]
pub fn set_base(&mut self, base: ObjectBase<T>) {
self.base = base;
}
#[inline]
pub fn last_modified(&self) -> &DateTime<Utc> {
&self.last_modified
}
#[inline]
pub fn set_last_modified(&mut self, last_modified: DateTime<Utc>) {
self.last_modified = last_modified;
}
#[inline]
pub fn etag(&self) -> &String {
&self.etag
}
#[inline]
pub fn set_etag(&mut self, etag: String) {
self.etag = etag
}
#[inline]
pub fn get_type_string(&self) -> &String {
&self._type
}
#[inline]
pub fn set_type_string(&mut self, _type: String) {
self._type = _type;
}
#[inline]
pub fn size(&self) -> u64 {
self.size
}
#[inline]
pub fn set_size(&mut self, size: u64) {
self.size = size;
}
#[inline]
pub fn storage_class(&self) -> &StorageClass {
&self.storage_class
}
#[inline]
pub fn set_storage_class(&mut self, storage_class: StorageClass) {
self.storage_class = storage_class;
}
pub fn pieces(
self,
) -> (
ObjectBase<T>,
DateTime<Utc>,
String,
String,
u64,
StorageClass,
) {
(
self.base,
self.last_modified,
self.etag,
self._type,
self.size,
self.storage_class,
)
}
pub fn path(&self) -> ObjectPath {
self.base.path()
}
#[doc(hidden)]
pub fn path_string(&self) -> String {
self.base.path().to_string()
}
}
impl Object<ArcPointer> {
#[cfg(test)]
pub fn test_path(path: &'static str) -> Self {
let mut object = Self::default();
object.set_base(ObjectBase::<ArcPointer>::new2(
Arc::new(BucketBase::default()),
path.try_into().unwrap(),
));
object
}
}
impl<T: PointerFamily> From<Object<T>> for ObjectPathInner<'static> {
#[inline]
fn from(obj: Object<T>) -> Self {
obj.base.path
}
}
#[oss_gen_rc]
impl Object<ArcPointer> {
pub fn builder(path: ObjectPath) -> ObjectBuilder<ArcPointer> {
ObjectBuilder::<ArcPointer>::new(Arc::default(), path)
}
pub fn to_sign_url(&self, key: &KeyId, secret: &KeySecret, expires: i64) -> Url {
self.base.to_sign_url(key, secret, expires)
}
}
pub struct ObjectBuilder<T: PointerFamily = ArcPointer> {
object: Object<T>,
}
impl<T: PointerFamily> ObjectBuilder<T> {
pub fn new(bucket: T::Bucket, path: ObjectPath) -> Self {
let base = ObjectBase::<T>::new2(bucket, path);
Self {
object: Object {
base,
last_modified: DateTime::<Utc>::from_utc(
#[allow(clippy::unwrap_used)]
NaiveDateTime::from_timestamp_opt(0, 0).unwrap(),
Utc,
),
etag: String::default(),
_type: String::default(),
size: 0,
storage_class: StorageClass::default(),
},
}
}
pub fn bucket(&mut self, bucket: T::Bucket) -> &mut Self {
self.object.base.set_bucket(bucket);
self
}
pub fn last_modified(&mut self, date: DateTime<Utc>) -> &mut Self {
self.object.last_modified = date;
self
}
pub fn etag(&mut self, etag: String) -> &mut Self {
self.object.etag = etag;
self
}
pub fn set_type(&mut self, _type: String) -> &mut Self {
self.object._type = _type;
self
}
pub fn size(&mut self, size: u64) -> &mut Self {
self.object.size = size;
self
}
pub fn storage_class(&mut self, storage_class: StorageClass) -> &mut Self {
self.object.storage_class = storage_class;
self
}
pub fn build(self) -> Object<T> {
self.object
}
}
#[oss_gen_rc]
impl ObjectBuilder<ArcPointer> {
pub fn bucket_base(&mut self, base: BucketBase) -> &mut Self {
self.object.base.set_bucket(Arc::new(base));
self
}
}
impl<T: PointerFamily + Sized> RefineObject<BuildInItemError> for Object<T> {
#[inline]
fn set_key(&mut self, key: &str) -> Result<(), BuildInItemError> {
self.base
.set_path(key.to_owned())
.map_err(|e| BuildInItemError {
source: key.to_string(),
kind: BuildInItemErrorKind::BasePath(e),
})
}
#[inline]
fn set_last_modified(&mut self, value: &str) -> Result<(), BuildInItemError> {
self.last_modified = value.parse().map_err(|e| BuildInItemError {
source: value.to_string(),
kind: BuildInItemErrorKind::LastModified(e),
})?;
Ok(())
}
#[inline]
fn set_etag(&mut self, value: &str) -> Result<(), BuildInItemError> {
self.etag = value.to_string();
Ok(())
}
#[inline]
fn set_type(&mut self, value: &str) -> Result<(), BuildInItemError> {
self._type = value.to_string();
Ok(())
}
#[inline]
fn set_size(&mut self, size: &str) -> Result<(), BuildInItemError> {
self.size = size.parse().map_err(|e| BuildInItemError {
source: size.to_string(),
kind: BuildInItemErrorKind::Size(e),
})?;
Ok(())
}
#[inline]
fn set_storage_class(&mut self, storage_class: &str) -> Result<(), BuildInItemError> {
self.storage_class = StorageClass::new(storage_class).ok_or(BuildInItemError {
source: storage_class.to_string(),
kind: BuildInItemErrorKind::InvalidStorageClass,
})?;
Ok(())
}
}
#[derive(Debug)]
#[non_exhaustive]
pub struct BuildInItemError {
source: String,
kind: BuildInItemErrorKind,
}
impl BuildInItemError {
#[cfg(test)]
pub(crate) fn test_new() -> Self {
Self {
source: "foo".to_string(),
kind: BuildInItemErrorKind::InvalidStorageClass,
}
}
}
impl Display for BuildInItemError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use BuildInItemErrorKind::*;
let kind = match &self.kind {
Size(_) => "size",
BasePath(_) => "base-path",
LastModified(_) => "last-modified",
InvalidStorageClass => "storage-class",
};
write!(f, "parse {kind} failed, gived str: {}", self.source)
}
}
impl Error for BuildInItemError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
use BuildInItemErrorKind::*;
match &self.kind {
Size(e) => Some(e),
BasePath(e) => Some(e),
LastModified(e) => Some(e),
InvalidStorageClass => None,
}
}
}
#[derive(Debug)]
#[non_exhaustive]
enum BuildInItemErrorKind {
Size(ParseIntError),
BasePath(InvalidObjectPath),
LastModified(chrono::ParseError),
InvalidStorageClass,
}
impl<P: PointerFamily, Item: RefineObject<E>, E: Error + 'static>
RefineObjectList<Item, ObjectListError, E> for ObjectList<P, Item, E>
{
#[inline]
fn set_key_count(&mut self, key_count: &str) -> Result<(), ObjectListError> {
self.key_count = key_count.parse().map_err(|e| ObjectListError {
source: key_count.to_owned(),
kind: ObjectListErrorKind::KeyCount(e),
})?;
Ok(())
}
#[inline]
fn set_prefix(&mut self, prefix: &str) -> Result<(), ObjectListError> {
if prefix.is_empty() {
self.prefix = None;
} else {
let mut string = String::from(prefix);
string += "/";
self.prefix = Some(string.parse().map_err(|e| ObjectListError {
source: prefix.to_owned(),
kind: ObjectListErrorKind::Prefix(e),
})?)
}
Ok(())
}
#[inline]
fn set_common_prefix(
&mut self,
list: &[std::borrow::Cow<'_, str>],
) -> Result<(), ObjectListError> {
for val in list.iter() {
self.common_prefixes
.push(val.parse().map_err(|e| ObjectListError {
source: val.to_string(),
kind: ObjectListErrorKind::CommonPrefix(e),
})?);
}
Ok(())
}
#[inline]
fn set_max_keys(&mut self, max_keys: &str) -> Result<(), ObjectListError> {
self.max_keys = max_keys.parse().map_err(|e| ObjectListError {
source: max_keys.to_string(),
kind: ObjectListErrorKind::MaxKeys(e),
})?;
Ok(())
}
#[inline]
fn set_next_continuation_token_str(&mut self, token: &str) -> Result<(), ObjectListError> {
self.next_continuation_token = token.to_owned();
Ok(())
}
#[inline]
fn set_list(&mut self, list: Vec<Item>) -> Result<(), ObjectListError> {
self.object_list = list;
Ok(())
}
}
#[derive(Debug)]
#[non_exhaustive]
pub struct ObjectListError {
source: String,
kind: ObjectListErrorKind,
}
impl ObjectListError {
#[cfg(test)]
pub(crate) fn test_new() -> Self {
Self {
source: "foo".to_string(),
kind: ObjectListErrorKind::Bar,
}
}
}
impl Display for ObjectListError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use ObjectListErrorKind::*;
let kind: &str = match &self.kind {
KeyCount(_) => "key-count",
Prefix(_) => "prefix",
CommonPrefix(_) => "common-prefix",
MaxKeys(_) => "max-keys",
#[cfg(test)]
Bar => "bar",
};
write!(f, "parse {kind} failed, gived str: {}", self.source)
}
}
impl Error for ObjectListError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
use ObjectListErrorKind::*;
match &self.kind {
KeyCount(e) | MaxKeys(e) => Some(e),
Prefix(e) | CommonPrefix(e) => Some(e),
#[cfg(test)]
Bar => None,
}
}
}
impl ListError for ObjectListError {}
#[derive(Debug)]
#[non_exhaustive]
enum ObjectListErrorKind {
KeyCount(ParseIntError),
Prefix(InvalidObjectDir),
CommonPrefix(InvalidObjectDir),
MaxKeys(ParseIntError),
#[cfg(test)]
Bar,
}
impl Client {
#[inline(always)]
pub async fn get_object_list<Q: IntoIterator<Item = (QueryKey, QueryValue)>>(
&self,
query: Q,
) -> Result<ObjectList, ExtractListError> {
self.get_object_list2(Query::from_iter(query)).await
}
pub async fn get_object_list2(&self, query: Query) -> Result<ObjectList, ExtractListError> {
let bucket = BucketBase::new(self.bucket.to_owned(), self.endpoint.to_owned());
let (bucket_url, resource) = bucket.get_url_resource(&query);
let bucket_arc = Arc::new(bucket.clone());
let mut list = ObjectList::<ArcPointer> {
object_list: Vec::with_capacity(query.get_max_keys()),
bucket,
..Default::default()
};
let response = self.builder(Method::GET, bucket_url, resource)?;
let content = response.send_adjust_error().await?;
list.decode(&content.text().await?, || {
Object::from_bucket(bucket_arc.clone())
})?;
list.set_client(Arc::new(self.clone()));
list.set_search_query(query);
Ok(list)
}
#[inline]
pub async fn base_object_list<
Name: Into<BucketName>,
Q: IntoIterator<Item = (QueryKey, QueryValue)>,
List,
Item,
F,
E: ListError,
ItemErr: Error + 'static,
>(
&self,
name: Name,
query: Q,
list: &mut List,
init_object: F,
) -> Result<(), ExtractListError>
where
List: RefineObjectList<Item, E, ItemErr>,
Item: RefineObject<ItemErr>,
F: FnMut() -> Item,
{
let query = Query::from_iter(query);
let name = name.into();
self.base_object_list2(&name, &query, list, init_object)
.await
}
pub async fn base_object_list2<List, Item, F, E: ListError, ItemErr: Error + 'static>(
&self,
name: &BucketName,
query: &Query,
list: &mut List,
init_object: F,
) -> Result<(), ExtractListError>
where
List: RefineObjectList<Item, E, ItemErr>,
Item: RefineObject<ItemErr>,
F: FnMut() -> Item,
{
let (bucket_url, resource) = get_url_resource_with_bucket(self.as_ref(), name, query);
let response = self.builder(Method::GET, bucket_url, resource)?;
let content = response.send_adjust_error().await?;
list.decode(&content.text().await?, init_object)?;
Ok(())
}
}
#[derive(Debug)]
#[non_exhaustive]
pub struct ExtractListError {
pub(crate) kind: ExtractListErrorKind,
}
#[derive(Debug)]
#[non_exhaustive]
pub(crate) enum ExtractListErrorKind {
#[doc(hidden)]
Builder(BuilderError),
#[doc(hidden)]
Reqwest(reqwest::Error),
Decode(InnerListError),
NoMoreFile,
}
impl From<InnerListError> for ExtractListError {
fn from(value: InnerListError) -> Self {
use ExtractListErrorKind::*;
Self {
kind: Decode(value),
}
}
}
impl From<BuilderError> for ExtractListError {
fn from(value: BuilderError) -> Self {
use ExtractListErrorKind::*;
Self {
kind: Builder(value),
}
}
}
impl From<reqwest::Error> for ExtractListError {
fn from(value: reqwest::Error) -> Self {
use ExtractListErrorKind::*;
Self {
kind: Reqwest(value),
}
}
}
impl Display for ExtractListError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use ExtractListErrorKind::*;
match &self.kind {
Builder(_) => "builder error".fmt(f),
Reqwest(_) => "reqwest error".fmt(f),
Decode(_) => "decode xml failed".fmt(f),
NoMoreFile => "no more file".fmt(f),
}
}
}
impl Error for ExtractListError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
use ExtractListErrorKind::*;
match &self.kind {
Builder(e) => Some(e),
Reqwest(e) => Some(e),
Decode(e) => e.get_source(),
NoMoreFile => None,
}
}
}
#[cfg(feature = "blocking")]
impl ClientRc {
pub fn get_object_list<Q: IntoIterator<Item = (QueryKey, QueryValue)>>(
self,
query: Q,
) -> Result<ObjectList<RcPointer>, ExtractListError> {
let name = self.get_bucket_name();
let bucket = BucketBase::new(name.clone(), self.get_endpoint().to_owned());
let mut list = ObjectList::<RcPointer>::default();
list.set_bucket(bucket.clone());
let bucket_arc = Rc::new(bucket);
let query = Query::from_iter(query);
let (bucket_url, resource) = bucket_arc.get_url_resource(&query);
let response = self.builder(Method::GET, bucket_url, resource)?;
let content = response.send_adjust_error()?;
list.decode(&content.text()?, || {
Object::<RcPointer>::from_bucket(bucket_arc.clone())
})?;
list.set_client(Rc::new(self));
list.set_search_query(query);
Ok(list)
}
#[inline]
pub fn base_object_list<
Name: Into<BucketName>,
Q: IntoIterator<Item = (QueryKey, QueryValue)>,
List,
Item,
F,
E: ListError,
ItemErr: Error + 'static,
>(
&self,
name: Name,
query: Q,
list: &mut List,
init_object: F,
) -> Result<(), ExtractListError>
where
List: RefineObjectList<Item, E, ItemErr>,
Item: RefineObject<ItemErr>,
F: FnMut() -> Item,
{
let bucket = BucketBase::new(name.into(), self.get_endpoint().to_owned());
let query = Query::from_iter(query);
let (bucket_url, resource) = bucket.get_url_resource(&query);
let response = self.builder(Method::GET, bucket_url, resource)?;
let content = response.send_adjust_error()?;
list.decode(&content.text()?, init_object)?;
Ok(())
}
}
#[cfg(feature = "blocking")]
impl Iterator for ObjectList<RcPointer> {
type Item = ObjectList<RcPointer>;
fn next(&mut self) -> Option<Self> {
if !self.next_continuation_token.is_empty() {
self.search_query
.insert(CONTINUATION_TOKEN, self.next_continuation_token.to_owned());
self.get_object_list().ok()
} else {
None
}
}
}
#[oss_gen_rc]
impl PartialEq<Object<ArcPointer>> for Object<ArcPointer> {
#[inline]
fn eq(&self, other: &Object<ArcPointer>) -> bool {
self.base == other.base
&& self.last_modified == other.last_modified
&& self.etag == other.etag
&& self._type == other._type
&& self.size == other.size
&& self.storage_class == other.storage_class
}
}
impl<T: PointerFamily> PartialEq<DateTime<Utc>> for Object<T> {
#[inline]
fn eq(&self, other: &DateTime<Utc>) -> bool {
&self.last_modified == other
}
}
impl<T: PointerFamily> PartialEq<u64> for Object<T> {
#[inline]
fn eq(&self, other: &u64) -> bool {
&self.size == other
}
}
#[oss_gen_rc]
impl PartialEq<ObjectBase<ArcPointer>> for Object<ArcPointer> {
#[inline]
fn eq(&self, other: &ObjectBase<ArcPointer>) -> bool {
&self.base == other
}
}
#[derive(Default)]
#[doc(hidden)]
pub struct PutObject<'a> {
pub forbid_overwrite: bool,
pub server_side_encryption: Option<Encryption>,
pub server_side_data_encryption: Option<Encryption>,
pub server_side_encryption_key_id: Option<&'a str>,
pub object_acl: ObjectAcl,
pub storage_class: StorageClass,
pub tagging: Option<&'a str>,
}
#[derive(Default)]
#[doc(hidden)]
pub enum Encryption {
#[default]
Aes256,
Kms,
Sm4,
}
#[derive(Default)]
#[doc(hidden)]
pub enum ObjectAcl {
#[default]
Default,
Private,
PublicRead,
PublicReadWrite,
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct StorageClass {
kind: StorageClassKind,
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
#[non_exhaustive]
enum StorageClassKind {
#[default]
Standard,
IA,
Archive,
ColdArchive,
}
impl StorageClass {
pub const ARCHIVE: Self = Self {
kind: StorageClassKind::Archive,
};
pub const IA: Self = Self {
kind: StorageClassKind::IA,
};
pub const STANDARD: Self = Self {
kind: StorageClassKind::Standard,
};
pub const COLD_ARCHIVE: Self = Self {
kind: StorageClassKind::ColdArchive,
};
pub fn new(s: &str) -> Option<StorageClass> {
let start_char = s.chars().next()?;
let kind = match start_char {
'a' | 'A' => StorageClassKind::Archive,
'i' | 'I' => StorageClassKind::IA,
's' | 'S' => StorageClassKind::Standard,
'c' | 'C' => StorageClassKind::ColdArchive,
_ => return None,
};
Some(Self { kind })
}
}
#[derive(Default)]
#[doc(hidden)]
pub struct CopyObject<'a> {
pub forbid_overwrite: bool,
pub copy_source: &'a str,
pub copy_source_if_match: Option<&'a str>,
pub copy_source_if_none_match: Option<&'a str>,
pub copy_source_if_unmodified_since: Option<&'a str>,
pub copy_source_if_modified_since: Option<&'a str>,
pub metadata_directive: CopyDirective,
pub server_side_encryption: Option<Encryption>,
pub server_side_encryption_key_id: Option<&'a str>,
pub object_acl: ObjectAcl,
pub storage_class: StorageClass,
pub tagging: Option<&'a str>,
pub tagging_directive: CopyDirective,
}
#[derive(Default)]
#[doc(hidden)]
pub enum CopyDirective {
#[default]
Copy,
Replace,
}