use {
crate::{body::Body, execute::ExecuteCtx, Error},
futures::future::{self, Ready},
hyper::{
http::{Request, Response},
server::conn::AddrStream,
service::Service,
},
std::{
convert::Infallible,
future::Future,
net::{IpAddr, SocketAddr},
pin::Pin,
task::{self, Poll},
},
tracing::{event, Level},
};
pub struct ViceroyService {
ctx: ExecuteCtx,
}
impl ViceroyService {
pub fn new(ctx: ExecuteCtx) -> Self {
Self { ctx }
}
fn make_service(&self, remote: IpAddr) -> RequestService {
RequestService::new(self.ctx.clone(), remote)
}
pub async fn serve(self, addr: SocketAddr) -> Result<(), hyper::Error> {
let server = hyper::Server::bind(&addr).serve(self);
event!(Level::INFO, "Listening on http://{}", server.local_addr());
server.await?;
Ok(())
}
}
impl<'addr> Service<&'addr AddrStream> for ViceroyService {
type Response = RequestService;
type Error = Infallible;
type Future = Ready<Result<Self::Response, Self::Error>>;
fn poll_ready(&mut self, _cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, addr: &'addr AddrStream) -> Self::Future {
future::ok(self.make_service(addr.remote_addr().ip()))
}
}
#[derive(Clone)]
pub struct RequestService {
ctx: ExecuteCtx,
remote_addr: IpAddr,
}
impl RequestService {
fn new(ctx: ExecuteCtx, remote_addr: IpAddr) -> Self {
Self { ctx, remote_addr }
}
}
impl Service<Request<hyper::Body>> for RequestService {
type Response = Response<Body>;
type Error = Error;
#[allow(clippy::type_complexity)]
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
fn poll_ready(&mut self, _cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, req: Request<hyper::Body>) -> Self::Future {
let ctx = self.ctx.clone();
let remote = self.remote_addr;
Box::pin(async move { ctx.handle_request(req, remote).await.map(|result| result.0) })
}
}