use crate::{
client::Reqwest,
errors::EventErrorKind,
event::{
service::{service_fn, BoxCloneService, Service},
telegram::{handler::BoxedCloneHandlerService, HandlerResponse},
},
Request,
};
use futures_util::future::BoxFuture;
use std::future::Future;
pub(crate) type BoxedCloneMiddlewareService<Client> =
BoxCloneService<(Request<Client>, Next<Client>), HandlerResponse<Client>, EventErrorKind>;
pub type Next<Client = Reqwest> = Box<
dyn Fn(Request<Client>) -> BoxFuture<'static, Result<HandlerResponse<Client>, EventErrorKind>>
+ Send
+ Sync,
>;
pub trait Middleware<Client = Reqwest>: Clone + Send + Sync + 'static {
fn call(
&mut self,
request: Request<Client>,
next: Next<Client>,
) -> impl Future<Output = Result<HandlerResponse<Client>, EventErrorKind>> + Send;
}
impl<Client, F, Fut> Middleware<Client> for F
where
Client: Send + Sync + 'static,
F: FnMut(Request<Client>, Next<Client>) -> Fut + Clone + Send + Sync + 'static,
Fut: Future<Output = Result<HandlerResponse<Client>, EventErrorKind>> + Send,
{
fn call(
&mut self,
request: Request<Client>,
next: Next<Client>,
) -> impl Future<Output = Result<HandlerResponse<Client>, EventErrorKind>> + Send {
self(request, next)
}
}
#[must_use]
pub fn wrap_to_next<Client>(
handler: BoxedCloneHandlerService<Client>,
middlewares: Box<[BoxedCloneMiddlewareService<Client>]>,
) -> Next<Client>
where
Client: Send + Sync + 'static,
{
Box::new(move |request: Request<Client>| {
let mut handler = handler.clone();
let mut middlewares = middlewares.clone();
Box::pin(async move {
let Some((middleware, middlewares)) = middlewares.split_first_mut() else {
return match handler.call(request).await {
Ok(response) => match response.result {
Ok(_) => Ok(response),
Err(err) => Err(EventErrorKind::Handler(err)),
},
Err(err) => Err(EventErrorKind::Extraction(err)),
};
};
middleware
.call((
request,
wrap_to_next(handler, middlewares.to_vec().into_boxed_slice()),
))
.await
})
})
}
pub(crate) fn boxed_middleware_factory<Client>(
middleware: impl Middleware<Client>,
) -> BoxedCloneMiddlewareService<Client>
where
Client: Send + Sync + 'static,
{
BoxCloneService::new(service_fn(move |(request, next)| {
let mut middleware = middleware.clone();
async move { middleware.call(request, next).await }
}))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
client::Reqwest,
event::{telegram::handler::boxed_handler_factory, EventReturn},
types::{ChatPrivate, MessageText, Update, UpdateMessage},
Bot, Extensions,
};
use std::{convert::Infallible, sync::Arc};
async fn test_middleware<Client>(
request: Request<Client>,
next: Next<Client>,
) -> Result<HandlerResponse<Client>, EventErrorKind> {
next(request).await
}
#[tokio::test]
async fn test_call() {
let handler_service =
boxed_handler_factory(|| async { Ok::<_, Infallible>(EventReturn::Finish) });
let request = Request::<Reqwest> {
update: Arc::new(Update::Message(UpdateMessage::new(
0,
MessageText::new(0, 0, ChatPrivate::new(0), ""),
))),
bot: Bot::default(),
context: crate::Context::default(),
extensions: Extensions::default(),
};
let response = Middleware::call(
&mut test_middleware,
request,
wrap_to_next(handler_service, [].into()),
)
.await
.unwrap();
match response.result {
Ok(EventReturn::Finish) => {}
_ => panic!("Unexpected response"),
}
}
}