use std::collections::{HashMap, VecDeque};
use std::error::Error as StdError;
use std::future::Future;
use std::pin::Pin;
use std::result::Result as StdResult;
use std::sync::{Arc, Mutex};
use std::time::Duration;
use bytes::Bytes;
#[cfg(feature = "multipart")]
pub use super::common::generate_id;
#[cfg(feature = "multipart")]
use formdata::FormData;
#[cfg(feature = "multipart")]
use mime::MULTIPART_FORM_DATA;
#[cfg(feature = "multipart")]
use multer;
#[cfg(feature = "multipart")]
use multer::Multipart;
pub const DEFAULT_TIMEOUT_MILLISECOND: u64 = 30 * 1000;
pub trait Interceptor<R> {
fn get_id(&self) -> String;
fn intercept(&self, request: &mut R) -> StdResult<(), Box<dyn StdError>>;
}
#[derive(Clone)]
pub struct InterceptorFunc<R> {
id: String,
func: Arc<Mutex<dyn FnMut(&mut R) -> StdResult<(), Box<dyn StdError>> + Send + Sync + 'static>>,
}
impl<R> InterceptorFunc<R> {
pub fn new<T>(func: T) -> InterceptorFunc<R>
where
T: FnMut(&mut R) -> StdResult<(), Box<dyn StdError>> + Send + Sync + 'static,
{
InterceptorFunc {
id: Self::generate_id(),
func: Arc::new(Mutex::new(func)),
}
}
fn generate_id() -> String {
generate_id()
}
}
impl<R> Interceptor<R> for InterceptorFunc<R> {
fn get_id(&self) -> String {
return self.id.clone();
}
fn intercept(&self, request: &mut R) -> StdResult<(), Box<dyn StdError>> {
let func = &mut *self.func.lock().unwrap();
(func)(request)
}
}
pub type SimpleHTTPResponse<R> = StdResult<R, Box<dyn StdError>>;
pub trait BaseClient<Client, Req, Res, Method, Header, B> {
fn request(&self, req: Req) -> Pin<Box<dyn Future<Output = Res>>>;
fn get_client(&mut self) -> &mut Client;
}
pub struct SimpleHTTP<Client, Req, Res, Method, Header, B> {
pub client: Arc<Mutex<dyn BaseClient<Client, Req, Res, Method, Header, B>>>,
pub interceptors: VecDeque<Arc<dyn Interceptor<Req>>>,
pub timeout_millisecond: u64,
}
impl<Client, Req, Res, Method, Header, B> SimpleHTTP<Client, Req, Res, Method, Header, B> {
pub fn new_with_options(
client: Arc<Mutex<dyn BaseClient<Client, Req, Res, Method, Header, B>>>,
interceptors: VecDeque<Arc<dyn Interceptor<Req>>>,
timeout_millisecond: u64,
) -> Self {
SimpleHTTP {
client,
interceptors,
timeout_millisecond,
}
}
pub fn get_timeout_duration(&self) -> Duration {
Duration::from_millis(if self.timeout_millisecond > 0 {
self.timeout_millisecond
} else {
DEFAULT_TIMEOUT_MILLISECOND
})
}
pub fn set_client(
&mut self,
client: Arc<Mutex<dyn BaseClient<Client, Req, Res, Method, Header, B>>>,
) {
self.client = client;
}
pub fn add_interceptor(&mut self, interceptor: Arc<dyn Interceptor<Req>>) {
self.interceptors.push_back(interceptor);
}
pub fn add_interceptor_front(&mut self, interceptor: Arc<dyn Interceptor<Req>>) {
self.interceptors.push_front(interceptor);
}
pub fn delete_interceptor(&mut self, interceptor: Arc<dyn Interceptor<Req>>) {
let id;
{
id = interceptor.get_id();
}
for (index, obs) in self.interceptors.clone().iter().enumerate() {
if obs.get_id() == id {
self.interceptors.remove(index);
return;
}
}
}
}
impl<Client, Req, Res, Method, Header, B> SimpleHTTP<Client, Req, Res, Method, Header, B>
where
Req: 'static,
{
pub fn add_interceptor_fn(
&mut self,
func: impl FnMut(&mut Req) -> StdResult<(), Box<dyn StdError>> + Send + Sync + 'static,
) -> Arc<InterceptorFunc<Req>> {
let interceptor = Arc::new(InterceptorFunc::new(func));
self.add_interceptor(interceptor.clone());
interceptor
}
}
#[cfg(feature = "multipart")]
pub fn get_content_type_from_multipart_boundary(
boundary: Vec<u8>,
) -> StdResult<String, Box<dyn StdError>> {
Ok(MULTIPART_FORM_DATA.to_string() + "; boundary=\"" + &String::from_utf8(boundary)? + "\"")
}
#[cfg(feature = "multipart")]
pub fn data_and_boundary_from_multipart(
form_data: &FormData,
) -> StdResult<(Vec<u8>, Vec<u8>), Box<dyn StdError>> {
let mut data = Vec::<u8>::new();
let boundary = formdata::generate_boundary();
formdata::write_formdata(&mut data, &boundary, form_data)?;
Ok((data, boundary))
}
#[cfg(feature = "multipart")]
#[derive(Debug)]
pub struct FormDataParseError {
details: String,
}
#[cfg(feature = "multipart")]
impl StdError for FormDataParseError {}
#[cfg(feature = "multipart")]
impl FormDataParseError {
pub fn new(msg: impl Into<String>) -> FormDataParseError {
FormDataParseError {
details: msg.into(),
}
}
}
#[cfg(feature = "multipart")]
impl std::fmt::Display for FormDataParseError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.details)
}
}
#[cfg(feature = "multipart")]
pub async fn multer_multipart_to_hash_map(
multipart: &mut Multipart<'_>,
) -> StdResult<HashMap<String, (String, String, Bytes)>, Box<dyn StdError>> {
let mut result = HashMap::new();
while let Some(field) = multipart.next_field().await? {
let name = match field.name() {
Some(s) => s.to_string(),
None => {
"".to_string()
}
};
let file_name = match field.file_name() {
Some(s) => s.to_string(),
None => "".to_string(),
};
let data = if file_name.is_empty() {
field.bytes().await?
} else {
Bytes::new()
};
result.insert(name.to_string(), (name, file_name, data));
}
Ok(result)
}