Skip to main content

ullun/
app.rs

1//! Main application orchestrator
2
3use crate::error::{Error, Result};
4use crate::handler::{DynHandler, Handler, HandlerWithParams};
5use crate::middleware::{Middleware, Next};
6use crate::request::{Params, Request};
7use crate::response::Response;
8use crate::router::Router;
9use http_body_util::BodyExt;
10use hyper::server::conn::http1;
11use hyper::service::service_fn;
12use hyper_util::rt::TokioIo;
13use std::convert::Infallible;
14use std::net::SocketAddr;
15use std::sync::Arc;
16use tokio::net::TcpListener;
17
18/// Main application struct
19pub struct App {
20    router: Router,
21    middlewares: Vec<Arc<dyn Middleware>>,
22}
23
24impl App {
25    pub fn new() -> Self {
26        Self {
27            router: Router::new(),
28            middlewares: Vec::new(),
29        }
30    }
31
32    /// Add GET route
33    pub fn get<H>(mut self, path: &str, handler: H) -> Self
34    where
35        H: Handler,
36    {
37        if let Err(e) = self
38            .router
39            .insert("GET", path, Arc::new(handler) as DynHandler)
40        {
41            panic!("Failed to register GET route {}: {}", path, e);
42        }
43        self
44    }
45
46    /// Add GET route with path params extractor
47    pub fn get_with_params<F, Fut>(mut self, path: &str, handler: F) -> Self
48    where
49        F: Fn(Params) -> Fut + Send + Sync + 'static,
50        Fut: std::future::Future<Output = Result<Response>> + Send + 'static,
51    {
52        if let Err(e) = self.router.insert(
53            "GET",
54            path,
55            Arc::new(HandlerWithParams::new(handler)) as DynHandler,
56        ) {
57            panic!("Failed to register GET route {}: {}", path, e);
58        }
59        self
60    }
61
62    /// Add POST route
63    pub fn post<H>(mut self, path: &str, handler: H) -> Self
64    where
65        H: Handler,
66    {
67        if let Err(e) = self
68            .router
69            .insert("POST", path, Arc::new(handler) as DynHandler)
70        {
71            panic!("Failed to register POST route {}: {}", path, e);
72        }
73        self
74    }
75
76    /// Add PUT route
77    pub fn put<H>(mut self, path: &str, handler: H) -> Self
78    where
79        H: Handler,
80    {
81        if let Err(e) = self
82            .router
83            .insert("PUT", path, Arc::new(handler) as DynHandler)
84        {
85            panic!("Failed to register PUT route {}: {}", path, e);
86        }
87        self
88    }
89
90    /// Add DELETE route
91    pub fn delete<H>(mut self, path: &str, handler: H) -> Self
92    where
93        H: Handler,
94    {
95        if let Err(e) = self
96            .router
97            .insert("DELETE", path, Arc::new(handler) as DynHandler)
98        {
99            panic!("Failed to register DELETE route {}: {}", path, e);
100        }
101        self
102    }
103
104    /// Add PATCH route
105    pub fn patch<H>(mut self, path: &str, handler: H) -> Self
106    where
107        H: Handler,
108    {
109        if let Err(e) = self
110            .router
111            .insert("PATCH", path, Arc::new(handler) as DynHandler)
112        {
113            panic!("Failed to register PATCH route {}: {}", path, e);
114        }
115        self
116    }
117
118    /// Add middleware
119    pub fn middleware<M>(mut self, middleware: M) -> Self
120    where
121        M: Middleware,
122    {
123        self.middlewares.push(Arc::new(middleware));
124        self
125    }
126
127    /// Run the server with graceful shutdown on CTRL+C
128    pub async fn run(self, addr: &str) -> Result<()> {
129        let addr: SocketAddr = addr
130            .parse()
131            .map_err(|e| Error::internal(format!("Invalid address: {}", e)))?;
132
133        let listener = TcpListener::bind(addr)
134            .await
135            .map_err(|e| Error::internal(format!("Failed to bind: {}", e)))?;
136
137        println!("šŸš€ ullun-api listening on http://{}", addr);
138
139        let router = Arc::new(self.router);
140        let middlewares = Arc::new(self.middlewares);
141
142        // Graceful shutdown signal
143        let shutdown = async {
144            tokio::signal::ctrl_c()
145                .await
146                .expect("Failed to install CTRL+C handler");
147            println!("\nšŸ›‘ Shutting down gracefully...");
148        };
149
150        tokio::select! {
151            _ = shutdown => {
152                println!("āœ… Server stopped");
153                Ok(())
154            }
155            result = Self::serve_loop(listener, router, middlewares) => result
156        }
157    }
158
159    async fn serve_loop(
160        listener: TcpListener,
161        router: Arc<Router>,
162        middlewares: Arc<Vec<Arc<dyn Middleware>>>,
163    ) -> Result<()> {
164        loop {
165            let (stream, _) = listener
166                .accept()
167                .await
168                .map_err(|e| Error::internal(format!("Failed to accept: {}", e)))?;
169
170            let io = TokioIo::new(stream);
171            let router = router.clone();
172            let middlewares = middlewares.clone();
173
174            tokio::task::spawn(async move {
175                if let Err(err) = http1::Builder::new()
176                    .serve_connection(
177                        io,
178                        service_fn(|req| {
179                            let router = router.clone();
180                            let middlewares = middlewares.clone();
181                            async move {
182                                Ok::<_, Infallible>(handle_request(req, router, middlewares).await)
183                            }
184                        }),
185                    )
186                    .await
187                {
188                    eprintln!("Error serving connection: {:?}", err);
189                }
190            });
191        }
192    }
193}
194
195impl Default for App {
196    fn default() -> Self {
197        Self::new()
198    }
199}
200
201async fn handle_request(
202    req: hyper::Request<hyper::body::Incoming>,
203    router: Arc<Router>,
204    middlewares: Arc<Vec<Arc<dyn Middleware>>>,
205) -> hyper::Response<http_body_util::Full<bytes::Bytes>> {
206    let method = req.method().to_string();
207    let path = req.uri().path().to_string();
208
209    // Convert hyper request to our Request type
210    let (parts, body) = req.into_parts();
211    let body_bytes = match body.collect().await {
212        Ok(collected) => collected.to_bytes(),
213        Err(_) => bytes::Bytes::new(),
214    };
215
216    let mut request = Request::new(parts.method, parts.uri, parts.headers, body_bytes);
217
218    // Match route
219    let result = match router.match_route(&method, &path) {
220        Ok((handler, params)) => {
221            request.params = params;
222
223            // Run middlewares + handler
224            if middlewares.is_empty() {
225                handler.call(request).await
226            } else {
227                // Create middleware chain
228                let mut chain = middlewares.to_vec();
229
230                // Add final handler as last middleware
231                let final_handler = Arc::new(move |req: Request, _next: Next| {
232                    let h = handler.clone();
233                    async move { h.call(req).await }
234                });
235                chain.push(final_handler as Arc<dyn Middleware>);
236
237                let next = Next::new(Arc::new(chain));
238                next.run(request).await
239            }
240        }
241        Err(e) => Err(e),
242    };
243
244    // Convert Result to Response
245    let response = match result {
246        Ok(resp) => resp,
247        Err(err) => Response::from_error(err),
248    };
249
250    response.into_hyper()
251}