use super::sign_v4::{HTTPVerb, SignV4Param};
use super::utils::{handle_response_status, into_request_header, SerializeToHashMap};
use super::OSSClient;
use crate::error::Error;
use crate::utils::common::gmt_format;
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, DisplayFromStr};
use std::collections::{BTreeMap, BTreeSet, HashMap};
use url::Url;
#[serde_as]
#[serde_with::skip_serializing_none]
#[derive(Serialize, Default)]
#[serde(rename_all = "kebab-case")]
pub struct ListBucketsQueryParams<'a> {
pub prefix: Option<&'a str>,
pub marker: Option<&'a str>,
#[serde_as(as = "Option<DisplayFromStr>")]
pub max_keys: Option<u16>,
}
impl SerializeToHashMap for ListBucketsQueryParams<'_> {}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "PascalCase")]
pub struct ListAllMyBucketsResult {
pub prefix: Option<String>,
pub marker: Option<String>,
pub max_keys: Option<u32>,
pub is_truncated: Option<bool>,
pub next_marker: Option<String>,
pub owner: Owner,
pub buckets: Buckets,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "PascalCase")]
pub struct Owner {
#[serde(rename = "ID")]
pub id: String,
pub display_name: String,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "PascalCase")]
pub struct Buckets {
pub bucket: Option<Vec<Bucket>>,
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "PascalCase")]
pub struct Bucket {
pub name: String,
pub comment: String,
pub creation_date: String,
pub location: String,
pub extranet_endpoint: String,
pub intranet_endpoint: String,
pub region: String,
pub storage_class: String,
}
impl OSSClient {
pub async fn list_buckets(
&self,
x_oss_resource_group_id: Option<&str>,
query_params: Option<ListBucketsQueryParams<'_>>,
) -> Result<ListAllMyBucketsResult, Error> {
let query_map = if let Some(query_params) = query_params {
query_params.serialize_to_hashmap()?
} else {
HashMap::with_capacity(0)
};
let request_url =
Url::parse_with_params(&format!("https://{}", self.endpoint), query_map).unwrap();
let mut canonical_header = BTreeMap::new();
canonical_header.insert("x-oss-content-sha256", "UNSIGNED-PAYLOAD");
canonical_header.insert("host", request_url.host_str().unwrap());
if let Some(s) = x_oss_resource_group_id {
canonical_header.insert("x-oss-resource-group-id", s);
}
let mut additional_header = BTreeSet::new();
additional_header.insert("host");
let now = time::OffsetDateTime::now_utc();
let sign_v4_param = SignV4Param {
signing_region: &self.region,
http_verb: HTTPVerb::Get,
uri: &request_url,
bucket: None,
header_map: &canonical_header,
additional_header: Some(&additional_header),
date_time: &now,
};
let authorization = self.sign_v4(sign_v4_param);
let mut header = canonical_header.into_iter().collect::<HashMap<_, _>>();
header.insert("Authorization", &authorization);
let gmt = gmt_format(&now);
header.insert("Date", &gmt);
let header_map = into_request_header(header);
let resp = self
.http_client
.get(request_url)
.headers(header_map)
.send()
.await?;
let text = handle_response_status(resp).await?;
let res = quick_xml::de::from_str(&text)?;
Ok(res)
}
}