cargo_coupling/web/
server.rs1use std::net::SocketAddr;
7use std::sync::Arc;
8
9use axum::Router;
10use tokio::net::TcpListener;
11
12use crate::balance::IssueThresholds;
13use crate::metrics::ProjectMetrics;
14
15use super::routes;
16
17pub struct AppState {
19 pub metrics: ProjectMetrics,
20 pub thresholds: IssueThresholds,
21 pub api_endpoint: Option<String>,
22}
23
24pub struct ServerConfig {
26 pub port: u16,
27 pub open_browser: bool,
28 pub api_endpoint: Option<String>,
29}
30
31impl Default for ServerConfig {
32 fn default() -> Self {
33 Self {
34 port: 3000,
35 open_browser: true,
36 api_endpoint: None,
37 }
38 }
39}
40
41pub async fn start_server(
43 metrics: ProjectMetrics,
44 thresholds: IssueThresholds,
45 config: ServerConfig,
46) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
47 let state = Arc::new(AppState {
48 metrics,
49 thresholds,
50 api_endpoint: config.api_endpoint.clone(),
51 });
52
53 let app = Router::new()
54 .merge(routes::api_routes())
55 .merge(routes::static_routes())
56 .with_state(state);
57
58 let addr = SocketAddr::from(([127, 0, 0, 1], config.port));
59 let listener = TcpListener::bind(addr).await?;
60
61 let url = format!("http://localhost:{}", config.port);
62 eprintln!("Starting web server at {}", url);
63
64 if config.open_browser {
65 eprintln!("Opening browser...");
66 if let Err(e) = open::that(&url) {
67 eprintln!("Warning: Could not open browser: {}", e);
68 eprintln!("Please open {} manually", url);
69 }
70 }
71
72 eprintln!("Press Ctrl+C to stop the server");
73
74 axum::serve(listener, app).await?;
75
76 Ok(())
77}