use crate::response::template::TemplateEngine;
use std::{error::Error, net::SocketAddr, sync::Arc};
use hyper::{server::conn::http1, service::service_fn};
use tokio::net::TcpListener;
use crate::{
prelude::{Catch, Endpoint},
support::TokioIo,
Router,
};
pub trait IntoSocketAddr {
fn into_socket_addr(self) -> SocketAddr;
}
impl IntoSocketAddr for u16 {
fn into_socket_addr(self) -> SocketAddr {
SocketAddr::from(([127, 0, 0, 1], self))
}
}
impl IntoSocketAddr for ([u8; 4], u16) {
fn into_socket_addr(self) -> SocketAddr {
SocketAddr::from(self)
}
}
pub struct Server {
router: Router,
}
#[cfg(feature = "handlebars")]
impl Server {
pub fn handlebars<T: Into<String>>(
self,
path: T,
globals: std::collections::BTreeMap<String, serde_json::Value>,
) -> Self {
crate::response::template::Handlebars::init(path, globals);
self
}
}
#[cfg(feature = "tera")]
impl Server {
pub fn tera<T: Into<String>>(
self,
path: T,
globals: std::collections::BTreeMap<String, serde_json::Value>,
) -> Self {
crate::response::template::Tera::init(path, globals);
self
}
}
impl Server {
pub fn new() -> Self {
Server {
router: Router::new(),
}
}
pub fn assets<T: Into<String>>(mut self, path: T) -> Self {
self.router.assets(Into::<String>::into(path));
self
}
pub fn route<T: Endpoint + 'static>(mut self, route: T) -> Self {
self.router.route(Arc::new(route));
self
}
pub fn routes(mut self, routes: Vec<Arc<dyn Endpoint>>) -> Self {
for route in routes {
self.router.route(route);
}
self
}
pub fn catch<T: Catch + 'static>(mut self, catch: T) -> Self {
self.router.catch(Arc::new(catch));
self
}
pub fn catches(mut self, catches: Vec<Arc<dyn Catch>>) -> Self {
for catch in catches {
self.router.catch(catch);
}
self
}
pub async fn serve<ADDR: IntoSocketAddr>(
&mut self,
addr: ADDR,
) -> Result<(), Box<dyn Error + Send + Sync>> {
let addr: SocketAddr = addr.into_socket_addr();
let listener = TcpListener::bind(addr.clone()).await?;
println!("Server started at https://{}", addr);
self.router.serve_routes();
loop {
let (stream, _) = listener.accept().await?;
let io = TokioIo::new(stream);
let rh = self.router.clone();
tokio::task::spawn(async move {
if let Err(err) = http1::Builder::new()
.serve_connection(io, service_fn(|req| rh.parse(req)))
.await
{
println!("Error serving connection: {:?}", err);
}
});
}
}
}