1use crate::{Router, Request, Response, Handler, static_files::StaticFiles, template::TemplateEngine, error::{AppError, IntoResponse}};
2use async_trait::async_trait;
3use std::sync::Arc; pub struct App {
6 router: Router,
7 static_handler: Option<Arc<StaticFiles>>,
8 template_engine: Option<Arc<TemplateEngine>>,
9 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 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 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; 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}