use std::rc::Rc;
use actix_service::ServiceFactory;
use actix_web::{
Error,
dev::{AppService, HttpServiceFactory, ResourceDef, ServiceRequest, ServiceResponse},
guard::Guard,
};
use futures_core::future::LocalBoxFuture;
use crate::link::Link;
use super::service::{ChainInner, ChainService};
#[derive(Clone)]
pub struct Chain {
mount_path: String,
links: Vec<Link>,
guards: Vec<Rc<dyn Guard>>,
body_buffer_size: usize,
}
impl Chain {
pub fn new(mount_path: &str) -> Self {
Self {
mount_path: mount_path.to_owned(),
links: Vec::new(),
guards: Vec::new(),
body_buffer_size: 32 * 1024, }
}
pub fn guard<G: Guard + 'static>(mut self, guards: G) -> Self {
self.guards.push(Rc::new(guards));
self
}
#[inline]
pub fn link(mut self, link: Link) -> Self {
self.push_link(link);
self
}
#[inline]
pub fn push_link(&mut self, link: Link) -> &mut Self {
self.links.push(link);
self
}
}
impl Default for Chain {
#[inline]
fn default() -> Self {
Self::new("")
}
}
impl HttpServiceFactory for Chain {
fn register(mut self, config: &mut AppService) {
let guards = if self.guards.is_empty() {
None
} else {
let guards = std::mem::take(&mut self.guards);
Some(
guards
.into_iter()
.map(|guard| -> Box<dyn Guard> { Box::new(guard) })
.collect::<Vec<_>>(),
)
};
let rdef = if config.is_root() {
ResourceDef::root_prefix(&self.mount_path)
} else {
ResourceDef::prefix(&self.mount_path)
};
config.register_service(rdef, guards, self, None)
}
}
impl ServiceFactory<ServiceRequest> for Chain {
type Response = ServiceResponse;
type Error = Error;
type Config = ();
type Service = ChainService;
type InitError = ();
type Future = LocalBoxFuture<'static, Result<Self::Service, Self::InitError>>;
fn new_service(&self, _: ()) -> Self::Future {
let this = self.clone();
Box::pin(async move {
let mut links = vec![];
for link in this.links {
match link.into_inner().await {
Ok(link) => links.push(link),
Err(_) => return Err(()),
}
}
Ok(ChainService(Rc::new(ChainInner {
links,
body_buffer_size: this.body_buffer_size,
})))
})
}
}