rustnext/
app.rs

1use crate::{Router, Request, Response, Handler, static_files::StaticFiles, template::TemplateEngine, error::{AppError, IntoResponse}};
2use async_trait::async_trait;
3use std::sync::Arc; // Ensure Arc is imported
4
5pub struct App {
6    router: Router,
7    static_handler: Option<Arc<StaticFiles>>,
8    template_engine: Option<Arc<TemplateEngine>>,
9    // This field type is correct, it stores an Arc to the error handler trait object
10    error_handler: Arc<dyn Fn(AppError) -> Result<Response, Box<dyn std::error::Error + Send + Sync>> + Send + Sync>,
11}
12
13impl App {
14    pub fn new() -> Self {
15        App {
16            router: Router::new(),
17            static_handler: None,
18            template_engine: None,
19            // Default error handler is also an Arc
20            error_handler: Arc::new(|err: AppError| err.into_response()),
21        }
22    }
23
24    pub fn router(mut self, router: Router) -> Self {
25        self.router = router;
26        self
27    }
28
29    pub fn static_files(mut self, dir: &str, prefix: &str) -> Self {
30        self.static_handler = Some(Arc::new(StaticFiles::new(dir, prefix)));
31        self
32    }
33
34    pub fn templates(mut self, engine: TemplateEngine) -> Self {
35        self.template_engine = Some(Arc::new(engine));
36        self
37    }
38
39    // Modified: Now accepts an Arc<dyn Fn(...)> directly
40    pub fn error_handler(mut self, handler: Arc<dyn Fn(AppError) -> Result<Response, Box<dyn std::error::Error + Send + Sync>> + Send + Sync + 'static>) -> Self
41    {
42        self.error_handler = handler; // Directly assign the Arc
43        self
44    }
45}
46
47#[async_trait]
48impl Handler for App {
49    async fn handle(&self, req: Request) -> Result<Response, Box<dyn std::error::Error + Send + Sync>> {
50        if let Some(static_handler) = &self.static_handler {
51            if req.uri.path().starts_with("/static") {
52                return static_handler.handle(req).await;
53            }
54        }
55
56        match self.router.handle_request(req).await {
57            Ok(response) => Ok(response),
58            Err(e) => {
59                let app_error: AppError = e.into();
60                (self.error_handler)(app_error)
61            }
62        }
63    }
64}