kit_rs/
server.rs

1use crate::http::{HttpResponse, Request};
2use crate::routing::Router;
3use bytes::Bytes;
4use http_body_util::Full;
5use hyper::server::conn::http1;
6use hyper::service::service_fn;
7use hyper_util::rt::TokioIo;
8use std::convert::Infallible;
9use std::net::SocketAddr;
10use std::sync::Arc;
11use tokio::net::TcpListener;
12
13pub struct Server {
14    router: Arc<Router>,
15    host: String,
16    port: u16,
17}
18
19impl Server {
20    pub fn new(router: Router) -> Self {
21        Self {
22            router: Arc::new(router),
23            host: "127.0.0.1".to_string(),
24            port: 8000,
25        }
26    }
27    
28    pub fn host(&mut self, host: &str) -> &mut Self {
29        self.host = host.to_string();
30        self
31    }
32    
33    pub fn port(&mut self, port: u16) -> &mut Self {
34        self.port = port;
35        self
36    }
37    
38    fn get_addr(&self) -> SocketAddr {
39        SocketAddr::new(self.host.parse().unwrap(), self.port)
40    }
41
42    pub async fn run(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
43        // Default to localhost:8000
44        let addr: SocketAddr = self.get_addr();
45        let listener = TcpListener::bind(addr).await?;
46
47        println!("Kit server running on http://{}", addr);
48
49        loop {
50            let (stream, _) = listener.accept().await?;
51            let io = TokioIo::new(stream);
52            let router = self.router.clone();
53
54            tokio::spawn(async move {
55                let service = service_fn(move |req: hyper::Request<hyper::body::Incoming>| {
56                    let router = router.clone();
57                    async move { Ok::<_, Infallible>(handle_request(router, req).await) }
58                });
59
60                if let Err(err) = http1::Builder::new().serve_connection(io, service).await {
61                    eprintln!("Error serving connection: {:?}", err);
62                }
63            });
64        }
65    }
66}
67
68async fn handle_request(
69    router: Arc<Router>,
70    req: hyper::Request<hyper::body::Incoming>,
71) -> hyper::Response<Full<Bytes>> {
72    let method = req.method().clone();
73    let path = req.uri().path().to_string();
74
75    match router.match_route(&method, &path) {
76        Some((handler, params)) => {
77            let request = Request::new(req).with_params(params);
78            let response = handler(request).await;
79            // Unwrap the Result - both Ok and Err contain HttpResponse
80            let http_response = response.unwrap_or_else(|e| e);
81            http_response.into_hyper()
82        }
83        None => {
84            HttpResponse::text("404 Not Found")
85                .status(404)
86                .into_hyper()
87        }
88    }
89}