Files
servme/src/server.rs

86 lines
2.7 KiB
Rust

use crate::{
builder::ServerBuilder,
config::ServerConfig,
middleware::{Middleware, MiddlewareResult},
};
use http1::Builder;
use http_body_util::Full;
use hyper::{body::Incoming, server::conn::http1, service::service_fn, Request, Response};
use hyper_util::rt::TokioIo;
use log::error;
use std::{convert::Infallible, future::Future, net::SocketAddr, sync::Arc};
use tokio::{net::TcpListener, spawn};
use tokio_util::bytes::Bytes;
pub struct Server {
pub config: Arc<ServerConfig>,
pub middlewares: Arc<Vec<Box<dyn Middleware>>>,
}
impl Server {
pub fn builder() -> ServerBuilder {
ServerBuilder {
config: ServerConfig::default(),
middlewares: vec![],
}
}
pub async fn run<F, Fut>(self, handler: F)
where
F: Fn(Request<Incoming>) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<Response<Full<Bytes>>, Infallible>> + Send,
{
let addr: SocketAddr = format!("{}:{}", self.config.ip, self.config.port)
.parse()
.expect("Invalid IP or port");
let listener = TcpListener::bind(addr)
.await
.expect("Failed to bind to address");
let handler = Arc::new(handler);
let shared_middlewares = self.middlewares;
loop {
let (tcp, client_addr) = match listener.accept().await {
Ok(conn) => conn,
Err(e) => {
error!("Accept error: {}", e);
continue;
}
};
let io = TokioIo::new(tcp);
let mws = Arc::clone(&shared_middlewares);
let h = Arc::clone(&handler);
let client_ip = client_addr.ip();
spawn(async move {
let conn = Builder::new().serve_connection(
io,
service_fn(move |mut req| {
let mws = Arc::clone(&mws);
let h = Arc::clone(&h);
async move {
req.extensions_mut().insert(client_ip);
for mw in mws.iter() {
match mw.run(req).await {
MiddlewareResult::Continue(next_req) => req = next_req,
MiddlewareResult::Respond(res) => return Ok(res),
}
}
h(req).await
}
}),
);
if let Err(err) = conn.await {
error!("Error serving connection: {:?}", err);
}
});
}
}
}