use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use async_trait::async_trait;
use crate::client::{RedirectPolicy, Transport};
use crate::error::Result;
use crate::request::Request;
use crate::response::Response;
#[async_trait]
pub trait Middleware: Send + Sync {
async fn handle(&self, req: Request, next: Next<'_>) -> Result<Response>;
}
pub struct Next<'a> {
middlewares: &'a [Arc<dyn Middleware>],
transport: Arc<dyn Transport>,
redirect_policy: RedirectPolicy,
}
impl<'a> Next<'a> {
pub(crate) fn new(
middlewares: &'a [Arc<dyn Middleware>],
transport: Arc<dyn Transport>,
redirect_policy: RedirectPolicy,
) -> Self {
Self {
middlewares,
transport,
redirect_policy,
}
}
pub fn run(self, req: Request) -> Pin<Box<dyn Future<Output = Result<Response>> + Send + 'a>> {
Box::pin(async move {
if let Some((current, rest)) = self.middlewares.split_first() {
current
.handle(
req,
Next {
middlewares: rest,
transport: Arc::clone(&self.transport),
redirect_policy: self.redirect_policy,
},
)
.await
} else {
self.transport
.execute_with_redirect(req, self.redirect_policy)
.await
}
})
}
}