1use axum::{
4 routing::{delete, get, post},
5 Router,
6};
7use tower_http::{compression::CompressionLayer, cors::CorsLayer};
8
9use crate::audit::init_global_audit_store;
10use crate::auth::init_global_user_store;
11use crate::handlers::analytics::AnalyticsState;
12use crate::handlers::AdminState;
13use crate::handlers::*;
14use crate::rbac::rbac_middleware;
15use crate::time_travel_handlers;
16use axum::middleware::from_fn;
17use mockforge_core::{get_global_logger, init_global_logger};
18
19pub fn create_admin_router(
35 http_server_addr: Option<std::net::SocketAddr>,
36 ws_server_addr: Option<std::net::SocketAddr>,
37 grpc_server_addr: Option<std::net::SocketAddr>,
38 graphql_server_addr: Option<std::net::SocketAddr>,
39 api_enabled: bool,
40 admin_port: u16,
41 prometheus_url: String,
42 chaos_api_state: Option<std::sync::Arc<mockforge_chaos::api::ChaosApiState>>,
43 latency_injector: Option<
44 std::sync::Arc<tokio::sync::RwLock<mockforge_core::latency::LatencyInjector>>,
45 >,
46 mockai: Option<
47 std::sync::Arc<tokio::sync::RwLock<mockforge_core::intelligent_behavior::MockAI>>,
48 >,
49 continuum_config: Option<mockforge_core::ContinuumConfig>,
50 virtual_clock: Option<std::sync::Arc<mockforge_core::VirtualClock>>,
51) -> Router {
52 let _logger = get_global_logger().unwrap_or_else(|| init_global_logger(1000));
54
55 let _audit_store = init_global_audit_store(10000);
57
58 let _user_store = init_global_user_store();
60
61 let state = AdminState::new(
62 http_server_addr,
63 ws_server_addr,
64 grpc_server_addr,
65 graphql_server_addr,
66 api_enabled,
67 admin_port,
68 chaos_api_state,
69 latency_injector,
70 mockai,
71 continuum_config,
72 virtual_clock,
73 );
74
75 let state_clone = state.clone();
77 tokio::spawn(async move {
78 state_clone.start_system_monitoring().await;
79 });
80 let mut router = Router::new()
81 .route("/", get(serve_admin_html))
83 .route("/assets/index.css", get(serve_admin_css))
84 .route("/assets/index.js", get(serve_admin_js))
85 .route("/assets/{filename}", get(serve_vendor_asset))
86 .route("/api-docs", get(serve_api_docs))
87 .route("/mockforge-icon.png", get(serve_icon))
88 .route("/mockforge-icon-32.png", get(serve_icon_32))
89 .route("/mockforge-icon-48.png", get(serve_icon_48))
90 .route("/mockforge-logo.png", get(serve_logo))
91 .route("/mockforge-logo-40.png", get(serve_logo_40))
92 .route("/mockforge-logo-80.png", get(serve_logo_80))
93 .route("/manifest.json", get(serve_manifest))
94 .route("/sw.js", get(serve_service_worker))
95 .route("/__mockforge/auth/login", post(crate::auth::login))
97 .route("/__mockforge/auth/refresh", post(crate::auth::refresh_token))
98 .route("/__mockforge/auth/logout", post(crate::auth::logout))
99 .route("/__mockforge/health", get(get_health));
100
101 router = router
103 .route("/__mockforge/dashboard", get(get_dashboard))
104 .route("/_mf", get(get_dashboard)) .route("/admin/server-info", get(get_server_info))
106 .route("/__mockforge/server-info", get(get_server_info))
107 .route("/__mockforge/routes", get(get_routes))
108 .route("/__mockforge/logs", get(get_logs))
109 .route("/__mockforge/logs/sse", get(logs_sse))
110 .route("/__mockforge/metrics", get(get_metrics))
111 .route("/__mockforge/api/reality/trace/{request_id}", get(get_reality_trace))
112 .route("/__mockforge/api/reality/response-trace/{request_id}", get(get_response_trace))
113 .route("/__mockforge/config", get(get_config))
114 .route("/__mockforge/config/latency", post(update_latency))
115 .route("/__mockforge/config/faults", post(update_faults))
116 .route("/__mockforge/config/proxy", post(update_proxy))
117 .route("/__mockforge/config/traffic-shaping", post(update_traffic_shaping))
118 .route("/__mockforge/logs", delete(clear_logs))
119 .route("/__mockforge/restart", post(restart_servers))
120 .route("/__mockforge/restart/status", get(get_restart_status))
121 .route("/__mockforge/fixtures", get(get_fixtures))
122 .route("/__mockforge/fixtures/{id}", delete(delete_fixture))
123 .route("/__mockforge/fixtures/bulk", delete(delete_fixtures_bulk))
124 .route("/__mockforge/audit/logs", get(get_audit_logs))
125 .route("/__mockforge/audit/stats", get(get_audit_stats))
126 .route("/__mockforge/fixtures/{id}/download", get(download_fixture))
127 .route("/__mockforge/fixtures/{id}/rename", post(rename_fixture))
128 .route("/__mockforge/fixtures/{id}/move", post(move_fixture))
129 .route("/__mockforge/import/postman", post(import_postman))
131 .route("/__mockforge/import/insomnia", post(import_insomnia))
132 .route("/__mockforge/import/curl", post(import_curl))
133 .route("/__mockforge/import/preview", post(preview_import))
134 .route("/__mockforge/import/history", get(get_import_history))
135 .route("/__mockforge/import/history/clear", post(clear_import_history))
136 .route("/__mockforge/plugins", get(get_plugins))
138 .route("/__mockforge/plugins/status", get(get_plugin_status))
139 .route("/__mockforge/plugins/{id}", get(get_plugin_details))
140 .route("/__mockforge/plugins/{id}", delete(delete_plugin))
141 .route("/__mockforge/plugins/reload", post(reload_plugin))
142 .route("/__mockforge/chains", get(proxy_chains_list))
146 .route("/__mockforge/chains", post(proxy_chains_create))
147 .route("/__mockforge/chains/{id}", get(proxy_chain_get))
148 .route("/__mockforge/chains/{id}", axum::routing::put(proxy_chain_update))
149 .route("/__mockforge/chains/{id}", delete(proxy_chain_delete))
150 .route("/__mockforge/chains/{id}/execute", post(proxy_chain_execute))
151 .route("/__mockforge/chains/{id}/validate", post(proxy_chain_validate))
152 .route("/__mockforge/chains/{id}/history", get(proxy_chain_history))
153 .route("/__mockforge/graph", get(get_graph))
155 .route("/__mockforge/graph/sse", get(graph_sse))
156 .route("/__mockforge/validation", get(get_validation))
158 .route("/__mockforge/validation", post(update_validation))
159 .route("/__mockforge/migration/routes", get(migration::get_migration_routes))
161 .route("/__mockforge/migration/routes/{pattern}/toggle", post(migration::toggle_route_migration))
162 .route("/__mockforge/migration/routes/{pattern}", axum::routing::put(migration::set_route_migration_mode))
163 .route("/__mockforge/migration/groups/{group}/toggle", post(migration::toggle_group_migration))
164 .route("/__mockforge/migration/groups/{group}", axum::routing::put(migration::set_group_migration_mode))
165 .route("/__mockforge/migration/groups", get(migration::get_migration_groups))
166 .route("/__mockforge/migration/status", get(migration::get_migration_status))
167 .route("/__mockforge/env", get(get_env_vars))
169 .route("/__mockforge/env", post(update_env_var))
170 .route("/__mockforge/files/content", post(get_file_content))
172 .route("/__mockforge/files/save", post(save_file_content))
173 .route("/__mockforge/smoke", get(get_smoke_tests))
175 .route("/__mockforge/smoke/run", get(run_smoke_tests_endpoint))
176 .route("/__mockforge/time-travel/status", get(time_travel_handlers::get_time_travel_status))
178 .route("/__mockforge/time-travel/enable", post(time_travel_handlers::enable_time_travel))
179 .route("/__mockforge/time-travel/disable", post(time_travel_handlers::disable_time_travel))
180 .route("/__mockforge/time-travel/advance", post(time_travel_handlers::advance_time))
181 .route("/__mockforge/time-travel/set", post(time_travel_handlers::set_time))
182 .route("/__mockforge/time-travel/scale", post(time_travel_handlers::set_time_scale))
183 .route("/__mockforge/time-travel/reset", post(time_travel_handlers::reset_time_travel))
184 .route("/__mockforge/time-travel/schedule", post(time_travel_handlers::schedule_response))
185 .route("/__mockforge/time-travel/scheduled", get(time_travel_handlers::list_scheduled_responses))
186 .route("/__mockforge/time-travel/scheduled/{id}", delete(time_travel_handlers::cancel_scheduled_response))
187 .route("/__mockforge/time-travel/scheduled/clear", post(time_travel_handlers::clear_scheduled_responses))
188 .route("/__mockforge/time-travel/scenario/save", post(time_travel_handlers::save_scenario))
189 .route("/__mockforge/time-travel/scenario/load", post(time_travel_handlers::load_scenario))
190 .route("/__mockforge/time-travel/cron", get(time_travel_handlers::list_cron_jobs))
192 .route("/__mockforge/time-travel/cron", post(time_travel_handlers::create_cron_job))
193 .route("/__mockforge/time-travel/cron/{id}", get(time_travel_handlers::get_cron_job))
194 .route("/__mockforge/time-travel/cron/{id}", delete(time_travel_handlers::delete_cron_job))
195 .route("/__mockforge/time-travel/cron/{id}/enable", post(time_travel_handlers::set_cron_job_enabled))
196 .route("/__mockforge/time-travel/mutations", get(time_travel_handlers::list_mutation_rules))
198 .route("/__mockforge/time-travel/mutations", post(time_travel_handlers::create_mutation_rule))
199 .route("/__mockforge/time-travel/mutations/{id}", get(time_travel_handlers::get_mutation_rule))
200 .route("/__mockforge/time-travel/mutations/{id}", delete(time_travel_handlers::delete_mutation_rule))
201 .route("/__mockforge/time-travel/mutations/{id}/enable", post(time_travel_handlers::set_mutation_rule_enabled))
202 .route("/__mockforge/verification/verify", post(verification::verify))
204 .route("/__mockforge/verification/count", post(verification::count))
205 .route("/__mockforge/verification/sequence", post(verification::verify_sequence_handler))
206 .route("/__mockforge/verification/never", post(verification::verify_never_handler))
207 .route("/__mockforge/verification/at-least", post(verification::verify_at_least_handler))
208 .route("/__mockforge/reality/level", get(get_reality_level))
210 .route("/__mockforge/reality/level", axum::routing::put(set_reality_level))
211 .route("/__mockforge/reality/presets", get(list_reality_presets))
212 .route("/__mockforge/reality/presets/import", post(import_reality_preset))
213 .route("/__mockforge/reality/presets/export", post(export_reality_preset))
214 .route("/__mockforge/continuum/ratio", get(get_continuum_ratio))
216 .route("/__mockforge/continuum/ratio", axum::routing::put(set_continuum_ratio))
217 .route("/__mockforge/continuum/schedule", get(get_continuum_schedule))
218 .route("/__mockforge/continuum/schedule", axum::routing::put(set_continuum_schedule))
219 .route("/__mockforge/continuum/advance", post(advance_continuum_ratio))
220 .route("/__mockforge/continuum/enabled", axum::routing::put(set_continuum_enabled))
221 .route("/__mockforge/continuum/overrides", get(get_continuum_overrides))
222 .route("/__mockforge/continuum/overrides", axum::routing::delete(clear_continuum_overrides))
223 .route("/__mockforge/contract-diff/upload", post(contract_diff::upload_request))
225 .route("/__mockforge/contract-diff/submit", post(contract_diff::submit_request))
226 .route("/__mockforge/contract-diff/captures", get(contract_diff::get_captured_requests))
227 .route("/__mockforge/contract-diff/captures/{id}", get(contract_diff::get_captured_request))
228 .route("/__mockforge/contract-diff/captures/{id}/analyze", post(contract_diff::analyze_captured_request))
229 .route("/__mockforge/contract-diff/captures/{id}/patch", post(contract_diff::generate_patch_file))
230 .route("/__mockforge/contract-diff/statistics", get(contract_diff::get_capture_statistics))
231 .route("/__mockforge/playground/endpoints", get(playground::list_playground_endpoints))
233 .route("/__mockforge/playground/execute", post(playground::execute_rest_request))
234 .route("/__mockforge/playground/graphql", post(playground::execute_graphql_query))
235 .route("/__mockforge/playground/graphql/introspect", get(playground::graphql_introspect))
236 .route("/__mockforge/playground/history", get(playground::get_request_history))
237 .route("/__mockforge/playground/history/{id}/replay", post(playground::replay_request))
238 .route("/__mockforge/playground/snippets", post(playground::generate_code_snippet))
239 .route("/api/v2/voice/process", post(voice::process_voice_command))
241 .route("/__mockforge/voice/process", post(voice::process_voice_command))
242 .route("/api/v2/voice/transpile-hook", post(voice::transpile_hook))
243 .route("/__mockforge/voice/transpile-hook", post(voice::transpile_hook))
244 .route(
245 "/api/v2/voice/create-workspace-scenario",
246 post(voice::create_workspace_scenario),
247 )
248 .route(
249 "/__mockforge/voice/create-workspace-scenario",
250 post(voice::create_workspace_scenario),
251 )
252 .route(
253 "/api/v2/voice/create-workspace-preview",
254 post(voice::create_workspace_preview),
255 )
256 .route(
257 "/__mockforge/voice/create-workspace-preview",
258 post(voice::create_workspace_preview),
259 )
260 .route("/api/v1/ai-studio/chat", post(ai_studio::chat))
263 .route("/__mockforge/ai-studio/chat", post(ai_studio::chat))
264 .route("/api/v1/ai-studio/generate-mock", post(ai_studio::generate_mock))
265 .route("/__mockforge/ai-studio/generate-mock", post(ai_studio::generate_mock))
266 .route("/api/v1/ai-studio/debug-test", post(ai_studio::debug_test))
267 .route("/__mockforge/ai-studio/debug-test", post(ai_studio::debug_test))
268 .route("/api/v1/ai-studio/debug/analyze-with-context", post(ai_studio::debug_analyze_with_context))
269 .route("/__mockforge/ai-studio/debug/analyze-with-context", post(ai_studio::debug_analyze_with_context))
270 .route("/api/v1/ai-studio/generate-persona", post(ai_studio::generate_persona))
271 .route("/__mockforge/ai-studio/generate-persona", post(ai_studio::generate_persona))
272 .route("/api/v1/ai-studio/freeze", post(ai_studio::freeze_artifact))
273 .route("/__mockforge/ai-studio/freeze", post(ai_studio::freeze_artifact))
274 .route("/api/v1/ai-studio/frozen", get(ai_studio::list_frozen))
275 .route("/__mockforge/ai-studio/frozen", get(ai_studio::list_frozen))
276 .route("/api/v1/ai-studio/apply-patch", post(ai_studio::apply_patch))
277 .route("/__mockforge/ai-studio/apply-patch", post(ai_studio::apply_patch))
278 .route("/api/v1/ai-studio/usage", get(ai_studio::get_usage))
279 .route("/__mockforge/ai-studio/usage", get(ai_studio::get_usage))
280 .route("/api/v1/ai-studio/org-controls", get(ai_studio::get_org_controls))
281 .route("/__mockforge/ai-studio/org-controls", get(ai_studio::get_org_controls))
282 .route("/api/v1/ai-studio/org-controls", axum::routing::put(ai_studio::update_org_controls))
283 .route("/__mockforge/ai-studio/org-controls", axum::routing::put(ai_studio::update_org_controls))
284 .route("/api/v1/ai-studio/org-controls/usage", get(ai_studio::get_org_usage))
285 .route("/__mockforge/ai-studio/org-controls/usage", get(ai_studio::get_org_usage))
286 .route("/api/v1/ai-studio/contract-diff/query", post(ai_studio::contract_diff_query))
287 .route("/__mockforge/ai-studio/contract-diff/query", post(ai_studio::contract_diff_query))
288 .route("/api/v2/failures/analyze", post(failure_analysis::analyze_failure))
290 .route("/api/v2/failures/{request_id}", get(failure_analysis::get_failure_analysis))
291 .route("/api/v2/failures/recent", get(failure_analysis::list_recent_failures))
292 .route("/__mockforge/failures/analyze", post(failure_analysis::analyze_failure))
293 .route("/__mockforge/failures/{request_id}", get(failure_analysis::get_failure_analysis))
294 .route("/__mockforge/failures/recent", get(failure_analysis::list_recent_failures))
295 .route("/__mockforge/community/showcase/projects", get(community::get_showcase_projects))
297 .route("/__mockforge/community/showcase/projects/{id}", get(community::get_showcase_project))
298 .route("/__mockforge/community/showcase/categories", get(community::get_showcase_categories))
299 .route("/__mockforge/community/showcase/stories", get(community::get_success_stories))
300 .route("/__mockforge/community/showcase/submit", post(community::submit_showcase_project))
301 .route("/__mockforge/community/learning/resources", get(community::get_learning_resources))
302 .route("/__mockforge/community/learning/resources/{id}", get(community::get_learning_resource))
303 .route("/__mockforge/community/learning/categories", get(community::get_learning_categories))
304 .route("/__mockforge/flows", get(behavioral_cloning::get_flows))
306 .route("/__mockforge/flows/{id}", get(behavioral_cloning::get_flow))
307 .route("/__mockforge/flows/{id}/tag", axum::routing::put(behavioral_cloning::tag_flow))
308 .route("/__mockforge/flows/{id}/compile", post(behavioral_cloning::compile_flow))
309 .route("/__mockforge/scenarios", get(behavioral_cloning::get_scenarios))
310 .route("/__mockforge/scenarios/{id}", get(behavioral_cloning::get_scenario))
311 .route("/__mockforge/scenarios/{id}/export", get(behavioral_cloning::export_scenario))
312 .route("/health/live", get(health::liveness_probe))
314 .route("/health/ready", get(health::readiness_probe))
315 .route("/health/startup", get(health::startup_probe))
316 .route("/health", get(health::deep_health_check))
317 .route("/healthz", get(health::deep_health_check))
319 .route("/readyz", get(health::readiness_probe))
320 .route("/livez", get(health::liveness_probe))
321 .route("/startupz", get(health::startup_probe));
322
323 let analytics_state = AnalyticsState::new(prometheus_url);
325
326 let analytics_router = Router::new()
327 .route("/__mockforge/analytics/summary", get(analytics::get_summary))
328 .route("/__mockforge/analytics/requests", get(analytics::get_requests))
329 .route("/__mockforge/analytics/endpoints", get(analytics::get_endpoints))
330 .route("/__mockforge/analytics/websocket", get(analytics::get_websocket))
331 .route("/__mockforge/analytics/smtp", get(analytics::get_smtp))
332 .route("/__mockforge/analytics/system", get(analytics::get_system))
333 .with_state(analytics_state);
334
335 router = router.merge(analytics_router);
336
337 {
341 use crate::handlers::coverage_metrics::CoverageMetricsState;
342 use mockforge_analytics::AnalyticsDatabase;
343 use std::path::PathBuf;
344 use std::sync::Arc;
345 use tokio::sync::OnceCell;
346
347 let db_path = std::env::var("MOCKFORGE_ANALYTICS_DB_PATH")
349 .ok()
350 .map(PathBuf::from)
351 .unwrap_or_else(|| PathBuf::from("analytics.db"));
352
353 let db_path_clone = db_path.clone();
354 let coverage_db = Arc::new(OnceCell::new());
355 let coverage_db_clone = coverage_db.clone();
356
357 tokio::spawn(async move {
359 match AnalyticsDatabase::new(&db_path_clone).await {
360 Ok(analytics_db) => {
361 if let Err(e) = analytics_db.run_migrations().await {
362 tracing::warn!("Failed to run analytics database migrations: {}. Coverage metrics routes may not work correctly.", e);
363 } else {
364 let _ = coverage_db_clone.set(analytics_db);
365 tracing::info!("Analytics database initialized for coverage metrics");
366 }
367 }
368 Err(e) => {
369 tracing::debug!("Failed to initialize analytics database for coverage metrics: {}. Coverage metrics routes will be unavailable.", e);
370 }
371 }
372 });
373
374 let coverage_state = CoverageMetricsState { db: coverage_db };
376
377 use crate::handlers::coverage_metrics;
379 router = router
380 .route("/api/v2/analytics/scenarios/usage", get(coverage_metrics::get_scenario_usage))
381 .route("/api/v2/analytics/personas/ci-hits", get(coverage_metrics::get_persona_ci_hits))
382 .route(
383 "/api/v2/analytics/endpoints/coverage",
384 get(coverage_metrics::get_endpoint_coverage),
385 )
386 .route(
387 "/api/v2/analytics/reality-levels/staleness",
388 get(coverage_metrics::get_reality_level_staleness),
389 )
390 .route(
391 "/api/v2/analytics/drift/percentage",
392 get(coverage_metrics::get_drift_percentage),
393 )
394 .layer(axum::extract::Extension(coverage_state));
395
396 tracing::info!(
397 "Coverage metrics routes mounted at /api/v2/analytics (database initializing)"
398 );
399 }
400
401 {
412 use crate::handlers::workspaces::WorkspaceState;
413 use mockforge_core::multi_tenant::{MultiTenantConfig, MultiTenantWorkspaceRegistry};
414 use std::sync::Arc;
415
416 let mt_config = MultiTenantConfig {
418 enabled: true,
419 default_workspace: "default".to_string(),
420 ..Default::default()
421 };
422 let registry = MultiTenantWorkspaceRegistry::new(mt_config);
423 let workspace_state = WorkspaceState::new(Arc::new(tokio::sync::RwLock::new(registry)));
424
425 use crate::handlers::workspaces;
427 let workspace_router = Router::new()
428 .route("/__mockforge/workspaces", get(workspaces::list_workspaces))
429 .route("/__mockforge/workspaces", post(workspaces::create_workspace))
430 .route("/__mockforge/workspaces/{workspace_id}", get(workspaces::get_workspace))
431 .route(
432 "/__mockforge/workspaces/{workspace_id}",
433 axum::routing::put(workspaces::update_workspace),
434 )
435 .route("/__mockforge/workspaces/{workspace_id}", delete(workspaces::delete_workspace))
436 .route("/__mockforge/workspaces/{workspace_id}/stats", get(workspaces::get_workspace_stats))
437 .route("/__mockforge/workspaces/{workspace_id}/environments", get(workspaces::list_mock_environments))
439 .route("/__mockforge/workspaces/{workspace_id}/environments/{env_name}", get(workspaces::get_mock_environment))
440 .route("/__mockforge/workspaces/{workspace_id}/environments/{env_name}", axum::routing::put(workspaces::update_mock_environment))
441 .route("/__mockforge/workspaces/{workspace_id}/environments/active", axum::routing::post(workspaces::set_active_mock_environment))
442 .route("/api/v2/voice/create-workspace-confirm", post(voice::create_workspace_confirm))
448 .route(
449 "/__mockforge/voice/create-workspace-confirm",
450 post(voice::create_workspace_confirm),
451 )
452 .with_state(workspace_state);
453
454 router = router.merge(workspace_router);
455 tracing::info!("Workspace router mounted with WorkspaceState");
456
457 #[cfg(feature = "database-auth")]
461 {
462 use crate::handlers::promotions;
463 use crate::handlers::promotions::PromotionState;
464 use mockforge_collab::promotion::PromotionService;
465 use sqlx::{sqlite::SqlitePoolOptions, Pool, Sqlite};
466 use std::sync::Arc;
467
468 let db_url = std::env::var("MOCKFORGE_COLLAB_DB_URL")
470 .unwrap_or_else(|_| "sqlite://mockforge-collab.db".to_string());
471
472 tracing::debug!("Promotion routes require async database initialization - will be available once database is configured");
477 }
478 #[cfg(not(feature = "database-auth"))]
479 {
480 tracing::debug!("Promotion routes require 'database-auth' feature - not available");
481 }
482 }
483
484 router = router.route("/{*path}", get(serve_admin_html));
501
502 router = router.layer(from_fn(rbac_middleware));
506
507 router
508 .layer(CompressionLayer::new())
509 .layer(CorsLayer::permissive())
510 .with_state(state)
511}
512
513#[cfg(test)]
514mod tests {
515 use super::*;
516
517 #[tokio::test]
518 async fn test_create_admin_router() {
519 let http_addr: std::net::SocketAddr = "127.0.0.1:3000".parse().unwrap();
520 let router = create_admin_router(
521 Some(http_addr),
522 None,
523 None,
524 None,
525 true,
526 8080,
527 "http://localhost:9090".to_string(),
528 None,
529 None,
530 None,
531 None,
532 None,
533 );
534
535 let _ = router;
537 }
538
539 #[tokio::test]
540 async fn test_create_admin_router_no_servers() {
541 let router = create_admin_router(
542 None,
543 None,
544 None,
545 None,
546 false,
547 8080,
548 "http://localhost:9090".to_string(),
549 None,
550 None,
551 None,
552 None,
553 None,
554 );
555
556 let _ = router;
558 }
559}