1use std::net::SocketAddr;
7
8use axum::Router;
9
10use crate::{di::Container, error::Result};
11
12pub struct App {
29 container: Container,
30 router: Router,
31}
32
33impl App {
34 pub fn new() -> Self {
36 Self {
37 container: Container::new(),
38 router: Router::new(),
39 }
40 }
41
42 pub fn container(&self) -> &Container {
44 &self.container
45 }
46
47 pub fn container_mut(&mut self) -> &mut Container {
49 &mut self.container
50 }
51
52 pub fn router(&self) -> &Router {
54 &self.router
55 }
56
57 pub fn build(self) -> Router {
59 self.router
60 }
61
62 pub async fn serve(self, addr: impl Into<SocketAddr>) -> Result<()> {
70 let addr = addr.into();
71 let listener = self.create_listener_at(addr).await?;
72 let router = self.router;
73 Self::run_server_on(listener, router).await
74 }
75
76 async fn create_listener_at(&self, addr: SocketAddr) -> Result<tokio::net::TcpListener> {
78 tokio::net::TcpListener::bind(addr).await.map_err(|e| {
79 crate::error::Error::server_error(format!("Failed to bind to {}: {}", addr, e))
80 })
81 }
82
83 async fn run_server_on(listener: tokio::net::TcpListener, router: Router) -> Result<()> {
85 let addr = listener.local_addr().unwrap();
86 tracing::info!("Server running on http://{}", addr);
87
88 axum::serve(listener, router)
89 .await
90 .map_err(|e| crate::error::Error::server_error(format!("Server error: {}", e)))
91 }
92}
93
94impl Default for App {
95 fn default() -> Self {
96 Self::new()
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 #[test]
105 fn test_app_creation() {
106 let app = App::new();
107 assert!(app.container().is_empty());
108 }
109
110 #[test]
111 fn test_app_default() {
112 let app = App::default();
113 assert!(app.container().is_empty());
114 }
115}