use bytes::Bytes;
use hyper::header::{HeaderName, HeaderValue};
use hyper::{HeaderMap, Method};
use reqwest::Response;
use super::{Minio, QueryMap};
use crate::data::Data;
use crate::datatype::{FromXml, ToXml};
use crate::error::{Error, Result, S3Error};
use crate::utils::md5sum_hash;
pub struct BaseExecutor<'a> {
method: Method,
region: String,
bucket_name: Option<String>,
object_name: Option<String>,
body: Data<Error>,
headers: HeaderMap,
querys: QueryMap,
client: &'a Minio,
build_err: Result<()>,
}
impl<'a> BaseExecutor<'a> {
pub fn new(method: Method, client: &'a Minio) -> Self {
return Self {
method,
region: client.region().to_string(),
bucket_name: None,
object_name: None,
body: Default::default(),
headers: HeaderMap::new(),
client,
querys: QueryMap::new(),
build_err: Ok(()),
};
}
pub fn method(mut self, method: Method) -> Self {
self.method = method;
self
}
pub fn bucket_name<T: Into<String>>(mut self, name: T) -> Self {
self.bucket_name = Some(name.into());
self
}
pub fn object_name<T: Into<String>>(mut self, name: T) -> Self {
self.object_name = Some(name.into());
self
}
pub fn region<T: Into<String>>(mut self, region: T) -> Self {
self.region = region.into();
self
}
pub fn body<B: Into<Data<Error>>>(mut self, body: B) -> Self {
self.body = body.into();
self
}
pub(crate) fn xml<'de, S>(mut self, xml: &'de S) -> Self
where
S: ToXml,
{
let xml = match xml.to_xml() {
Ok(xml) => xml,
Err(e) => {
self.build_err = Err(e);
return self;
}
};
let body = Bytes::from(xml);
let md5 = md5sum_hash(&body);
self.body(body).header("Content-MD5", md5)
}
pub fn headers(mut self, header: HeaderMap) -> Self {
self.headers = header;
self
}
pub fn header<K, V>(mut self, key: K, value: V) -> Self
where
HeaderName: TryFrom<K>,
<HeaderName as TryFrom<K>>::Error: Into<crate::error::Error>,
HeaderValue: TryFrom<V>,
<HeaderValue as TryFrom<V>>::Error: Into<crate::error::Error>,
{
let key = <HeaderName as TryFrom<K>>::try_from(key).map_err(Into::into);
let value = <HeaderValue as TryFrom<V>>::try_from(value).map_err(Into::into);
match (key, value) {
(Ok(key), Ok(val)) => {
self.headers.insert(key, val);
}
(Err(e), _) => self.build_err = Err(e),
(_, Err(e)) => self.build_err = Err(e),
};
self
}
#[inline]
pub fn headers_merge(mut self, header: HeaderMap) -> Self {
self.headers.extend(header);
self
}
#[inline]
pub fn headers_merge2(self, header: Option<HeaderMap>) -> Self {
if let Some(header) = header {
self.headers_merge(header)
} else {
self
}
}
pub fn querys(mut self, querys: QueryMap) -> Self {
self.querys = querys;
self
}
pub fn querys_merge(mut self, querys: QueryMap) -> Self {
self.querys.merge(querys);
self
}
pub fn query<K: Into<String>, V: Into<String>>(mut self, key: K, value: V) -> Self {
self.querys.insert(key.into(), value.into());
self
}
pub fn query_string(mut self, query_str: &str) -> Self {
self.querys.merge_str(query_str);
self
}
pub fn apply<F>(self, apply: F) -> Self
where
F: FnOnce(Self) -> Self,
{
apply(self)
}
pub async fn send(self) -> Result<Response> {
self.build_err?;
let query = self.querys.to_query_string();
self.client
._execute(
self.method,
&self.region,
self.bucket_name,
self.object_name,
self.body,
Some(self.headers),
Some(query),
)
.await
}
pub async fn send_ok(self) -> Result<Response> {
let res = self.send().await?;
if res.status().is_success() {
Ok(res)
} else {
let text = res.text().await?;
let s: S3Error = text.as_str().try_into()?;
Err(s)?
}
}
pub async fn send_text_ok(self) -> Result<String> {
let res = self.send_ok().await?;
let text = res.text().await?;
Ok(text)
}
pub(crate) async fn send_xml_ok<T>(self) -> Result<T>
where
T: FromXml,
{
self.send_text_ok()
.await
.map(T::from_xml)?
.map_err(Into::into)
}
}