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