use crate::{
context::Context,
error::Error,
middleware::{ImplMiddleware, MiddlewareBuilder, Next},
request::Request,
response::Response,
router::{ImplRoute, Route, Router, RouterBuilder},
tokio_io::TokioIO,
};
use futures::{TryFutureExt,FutureExt};
use http_body_util::Full;
use hyper::body::Bytes;
use hyper::{server::conn::http1, service::Service};
use std::{future::Future, net::SocketAddr, pin::Pin};
use tokio::{net::TcpListener, sync::OnceCell};
#[doc(hidden)]
static SERVER: OnceCell<Server> = OnceCell::const_new();
#[doc(hidden)]
#[inline]
fn write_into_static(server: Server) -> Result<&'static Server, Error> {
SERVER
.set(server)
.map_err(|_| Error::Other(String::from("Server alrealy initialized")))?;
let server = SERVER.get().expect("Memory has been initialized above.");
Ok(server)
}
#[doc(hidden)]
pub struct Builder<'a, C, M>
where
C: 'static + Route + Unpin + Send + Sync,
M: 'static + Next + Unpin + Send + Sync,
{
router: RouterBuilder<'a, C>,
middlewares: MiddlewareBuilder<M>,
}
impl<'a, C, M> Builder<'a, C, M>
where
C: 'static + Route + Unpin + Send + Sync,
M: 'static + Next + Unpin + Send + Sync,
{
#[inline]
pub fn router<R, F>(self, f: F) -> Builder<'a, R, M>
where
R: Route + Send + Sync + Unpin,
F: FnOnce(RouterBuilder<C>) -> RouterBuilder<R>,
{
Builder {
router: f(self.router),
middlewares: self.middlewares,
}
}
#[inline]
pub fn middleware<N, F>(self, f: F) -> Builder<'a, C, N>
where
N: Next + Unpin + Send + Sync,
F: FnOnce(MiddlewareBuilder<M>) -> MiddlewareBuilder<N>,
{
Builder {
router: self.router,
middlewares: f(self.middlewares),
}
}
#[inline]
pub fn build(self) -> Server {
Server {
router: self.router.build(),
middlewares: self.middlewares.build(),
}
}
}
#[doc(hidden)]
pub struct Server {
router: Router,
middlewares: Box<dyn Next>,
}
impl<'a> Server {
#[inline]
fn new_stack(&'static self, addr: SocketAddr) -> Stack {
Stack { server: self, addr }
}
#[inline]
pub fn builder() -> Builder<'a, ImplRoute, ImplMiddleware> {
Builder {
router: RouterBuilder::default(),
middlewares: MiddlewareBuilder::default(),
}
}
#[inline]
async fn serve(&self, mut req: Request) -> Result<Response, Error> {
let meta = self.router.resolve_metadata(&mut req);
let ctx = Context::new(req, self.router.clone(), meta);
let err_ctx = ctx.clone_with_empty_state();
let res = self
.middlewares
.next(ctx)
.and_then(|mut ctx| async move {
let res = ctx
.state
.take_response()
.ok_or_else(|| Error::Other(String::from("Response moved")))?;
Ok(res)
})
.await
.or_else(|e| {
let builder = crate::response::Builder::new();
e.response_builder(builder, &err_ctx)
.build()
.map_err(|e2| e2)
});
res
}
#[inline]
pub async fn listen(self, addr: &str) -> Result<(), Error> {
let stack = write_into_static(self)?;
let listener = TcpListener::bind(addr).await?;
println!("{}{}", "\x1b[31m", addr);
loop {
let (stream, addr) = listener.accept().await?;
tokio::task::spawn(async move {
if let Err(error) = http1::Builder::new()
.serve_connection(TokioIO::new(stream), stack.new_stack(addr))
.await
{
eprintln!("Error while serving HTTP connection: {error}");
}
});
}
}
#[cfg(feature = "https")]
#[inline]
pub async fn listen_tls(self, addr: &str, tls: crate::rustls::TlsConfig) -> Result<(), Error> {
let stack = write_into_static(self)?;
let listener = TcpListener::bind(addr).await?;
println!("{}{}", "\x1b[31m", addr);
let tls: tokio_rustls::TlsAcceptor = tls.build().map(std::sync::Arc::new)?.into();
loop {
let (stream, addr) = listener.accept().await?;
let tls_stream = tls.accept(stream).await?;
tokio::task::spawn(async move {
if let Err(error) = http1::Builder::new()
.serve_connection(TokioIO::new(tls_stream), stack.new_stack(addr))
.await
{
eprintln!("Error while serving HTTP connection: {error}");
}
});
}
}
}
#[doc(hidden)]
#[derive(Clone)]
struct Stack {
server: &'static Server,
addr: SocketAddr,
}
impl Service<hyper::Request<hyper::body::Incoming>> for Stack {
type Error = Error;
type Response = hyper::Response<Full<Bytes>>;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
#[inline]
fn call(&self, req: hyper::Request<hyper::body::Incoming>) -> Self::Future {
let req = Request::new(req.map(crate::body::IncomingBody::Incoming), self.addr);
Box::pin(self.server.serve(req).map(|r| r.and_then(|r| r.into_raw()))) as Self::Future
}
}