use std::net::SocketAddr; use std::path::Path; use std::sync::{Arc, RwLock}; use std::time::Duration; use axum::{routing::any, Router}; use notify_debouncer_mini::{new_debouncer, notify::*}; use mock_server::loader::MockLoader; use mock_server::router::MockRouter; use mock_server::handler::{mock_handler, AppState}; /// 打印启动 Banner fn print_banner() { let version = env!("CARGO_PKG_VERSION"); // 蓝色 ANSI 转义码 println!("\x1b[34m"); println!(" ███╗ ███╗ ██████╗██████╗ ██████╗ "); println!(" ████╗ ████║██╔════╝██╔══██╗██╔═══██╗"); println!(" ██╔████╔██║██║ ██████╔╝██║ ██║"); println!(" ██║╚██╔╝██║██║ ██╔══██╗██║ ██║"); println!(" ██║ ╚═╝ ██║╚██████╗██║ ██║╚██████╔╝"); println!(" ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═════╝ "); println!("\x1b[0m"); // 重置颜色 println!(" Mock Server v{}\n", version); } #[tokio::main] async fn main() { print_banner(); tracing_subscriber::fmt::init(); let mocks_dir = Path::new("./mocks"); if !mocks_dir.exists() { std::fs::create_dir_all(mocks_dir).unwrap(); } // 1. 初始加载 println!("Scanning mocks directory..."); let index = MockLoader::load_all_from_dir(mocks_dir); let shared_state = Arc::new(AppState { router: RwLock::new(MockRouter::new(index)), }); // 2. 设置热加载监听器 let state_for_watcher = shared_state.clone(); let watch_path = mocks_dir.to_path_buf(); let (tx, rx) = std::sync::mpsc::channel(); // 200ms 防抖,防止编辑器保存文件时产生多次干扰 let mut debouncer = new_debouncer(Duration::from_millis(200), tx).unwrap(); debouncer.watcher().watch(&watch_path, RecursiveMode::Recursive).unwrap(); // 启动异步任务监听文件变动 tokio::spawn(async move { while let Ok(res) = rx.recv() { match res { Ok(_) => { println!("🔄 Detecting changes in mocks/, reloading..."); let new_index = MockLoader::load_all_from_dir(&watch_path); // 获取写锁 (Write Lock) 更新索引 let mut writer = state_for_watcher.router.write().expect("Failed to acquire write lock"); *writer = MockRouter::new(new_index); println!("✅ Mocks reloaded successfully."); } Err(e) => eprintln!("Watcher error: {:?}", e), } } }); // 3. 配置 Axum 路由 let app = Router::new() .fallback(any(mock_handler)) .with_state(shared_state); let addr = SocketAddr::from(([127, 0, 0, 1], 8080)); println!("🚀 Server running at http://{}", addr); let listener = tokio::net::TcpListener::bind(addr).await.unwrap(); axum::serve(listener, app).await.unwrap(); }