1pub mod handlers;
6pub mod routes;
7pub mod models;
9pub mod prometheus_client;
10pub mod time_travel_handlers;
11
12pub use models::{RequestLog, RouteInfo, ServerStatus, SystemInfo};
13pub use routes::create_admin_router;
14
15use std::net::SocketAddr;
16
17pub async fn start_admin_server(
33 addr: SocketAddr,
34 http_server_addr: Option<SocketAddr>,
35 ws_server_addr: Option<SocketAddr>,
36 grpc_server_addr: Option<SocketAddr>,
37 graphql_server_addr: Option<SocketAddr>,
38 api_enabled: bool,
39 prometheus_url: String,
40 chaos_api_state: Option<std::sync::Arc<mockforge_chaos::api::ChaosApiState>>,
41 latency_injector: Option<
42 std::sync::Arc<tokio::sync::RwLock<mockforge_core::latency::LatencyInjector>>,
43 >,
44 mockai: Option<
45 std::sync::Arc<tokio::sync::RwLock<mockforge_core::intelligent_behavior::MockAI>>,
46 >,
47 continuum_config: Option<mockforge_core::ContinuumConfig>,
48 virtual_clock: Option<std::sync::Arc<mockforge_core::VirtualClock>>,
49) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
50 let app = create_admin_router(
51 http_server_addr,
52 ws_server_addr,
53 grpc_server_addr,
54 graphql_server_addr,
55 api_enabled,
56 addr.port(),
57 prometheus_url,
58 chaos_api_state,
59 latency_injector,
60 mockai,
61 continuum_config,
62 virtual_clock,
63 );
64
65 tracing::info!("Starting MockForge Admin UI on {}", addr);
66
67 let listener = tokio::net::TcpListener::bind(addr).await.map_err(|e| {
68 format!(
69 "Failed to bind Admin UI server to port {}: {}\n\
70 Hint: The port may already be in use. Try using a different port with --admin-port or check if another process is using this port with: lsof -i :{} or netstat -tulpn | grep {}",
71 addr.port(), e, addr.port(), addr.port()
72 )
73 })?;
74
75 axum::serve(listener, app).await?;
76
77 Ok(())
78}
79
80pub fn get_admin_html() -> &'static str {
82 include_str!("../ui/dist/index.html")
83}
84
85pub fn get_admin_css() -> &'static str {
87 include_str!("../ui/dist/assets/index.css")
88}
89
90pub fn get_admin_js() -> &'static str {
92 include_str!("../ui/dist/assets/index.js")
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn test_get_admin_html() {
101 let html = get_admin_html();
102 assert!(!html.is_empty());
103 assert!(html.contains("<!DOCTYPE html>") || html.contains("<html"));
104 }
105
106 #[test]
107 fn test_get_admin_css() {
108 let css = get_admin_css();
109 assert!(!css.is_empty());
110 }
111
112 #[test]
113 fn test_get_admin_js() {
114 let js = get_admin_js();
115 assert!(!js.is_empty());
116 }
117}