use crate::authorities::AttachAuthorities;
use crate::authorities::AuthoritiesExtractor;
use actix_web::body::EitherBody;
use actix_web::dev::{Service, ServiceRequest, ServiceResponse, Transform};
use actix_web::Error;
use std::future::{self, Future, Ready};
use std::hash::Hash;
use std::marker::PhantomData;
use std::pin::Pin;
use std::rc::Rc;
use std::task::{Context, Poll};
pub struct GrantsMiddleware<E, Req, Type>
where
for<'a> E: AuthoritiesExtractor<'a, Req, Type>,
Type: Eq + Hash + 'static,
{
extractor: Rc<E>,
phantom_req: PhantomData<Req>,
phantom_type: PhantomData<Type>,
}
impl<E, Req, Type> GrantsMiddleware<E, Req, Type>
where
for<'a> E: AuthoritiesExtractor<'a, Req, Type>,
Type: Eq + Hash + 'static,
{
pub fn with_extractor(extractor: E) -> GrantsMiddleware<E, Req, Type> {
GrantsMiddleware {
extractor: Rc::new(extractor),
phantom_req: PhantomData,
phantom_type: PhantomData,
}
}
}
impl<S, B, E, Req, Type> Transform<S, ServiceRequest> for GrantsMiddleware<E, Req, Type>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
for<'a> E: AuthoritiesExtractor<'a, Req, Type> + 'static,
Type: Eq + Hash + 'static,
{
type Response = ServiceResponse<EitherBody<B>>;
type Error = Error;
type Transform = GrantsService<S, E, Req, Type>;
type InitError = ();
type Future = Ready<Result<Self::Transform, Self::InitError>>;
fn new_transform(&self, service: S) -> Self::Future {
future::ready(Ok(GrantsService {
service: Rc::new(service),
extractor: self.extractor.clone(),
phantom_req: PhantomData,
phantom_type: PhantomData,
}))
}
}
pub struct GrantsService<S, E, Req, Type>
where
for<'a> E: AuthoritiesExtractor<'a, Req, Type> + 'static,
{
service: Rc<S>,
extractor: Rc<E>,
phantom_req: PhantomData<Req>,
phantom_type: PhantomData<Type>,
}
impl<S, B, E, Req, Type> Service<ServiceRequest> for GrantsService<S, E, Req, Type>
where
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
for<'a> E: AuthoritiesExtractor<'a, Req, Type>,
Type: Eq + Hash + 'static,
{
type Response = ServiceResponse<EitherBody<B>>;
type Error = S::Error;
type Future =
Pin<Box<dyn Future<Output = Result<ServiceResponse<EitherBody<B>>, Self::Error>>>>;
fn poll_ready(&self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
self.service.poll_ready(cx)
}
fn call(&self, mut req: ServiceRequest) -> Self::Future {
let service = Rc::clone(&self.service);
let extractor = Rc::clone(&self.extractor);
Box::pin(async move {
match extractor.extract(&mut req).await {
Ok(authorities) => {
req.attach(authorities);
Ok(service.call(req).await?.map_into_left_body())
}
Err(err) => Ok(req.error_response(err).map_into_right_body()),
}
})
}
}