1use crate::config::{Config, ServerConfig};
2use crate::container::App;
3use crate::http::{HttpResponse, Request};
4use crate::inertia::InertiaContext;
5use crate::middleware::{Middleware, MiddlewareChain, MiddlewareRegistry};
6use crate::routing::Router;
7use bytes::Bytes;
8use http_body_util::Full;
9use hyper::server::conn::http1;
10use hyper::service::service_fn;
11use hyper_util::rt::TokioIo;
12use std::convert::Infallible;
13use std::net::SocketAddr;
14use std::sync::Arc;
15use tokio::net::TcpListener;
16
17pub struct Server {
18 router: Arc<Router>,
19 middleware: MiddlewareRegistry,
20 host: String,
21 port: u16,
22}
23
24impl Server {
25 pub fn new(router: impl Into<Router>) -> Self {
26 Self {
27 router: Arc::new(router.into()),
28 middleware: MiddlewareRegistry::new(),
29 host: "127.0.0.1".to_string(),
30 port: 8000,
31 }
32 }
33
34 pub fn from_config(router: impl Into<Router>) -> Self {
35 App::init();
37
38 App::boot_services();
40
41 let config = Config::get::<ServerConfig>().unwrap_or_else(ServerConfig::from_env);
42 Self {
43 router: Arc::new(router.into()),
44 middleware: MiddlewareRegistry::new(),
45 host: config.host,
46 port: config.port,
47 }
48 }
49
50 pub fn middleware<M: Middleware + 'static>(mut self, middleware: M) -> Self {
64 self.middleware = self.middleware.append(middleware);
65 self
66 }
67
68 pub fn host(mut self, host: &str) -> Self {
69 self.host = host.to_string();
70 self
71 }
72
73 pub fn port(mut self, port: u16) -> Self {
74 self.port = port;
75 self
76 }
77
78 fn get_addr(&self) -> SocketAddr {
79 SocketAddr::new(self.host.parse().unwrap(), self.port)
80 }
81
82 pub async fn run(self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
83 let addr: SocketAddr = self.get_addr();
84 let listener = TcpListener::bind(addr).await?;
85
86 println!("Kit server running on http://{}", addr);
87
88 let router = self.router;
89 let middleware = Arc::new(self.middleware);
90
91 loop {
92 let (stream, _) = listener.accept().await?;
93 let io = TokioIo::new(stream);
94 let router = router.clone();
95 let middleware = middleware.clone();
96
97 tokio::spawn(async move {
98 let service = service_fn(move |req: hyper::Request<hyper::body::Incoming>| {
99 let router = router.clone();
100 let middleware = middleware.clone();
101 async move { Ok::<_, Infallible>(handle_request(router, middleware, req).await) }
102 });
103
104 if let Err(err) = http1::Builder::new().serve_connection(io, service).await {
105 eprintln!("Error serving connection: {:?}", err);
106 }
107 });
108 }
109 }
110}
111
112async fn handle_request(
113 router: Arc<Router>,
114 middleware_registry: Arc<MiddlewareRegistry>,
115 req: hyper::Request<hyper::body::Incoming>,
116) -> hyper::Response<Full<Bytes>> {
117 let method = req.method().clone();
118 let path = req.uri().path().to_string();
119
120 let is_inertia = req
122 .headers()
123 .get("X-Inertia")
124 .and_then(|v| v.to_str().ok())
125 .map(|v| v == "true")
126 .unwrap_or(false);
127
128 let inertia_version = req
129 .headers()
130 .get("X-Inertia-Version")
131 .and_then(|v| v.to_str().ok())
132 .map(|v| v.to_string());
133
134 InertiaContext::set(InertiaContext {
135 path: path.clone(),
136 is_inertia,
137 version: inertia_version,
138 });
139
140 let response = match router.match_route(&method, &path) {
141 Some((handler, params)) => {
142 let request = Request::new(req).with_params(params);
143
144 let mut chain = MiddlewareChain::new();
146
147 chain.extend(middleware_registry.global_middleware().iter().cloned());
149
150 let route_middleware = router.get_route_middleware(&path);
152 chain.extend(route_middleware);
153
154 let response = chain.execute(request, handler).await;
156
157 let http_response = response.unwrap_or_else(|e| e);
159 http_response.into_hyper()
160 }
161 None => {
162 HttpResponse::text("404 Not Found")
163 .status(404)
164 .into_hyper()
165 }
166 };
167
168 InertiaContext::clear();
170
171 response
172}