use futures::{future, Future};
use hyper::service::{MakeService, Service};
use hyper::{Request, Response, StatusCode};
use std::ops::{Deref, DerefMut};
use std::{fmt, io};
pub trait NotFound<V> {
fn not_found() -> hyper::Response<V>;
}
impl NotFound<hyper::Body> for hyper::Body {
fn not_found() -> hyper::Response<hyper::Body> {
Response::builder()
.status(StatusCode::NOT_FOUND)
.body(hyper::Body::empty())
.unwrap()
}
}
type BoxedFuture<V, W> = Box<dyn Future<Item = V, Error = W>>;
type CompositeMakeServiceVec<C, U, V, W> =
Vec<(&'static str, Box<dyn BoxedMakeService<C, U, V, W>>)>;
type BoxedService<U, V, W> =
Box<dyn Service<ReqBody = U, ResBody = V, Error = W, Future = BoxedFuture<Response<V>, W>>>;
pub trait BoxedMakeService<C, U, V, W> {
fn boxed_make_service(&mut self, context: C) -> Result<BoxedService<U, V, W>, io::Error>;
}
impl<'a, SC, T, Rq, Rs, Er, S> BoxedMakeService<&'a SC, Rq, Rs, Er> for T
where
S: Service<ReqBody = Rq, ResBody = Rs, Error = Er, Future = BoxedFuture<Response<Rs>, Er>>
+ 'static,
T: MakeService<
&'a SC,
ReqBody = Rq,
ResBody = Rs,
Error = Er,
Future = futures::future::FutureResult<S, io::Error>,
Service = S,
MakeError = io::Error,
>,
Rq: hyper::body::Payload,
Rs: hyper::body::Payload,
Er: std::error::Error + Send + Sync + 'static,
{
fn boxed_make_service(
&mut self,
context: &'a SC,
) -> Result<BoxedService<Rq, Rs, Er>, io::Error> {
let service = self.make_service(context).wait()?;
Ok(Box::new(service))
}
}
#[derive(Default)]
pub struct CompositeMakeService<C, U, V, W>(CompositeMakeServiceVec<C, U, V, W>)
where
V: NotFound<V> + 'static,
W: 'static;
impl<C, U, V: NotFound<V>, W> CompositeMakeService<C, U, V, W> {
pub fn new() -> Self {
CompositeMakeService(Vec::new())
}
}
impl<'a, C, U, V, W> MakeService<&'a C> for CompositeMakeService<&'a C, U, V, W>
where
U: hyper::body::Payload,
V: NotFound<V> + 'static + hyper::body::Payload,
W: std::error::Error + Send + Sync + 'static,
{
type ReqBody = U;
type ResBody = V;
type Error = W;
type Service = CompositeService<U, V, W>;
type MakeError = io::Error;
type Future = futures::future::FutureResult<Self::Service, io::Error>;
fn make_service(
&mut self,
_service_ctx: &'a C,
) -> futures::future::FutureResult<Self::Service, io::Error> {
let mut vec = Vec::new();
for &mut (base_path, ref mut make_service) in &mut self.0 {
vec.push((
base_path,
make_service
.boxed_make_service(_service_ctx)
.expect("Error"),
))
}
future::FutureResult::from(Ok(CompositeService(vec)))
}
}
impl<C, U, V, W> fmt::Debug for CompositeMakeService<C, U, V, W>
where
V: NotFound<V> + 'static,
W: 'static,
{
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<C, U, V, W> Deref for CompositeMakeService<C, U, V, W>
where
V: NotFound<V> + 'static,
W: 'static,
{
type Target = CompositeMakeServiceVec<C, U, V, W>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<C, U, V, W> DerefMut for CompositeMakeService<C, U, V, W>
where
V: NotFound<V> + 'static,
W: 'static,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
pub struct CompositeService<U, V, W>(Vec<(&'static str, BoxedService<U, V, W>)>)
where
V: NotFound<V> + 'static,
W: 'static;
impl<U, V, W> Service for CompositeService<U, V, W>
where
U: hyper::body::Payload,
V: NotFound<V> + 'static + hyper::body::Payload,
W: 'static + std::error::Error + Send + Sync,
{
type ReqBody = U;
type ResBody = V;
type Error = W;
type Future = Box<dyn Future<Item = Response<V>, Error = W>>;
fn call(&mut self, req: Request<Self::ReqBody>) -> Self::Future {
let mut result = None;
for &mut (base_path, ref mut service) in &mut self.0 {
if req.uri().path().starts_with(base_path) {
result = Some(service.call(req));
break;
}
}
result.unwrap_or_else(|| Box::new(future::ok(V::not_found())))
}
}
impl<U, V, W> fmt::Debug for CompositeService<U, V, W>
where
V: NotFound<V> + 'static,
W: 'static,
{
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<U, V, W> Deref for CompositeService<U, V, W>
where
V: NotFound<V> + 'static,
W: 'static,
{
type Target = Vec<(&'static str, BoxedService<U, V, W>)>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<U, V, W> DerefMut for CompositeService<U, V, W>
where
V: NotFound<V> + 'static,
W: 'static,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}