use std::{convert::Infallible, sync::Arc};
use hyper::{body::Incoming, service::Service};
use hyper_util::{
rt::{TokioExecutor, TokioIo},
server::conn::auto::Builder,
};
use tokio::{net::TcpListener, spawn};
use crate::{
Flow::{Continue, Exit},
Handler, IntoResponse, Request, Response,
};
pub struct Server<H, S> {
handler: H,
state: S,
}
impl<S> Server<(), S> {
pub fn new(state: S) -> Server<(), S> {
Self { handler: (), state }
}
pub fn handler<H, I>(self, handler: H) -> Server<H, S>
where
H: Handler<I, S, Output = Response, Exception = Response>,
{
Server {
handler,
state: self.state,
}
}
}
impl<H, S> Server<H, S> {
pub async fn listen(self, listener: TcpListener)
where
H: Handler<Request, S, Output = Response> + Send + Sync + 'static,
H::Future: Send + 'static,
S: Clone + Send + 'static,
{
let http = Builder::new(TokioExecutor::new());
let handler = Arc::new(self.handler);
loop {
if let Ok((stream, _client)) = listener.accept().await {
let io = TokioIo::new(stream);
let connection = http
.serve_connection_with_upgrades(
io,
ServerService(handler.clone(), self.state.clone()),
)
.into_owned();
spawn(async move {
if let Err(err) = connection.await {
println!("Connection error: {:?}", err);
}
});
}
}
}
}
struct ServerService<H, S>(Arc<H>, S);
impl<H, S> Service<http::Request<Incoming>> for ServerService<H, S>
where
H: Handler<Request, S, Output = Response> + Send + Sync + 'static,
H::Future: Send + 'static,
S: Clone,
{
type Response = Response;
type Error = Infallible;
type Future = impl Future<Output = Result<Self::Response, Self::Error>> + Send + 'static;
fn call(&self, req: http::Request<Incoming>) -> Self::Future {
let future = self.0.handle(Request::from(req), self.1.clone());
async move {
match future.await {
Continue(value) => Ok(value),
Exit(value) => Ok(value.into_response()),
}
}
}
}