torch_web/
server.rs

1use std::convert::Infallible;
2use std::net::SocketAddr;
3use std::sync::Arc;
4use hyper::server::conn::http1;
5use hyper::service::service_fn;
6use hyper::{Request as HyperRequest, Response as HyperResponse};
7use hyper_util::rt::TokioIo;
8use tokio::net::TcpListener;
9use crate::{App, Request};
10
11/// Start the HTTP server
12pub async fn serve(
13    addr: SocketAddr,
14    app: App,
15) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
16    let app = Arc::new(app);
17    let listener = TcpListener::bind(addr).await?;
18
19    println!("🔥 Torch server listening on http://{}", addr);
20
21    loop {
22        let (stream, _) = listener.accept().await?;
23        let io = TokioIo::new(stream);
24        let app = app.clone();
25
26        tokio::task::spawn(async move {
27            let service = service_fn(move |req| {
28                let app = app.clone();
29                async move { handle_request(req, app).await }
30            });
31
32            if let Err(err) = http1::Builder::new().serve_connection(io, service).await {
33                eprintln!("Error serving connection: {:?}", err);
34            }
35        });
36    }
37}
38
39/// Handle a single HTTP request
40async fn handle_request(
41    hyper_req: HyperRequest<hyper::body::Incoming>,
42    app: Arc<App>,
43) -> Result<HyperResponse<http_body_util::Full<hyper::body::Bytes>>, Infallible> {
44    let (parts, body) = hyper_req.into_parts();
45
46    // Convert hyper request to our Request type
47    let request = match Request::from_hyper(parts, body).await {
48        Ok(req) => req,
49        Err(err) => {
50            eprintln!("Error parsing request: {:?}", err);
51            return Ok(create_error_response(500, "Internal Server Error"));
52        }
53    };
54
55    // Handle the request with our app
56    let response = app.handle_request(request).await;
57
58    // Convert our Response back to hyper Response
59    Ok(response.into_hyper_response())
60}
61
62/// Create an error response
63fn create_error_response(status: u16, message: &str) -> HyperResponse<http_body_util::Full<hyper::body::Bytes>> {
64    use http_body_util::Full;
65    use hyper::body::Bytes;
66
67    HyperResponse::builder()
68        .status(status)
69        .header("content-type", "text/plain")
70        .body(Full::new(Bytes::from(message.to_string())))
71        .unwrap()
72}
73
74/// Configuration for the server
75#[derive(Debug, Clone)]
76pub struct ServerConfig {
77    /// Maximum number of concurrent connections
78    pub max_connections: Option<usize>,
79    /// Request timeout in seconds
80    pub request_timeout: Option<u64>,
81    /// Keep-alive timeout in seconds
82    pub keep_alive_timeout: Option<u64>,
83    /// Maximum request body size in bytes
84    pub max_body_size: Option<usize>,
85}
86
87impl Default for ServerConfig {
88    fn default() -> Self {
89        Self {
90            max_connections: None,
91            request_timeout: Some(30),
92            keep_alive_timeout: Some(60),
93            max_body_size: Some(1024 * 1024), // 1MB
94        }
95    }
96}
97
98/// A more advanced server builder with configuration options
99pub struct Server {
100    app: App,
101    config: ServerConfig,
102}
103
104impl Server {
105    /// Create a new server with the given app
106    pub fn new(app: App) -> Self {
107        Self {
108            app,
109            config: ServerConfig::default(),
110        }
111    }
112
113    /// Set the server configuration
114    pub fn config(mut self, config: ServerConfig) -> Self {
115        self.config = config;
116        self
117    }
118
119    /// Set maximum number of concurrent connections
120    pub fn max_connections(mut self, max: usize) -> Self {
121        self.config.max_connections = Some(max);
122        self
123    }
124
125    /// Set request timeout
126    pub fn request_timeout(mut self, timeout_secs: u64) -> Self {
127        self.config.request_timeout = Some(timeout_secs);
128        self
129    }
130
131    /// Set keep-alive timeout
132    pub fn keep_alive_timeout(mut self, timeout_secs: u64) -> Self {
133        self.config.keep_alive_timeout = Some(timeout_secs);
134        self
135    }
136
137    /// Set maximum request body size
138    pub fn max_body_size(mut self, size: usize) -> Self {
139        self.config.max_body_size = Some(size);
140        self
141    }
142
143    /// Start the server
144    pub async fn listen(
145        self,
146        addr: SocketAddr,
147    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
148        serve(addr, self.app).await
149    }
150}
151
152#[cfg(test)]
153mod tests {
154    use super::*;
155    use crate::{App, Response};
156
157    #[test]
158    fn test_server_config() {
159        let config = ServerConfig::default();
160        assert_eq!(config.request_timeout, Some(30));
161        assert_eq!(config.keep_alive_timeout, Some(60));
162        assert_eq!(config.max_body_size, Some(1024 * 1024));
163    }
164
165    #[test]
166    fn test_server_builder() {
167        let app = App::new().get::<_, (crate::Request,)>("/", |_req: crate::Request| async { Response::ok() });
168        
169        let _server = Server::new(app)
170            .max_connections(1000)
171            .request_timeout(60)
172            .keep_alive_timeout(120)
173            .max_body_size(2 * 1024 * 1024);
174    }
175}