1use std::collections::HashMap;
7use std::net::SocketAddr;
8use std::sync::Arc;
9
10use axum::{
11 extract::{Path, Query},
12 http::Method,
13 middleware::{self, Next},
14 response::{IntoResponse, Response as AxumResponse},
15 routing::{delete, get, patch, post, put},
16 Json, Router as AxumRouter,
17};
18use serde_json::{json, Value};
19use tokio::net::TcpListener;
20use tower::ServiceBuilder;
21use tower_http::{
22 cors::CorsLayer,
23 trace::TraceLayer,
24};
25use tracing::{info, warn};
26
27use crate::{
28 config::Config,
29 errors::{Result, RustisanError},
30 routing::{Route, RouteGroup, Router},
31};
32
33pub struct Application {
35 config: Config,
37 router: Router,
39 state: HashMap<String, Value>,
41 built: bool,
43 axum_router: Option<AxumRouter>,
45}
46
47#[derive(Clone)]
49pub struct AppState {
50 pub config: Arc<Config>,
52 pub data: Arc<HashMap<String, Value>>,
54}
55
56impl Application {
57 pub fn new() -> Self {
59 Self {
60 config: Config::default(),
61 router: Router::new(),
62 state: HashMap::new(),
63 built: false,
64 axum_router: None,
65 }
66 }
67
68 pub fn with_config(config: Config) -> Self {
70 Self {
71 config,
72 router: Router::new(),
73 state: HashMap::new(),
74 built: false,
75 axum_router: None,
76 }
77 }
78
79 pub fn router(&mut self) -> &mut Router {
81 &mut self.router
82 }
83
84 pub fn set_state<K, V>(&mut self, key: K, value: V)
86 where
87 K: Into<String>,
88 V: Into<Value>,
89 {
90 self.state.insert(key.into(), value.into());
91 }
92
93 pub fn get_state(&self, key: &str) -> Option<&Value> {
95 self.state.get(key)
96 }
97
98 pub async fn build(&mut self) -> Result<()> {
100 if self.built {
101 return Ok(());
102 }
103
104 info!("🔧 Building Rustisan application...");
105
106 let app_state = AppState {
108 config: Arc::new(self.config.clone()),
109 data: Arc::new(self.state.clone()),
110 };
111
112 let mut axum_router = AxumRouter::new();
114
115 axum_router = self.register_routes(axum_router).await?;
117
118 axum_router = axum_router
120 .layer(
121 ServiceBuilder::new()
122 .layer(TraceLayer::new_for_http())
123 .layer(CorsLayer::permissive())
124 .layer(middleware::from_fn(error_handler)),
125 );
126
127 self.axum_router = Some(axum_router);
128 self.built = true;
129
130 info!("✅ Application built successfully");
131 Ok(())
132 }
133
134 async fn register_routes(
136 &self,
137 mut axum_router: AxumRouter,
138 ) -> Result<AxumRouter> {
139 info!("📍 Registering routes...");
140
141 for route in &self.router.routes {
143 axum_router = self.register_single_route(axum_router, route)?;
144 }
145
146 for group in &self.router.groups {
148 axum_router = self.register_group_routes(axum_router, group)?;
149 }
150
151 info!("📍 {} routes registered", self.router.routes.len());
152 Ok(axum_router)
153 }
154
155 fn register_single_route(
157 &self,
158 axum_router: AxumRouter,
159 route: &Route,
160 ) -> Result<AxumRouter> {
161 let path = route.path.clone();
162 let method = route.method.clone();
163
164 let handler = move || async move {
166 Json(json!({
167 "message": format!("Route {} {} handled", method, path),
168 "status": "success"
169 }))
170 };
171
172 let router = match route.method {
173 Method::GET => axum_router.route(&route.path, get(handler)),
174 Method::POST => axum_router.route(&route.path, post(handler)),
175 Method::PUT => axum_router.route(&route.path, put(handler)),
176 Method::PATCH => axum_router.route(&route.path, patch(handler)),
177 Method::DELETE => axum_router.route(&route.path, delete(handler)),
178 _ => {
179 warn!("Unsupported HTTP method: {}", route.method);
180 return Ok(axum_router);
181 }
182 };
183
184 Ok(router)
185 }
186
187 fn register_group_routes(
189 &self,
190 mut axum_router: AxumRouter,
191 group: &RouteGroup,
192 ) -> Result<AxumRouter> {
193 for route in &group.routes {
194 axum_router = self.register_single_route(axum_router, route)?;
195 }
196 Ok(axum_router)
197 }
198
199 pub async fn serve(&mut self, addr: SocketAddr) -> Result<()> {
201 if !self.built {
202 self.build().await?;
203 }
204
205 let axum_router = self
206 .axum_router
207 .take()
208 .ok_or_else(|| RustisanError::InternalError("Application not built".to_string()))?;
209
210 info!("🚀 Starting Rustisan server on {}", addr);
211 info!("📚 Routes available:");
212
213 for route in &self.router.routes {
215 info!(" {} {}", route.method, route.path);
216 }
217
218 for group in &self.router.groups {
219 for route in &group.routes {
220 info!(" {} {}", route.method, route.path);
221 }
222 }
223
224 let listener = TcpListener::bind(addr).await.map_err(|e| {
225 RustisanError::InternalError(format!("Failed to bind to address {}: {}", addr, e))
226 })?;
227
228 info!("✅ Server running on http://{}", addr);
229
230 axum::serve(listener, axum_router).await.map_err(|e| {
231 RustisanError::InternalError(format!("Server error: {}", e))
232 })?;
233
234 Ok(())
235 }
236
237 pub async fn serve_default(&mut self) -> Result<()> {
239 let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
240 self.serve(addr).await
241 }
242
243 pub fn config(&self) -> &Config {
245 &self.config
246 }
247
248 pub fn set_config(&mut self, config: Config) {
250 self.config = config;
251 self.built = false; }
253}
254
255impl Default for Application {
256 fn default() -> Self {
257 Self::new()
258 }
259}
260
261async fn error_handler(
263 request: axum::extract::Request,
264 next: Next,
265) -> AxumResponse {
266 next.run(request).await
267}
268
269pub async fn route_with_params_handler(
271 Path(params): Path<HashMap<String, String>>,
272 Query(query): Query<HashMap<String, String>>,
273) -> impl IntoResponse {
274 Json(json!({
275 "path_params": params,
276 "query_params": query,
277 "message": "Route with parameters handled successfully"
278 }))
279}
280
281pub async fn json_handler(
283 Json(payload): Json<Value>,
284) -> impl IntoResponse {
285 Json(json!({
286 "received": payload,
287 "message": "JSON payload processed successfully"
288 }))
289}
290
291#[cfg(test)]
292mod tests {
293 use super::*;
294
295 #[tokio::test]
296 async fn test_application_creation() {
297 let app = Application::new();
298 assert!(!app.built);
299 assert!(app.axum_router.is_none());
300 }
301
302 #[tokio::test]
303 async fn test_application_build() {
304 let mut app = Application::new();
305
306 app.router().get("/test", || async {
308 crate::Response::ok("Test route").unwrap()
309 });
310
311 let result = app.build().await;
312 assert!(result.is_ok());
313 assert!(app.built);
314 assert!(app.axum_router.is_some());
315 }
316
317 #[test]
318 fn test_application_state() {
319 let mut app = Application::new();
320 app.set_state("test_key", "test_value");
321
322 assert_eq!(
323 app.get_state("test_key"),
324 Some(&Value::String("test_value".to_string()))
325 );
326 }
327
328 #[test]
329 fn test_application_config() {
330 let config = Config::default();
331 let app = Application::with_config(config.clone());
332 assert_eq!(app.config().app_name, config.app_name);
333 }
334}