use anyhow_ext::Context;
use anyhow_ext::{Result, anyhow};
use derive_builder::Builder;
use serde::{Deserialize, Serialize};
use tracing::trace;
use crate::{S3Client, S3Error};
impl S3Client {
pub async fn list_bucket(&self, params: ListBucketParams) -> Result<ListBucketResult> {
let mut resp = self
.send(
None,
"GET",
Some(¶ms),
None,
None, )
.await
.dot()?;
let xml = resp
.body_string()
.await
.map_err(|err| anyhow!(err.to_string()))
.dot()?;
trace!(xml);
if resp.is_success() {
return Ok(serde_xml_rs::from_reader(xml.as_bytes()).dot()?);
} else {
let error: S3Error = serde_xml_rs::from_reader(xml.as_bytes()).dot()?;
return Err(anyhow!("s3 error = {:?}", error));
}
}
}
#[derive(Serialize, Default, Builder, Debug)]
#[builder(setter(into))]
#[builder(default)]
pub struct ListBucketParams {
#[serde(rename(serialize = "list-type"))]
#[builder(default = "2u8")]
list_type: u8, prefix: Option<String>,
delimiter: Option<String>,
#[serde(rename(serialize = "continuation-token"))]
continuation_token: Option<String>,
#[serde(rename(serialize = "max-keys"))]
max_keys: Option<String>,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "PascalCase")]
pub struct ListBucketResult {
pub name: String,
pub prefix: Option<String>,
pub key_count: Option<u16>,
pub max_keys: u16,
pub delimiter: Option<String>,
pub is_truncated: bool,
pub next_continuation_token: Option<String>,
pub server_side_encryption_enabled: Option<bool>,
pub common_prefixes: Option<Vec<CommonPrefexes>>, pub object_matches: Option<ObjectMatches>, pub contents: Option<Vec<Content>>,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "PascalCase")]
pub struct CommonPrefexes {
pub prefix: String,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ObjectMatches {
pub object: Option<Vec<Object>>,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Content {
pub object: Option<Vec<Object>>,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct Object {
pub object_name: Option<String>,
pub object_id: Option<String>,
pub version_id: Option<String>,
pub query_mds: Option<Vec<QueryMds>>,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct QueryMds {
r#type: QueryMetadataType,
md_map: MdMap,
}
#[derive(Deserialize, Debug)]
pub enum QueryMetadataType {
SYSMD,
USERMD,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct MdMap {
entry: Vec<Entry>,
}
#[derive(Deserialize, Debug)]
pub struct Entry {
key: String,
value: String,
}
#[cfg(test)]
mod test {
use async_std::{fs::File, task};
use anyhow_ext::Result;
use async_std::io::BufReader;
use tracing::info;
use tracing_test::traced_test;
use crate::{S3Client, bucket::ListBucketParamsBuilder};
#[test]
#[traced_test]
fn test_builder() -> Result<()> {
let req = ListBucketParamsBuilder::default()
.prefix(Some("/".to_owned()))
.delimiter(Some("/".to_owned()))
.build()?;
println!("{:?}", req);
Ok(())
}
#[test]
#[tracing_test::traced_test]
fn test_list_bucket() -> Result<()> {
let s3 = S3Client::from_toml_config("config.toml")?;
task::block_on(async {
let x = s3
.list_bucket(
ListBucketParamsBuilder::default()
.prefix(Some("/".to_owned()))
.delimiter(Some("/".to_owned()))
.build()
.unwrap(),
)
.await
.unwrap();
info!(?x);
});
return Ok(());
}
}