use futures::future::FutureExt;
use hyper::service::Service;
use hyper::{Request, Response, StatusCode};
use std::fmt;
use std::ops::{Deref, DerefMut};
use std::task::{Context, Poll};
pub trait NotFound<V> {
fn not_found() -> Response<V>;
}
impl<B: Default> NotFound<B> for B {
fn not_found() -> Response<B> {
Response::builder()
.status(StatusCode::NOT_FOUND)
.body(B::default())
.unwrap()
}
}
type CompositedService<ReqBody, ResBody, Error> = Box<
dyn Service<
Request<ReqBody>,
Response = Response<ResBody>,
Error = Error,
Future = futures::future::BoxFuture<'static, Result<Response<ResBody>, Error>>,
> + Send,
>;
type CompositedMakeService<Target, ReqBody, ResBody, Error, MakeError> = Box<
dyn Service<
Target,
Error = MakeError,
Future = futures::future::BoxFuture<
'static,
Result<CompositedService<ReqBody, ResBody, Error>, MakeError>,
>,
Response = CompositedService<ReqBody, ResBody, Error>,
>,
>;
type CompositeMakeServiceVec<Target, ReqBody, ResBody, Error, MakeError> = Vec<(
&'static str,
CompositedMakeService<Target, ReqBody, ResBody, Error, MakeError>,
)>;
#[derive(Default)]
pub struct CompositeMakeService<Target, ReqBody, ResBody, Error, MakeError>(
CompositeMakeServiceVec<Target, ReqBody, ResBody, Error, MakeError>,
)
where
ResBody: NotFound<ResBody>;
impl<Target, ReqBody, ResBody, Error, MakeError>
CompositeMakeService<Target, ReqBody, ResBody, Error, MakeError>
where
ResBody: NotFound<ResBody>,
{
pub fn new() -> Self {
CompositeMakeService(Vec::new())
}
}
impl<Target, ReqBody, ResBody, Error, MakeError> Service<Target>
for CompositeMakeService<Target, ReqBody, ResBody, Error, MakeError>
where
ReqBody: 'static,
ResBody: NotFound<ResBody> + 'static,
MakeError: Send + 'static,
Error: 'static,
Target: Clone,
{
type Error = MakeError;
type Response = CompositeService<ReqBody, ResBody, Error>;
type Future = futures::future::BoxFuture<'static, Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
for service in &mut self.0 {
match service.1.poll_ready(cx) {
Poll::Ready(Ok(_)) => {}
Poll::Ready(Err(e)) => {
return Poll::Ready(Err(e));
}
Poll::Pending => {
return Poll::Pending;
}
}
}
Poll::Ready(Ok(()))
}
fn call(&mut self, target: Target) -> Self::Future {
let services = self.0.iter_mut().map(|(path, service)| {
let path: &'static str = path;
service
.call(target.clone())
.map(move |res| res.map(move |service| (path, service)))
});
Box::pin(futures::future::join_all(services).map(|results| {
let services: Result<Vec<_>, MakeError> = results.into_iter().collect();
Ok(CompositeService(services?))
}))
}
}
impl<Target, ReqBody, ResBody, Error, MakeError> fmt::Debug
for CompositeMakeService<Target, ReqBody, ResBody, Error, MakeError>
where
ResBody: NotFound<ResBody>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
let str_vec: Vec<&'static str> = self.0.iter().map(|&(base_path, _)| base_path).collect();
write!(
f,
"CompositeMakeService accepting base paths: {:?}",
str_vec,
)
}
}
impl<Target, ReqBody, ResBody, Error, MakeError> Deref
for CompositeMakeService<Target, ReqBody, ResBody, Error, MakeError>
where
ResBody: NotFound<ResBody>,
{
type Target = CompositeMakeServiceVec<Target, ReqBody, ResBody, Error, MakeError>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<Target, ReqBody, ResBody, Error, MakeError> DerefMut
for CompositeMakeService<Target, ReqBody, ResBody, Error, MakeError>
where
ResBody: NotFound<ResBody>,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
pub struct CompositeService<ReqBody, ResBody, Error>(
Vec<(&'static str, CompositedService<ReqBody, ResBody, Error>)>,
)
where
ResBody: NotFound<ResBody>;
impl<ReqBody, ResBody, Error> Service<Request<ReqBody>>
for CompositeService<ReqBody, ResBody, Error>
where
Error: Send + 'static,
ResBody: NotFound<ResBody> + Send + 'static,
{
type Error = Error;
type Response = Response<ResBody>;
type Future = futures::future::BoxFuture<'static, Result<Response<ResBody>, Error>>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
for service in &mut self.0 {
match service.1.poll_ready(cx) {
Poll::Ready(Ok(_)) => {}
Poll::Ready(Err(e)) => return Poll::Ready(Err(e)),
Poll::Pending => return Poll::Pending,
}
}
Poll::Ready(Ok(()))
}
fn call(&mut self, req: Request<ReqBody>) -> Self::Future {
for &mut (base_path, ref mut service) in &mut self.0 {
if req.uri().path().starts_with(base_path) {
return service.call(req);
}
}
Box::pin(futures::future::ok(ResBody::not_found()))
}
}
impl<ReqBody, ResBody, Error> fmt::Debug for CompositeService<ReqBody, ResBody, Error>
where
ResBody: NotFound<ResBody>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
let str_vec: Vec<&'static str> = self.0.iter().map(|&(base_path, _)| base_path).collect();
write!(f, "CompositeService accepting base paths: {:?}", str_vec,)
}
}
impl<ReqBody, ResBody, Error> Deref for CompositeService<ReqBody, ResBody, Error>
where
ResBody: NotFound<ResBody> + 'static,
Error: 'static,
{
type Target = Vec<(&'static str, CompositedService<ReqBody, ResBody, Error>)>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<ReqBody, ResBody, Error> DerefMut for CompositeService<ReqBody, ResBody, Error>
where
ResBody: NotFound<ResBody> + 'static,
Error: 'static,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}