use std::future::Future;
use http::Method;
use serde::{Deserialize, Deserializer, Serialize};
use serde_with::skip_serializing_none;
use crate::body::NoneBody;
use crate::error::Result;
use crate::ops::Owner;
use crate::response::BodyResponseProcessor;
use crate::{Client, Ops, Prepared, QueryAuthOptions, Request};
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct ObjectSummary {
pub key: String,
pub last_modified: String,
#[serde(rename = "ETag")]
pub etag: String,
#[serde(rename = "Type")]
pub object_type: String,
pub size: u64,
pub storage_class: String,
pub owner: Option<Owner>,
pub restore_info: Option<String>,
}
fn unwrap_common_prefixes<'de, D>(deserializer: D) -> std::result::Result<Vec<String>, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(rename_all = "PascalCase")]
struct CommonPrefixes {
#[serde(default)]
prefix: Vec<String>,
}
let common_prefixes = Vec::<CommonPrefixes>::deserialize(deserializer)?;
Ok(common_prefixes.into_iter().flat_map(|v| v.prefix).collect())
}
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct ListObjectsResult {
pub name: String,
pub prefix: String,
pub max_keys: u32,
pub delimiter: Option<String>,
pub start_after: Option<String>,
pub encoding_type: Option<String>,
pub is_truncated: bool,
pub key_count: u64,
pub continuation_token: Option<String>,
pub next_continuation_token: Option<String>,
#[serde(default, deserialize_with = "unwrap_common_prefixes")]
pub common_prefixes: Vec<String>,
#[serde(default)]
pub contents: Vec<ObjectSummary>,
}
#[skip_serializing_none]
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "kebab-case")]
pub struct ListObjectsV2Params {
list_type: u8,
pub delimiter: Option<String>,
pub start_after: Option<String>,
pub continuation_token: Option<String>,
pub max_keys: Option<u32>,
pub prefix: Option<String>,
pub encoding_type: Option<String>,
pub fetch_owner: Option<bool>,
}
impl Default for ListObjectsV2Params {
fn default() -> Self {
Self {
list_type: 2,
delimiter: None,
start_after: None,
continuation_token: None,
max_keys: None,
prefix: None,
encoding_type: None,
fetch_owner: None,
}
}
}
pub struct ListObjects {
pub query: ListObjectsV2Params,
}
impl ListObjects {
pub fn new(options: Option<ListObjectsV2Params>) -> Self {
Self {
query: options.unwrap_or_default(),
}
}
}
impl Ops for ListObjects {
type Response = BodyResponseProcessor<ListObjectsResult>;
type Body = NoneBody;
type Query = ListObjectsV2Params;
fn prepare(self) -> Result<Prepared<ListObjectsV2Params>> {
Ok(Prepared {
method: Method::GET,
query: Some(self.query),
..Default::default()
})
}
}
pub trait ListObjectsOps {
fn list_objects(
&self,
params: Option<ListObjectsV2Params>,
) -> impl Future<Output = Result<ListObjectsResult>>;
fn presign_list_objects(
&self,
public: bool,
params: Option<ListObjectsV2Params>,
query_auth_options: QueryAuthOptions,
) -> impl Future<Output = Result<String>>;
}
impl ListObjectsOps for Client {
async fn list_objects(&self, params: Option<ListObjectsV2Params>) -> Result<ListObjectsResult> {
let ops = ListObjects::new(params);
self.request(ops).await
}
async fn presign_list_objects(
&self,
public: bool,
params: Option<ListObjectsV2Params>,
query_auth_options: QueryAuthOptions,
) -> Result<String> {
let ops = ListObjects::new(params);
self.presign(ops, public, Some(query_auth_options)).await
}
}