use std::{fmt::Debug, future::Future, sync::Arc};
use http_kit::{error::BoxHttpError, Body, Request, Response};
use skyzen_core::{
middleware::{Middleware, Next},
Error, Responder,
};
pub struct ErrorHandlingMiddleware<F> {
f: Arc<F>,
}
impl<F> Clone for ErrorHandlingMiddleware<F> {
fn clone(&self) -> Self {
Self {
f: Arc::clone(&self.f),
}
}
}
impl<F> Debug for ErrorHandlingMiddleware<F> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("ErrorHandlingMiddleware")
}
}
impl<F, Fut, Res> ErrorHandlingMiddleware<F>
where
F: 'static + Send + Sync + Fn(BoxHttpError) -> Fut,
Fut: Send + Future<Output = Res>,
Res: Responder,
{
pub fn new(f: F) -> Self {
Self { f: Arc::new(f) }
}
}
impl<F, Fut, Res> Middleware for ErrorHandlingMiddleware<F>
where
F: 'static + Send + Sync + Fn(BoxHttpError) -> Fut,
Fut: Send + Future<Output = Res>,
Res: Responder,
{
async fn handle(&self, request: &mut Request, next: Next<'_>) -> Result<Response, Error> {
match next.run(request).await {
Ok(response) => Ok(response),
Err(error) => {
let mut response = Response::new(Body::empty());
*response.status_mut() = error.status();
(self.f)(error.into_boxed_http_error())
.await
.respond_to(request, &mut response)?;
Ok(response)
}
}
}
}