use tauri::Manager; mod download_engine; mod logger; mod mihomo_manager; mod process_manager; use download_engine::{ DownloadEngine, ExtensionServer, downloader_add_task, downloader_get_extension_info, downloader_get_settings, downloader_get_tasks, downloader_open_dir, downloader_open_url, downloader_pause_task, downloader_remove_task, downloader_resume_task, downloader_save_settings, downloader_status, }; use logger::{ clear_logs, get_log_info, get_logs, log_message, LogManager, }; use mihomo_manager::{ proxy_activate_profile, proxy_check_kernel_update, proxy_clear_system_proxy, proxy_close_connection, proxy_delete_profile, proxy_get_connections, proxy_get_proxies, proxy_get_settings, proxy_get_system_proxy, proxy_import_profile, proxy_install_kernel, proxy_kernel_info, proxy_patch_configs, proxy_restart, proxy_save_settings, proxy_select_proxy, proxy_set_system_proxy, proxy_start, proxy_status, proxy_stop, proxy_test_delay, proxy_update_kernel, proxy_update_profile, proxy_version, MihomoManager, }; use process_manager::{ get_all_process_status, get_process_status, start_monitoring_thread, start_process, stop_all_processes, stop_process, ProcessManager, }; #[tauri::command] fn greet(name: &str) -> String { format!("Hello, {}! You've been greeted from Rust!", name) } #[tauri::command] fn quit_app( state: tauri::State<'_, ProcessManager>, mihomo: tauri::State<'_, MihomoManager>, engine: tauri::State<'_, DownloadEngine>, app: tauri::AppHandle, ) { // 退出前清理系统代理,避免遗留导致网络问题 mihomo.cleanup_on_exit(); // 退出前保存下载引擎状态 engine.cleanup_on_exit(); // 停止所有子进程(同步 kill + 带超时的 wait,确保进程真正终止) state.stop_all(); // 通过 app.exit 触发 RunEvent::ExitRequested,统一退出路径 app.exit(0); } #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() .plugin(tauri_plugin_autostart::Builder::new().build()) .plugin(tauri_plugin_opener::init()) .plugin(tauri_plugin_dialog::init()) .plugin( tauri_plugin_snap_layout::init() .button_id("titlebar-maximize") .build() ) .manage(ProcessManager::new()) .invoke_handler(tauri::generate_handler![ greet, quit_app, start_process, stop_process, get_process_status, get_all_process_status, stop_all_processes, log_message, get_logs, clear_logs, get_log_info, proxy_get_settings, proxy_save_settings, proxy_kernel_info, proxy_check_kernel_update, proxy_update_kernel, proxy_install_kernel, proxy_status, proxy_start, proxy_stop, proxy_restart, proxy_version, proxy_get_proxies, proxy_select_proxy, proxy_test_delay, proxy_get_connections, proxy_close_connection, proxy_patch_configs, proxy_import_profile, proxy_update_profile, proxy_delete_profile, proxy_activate_profile, proxy_set_system_proxy, proxy_clear_system_proxy, proxy_get_system_proxy, downloader_get_tasks, downloader_add_task, downloader_pause_task, downloader_resume_task, downloader_remove_task, downloader_get_settings, downloader_save_settings, downloader_status, downloader_get_extension_info, downloader_open_dir, downloader_open_url ]) .setup(|app| { // 初始化日志系统,日志目录: {app_data_dir}/logs/ let log_dir = app .path() .app_data_dir() .unwrap_or_else(|_| std::path::PathBuf::from(".")) .join("logs"); app.manage(LogManager::new(log_dir)); // 初始化 MihomoManager,数据目录: {app_data_dir}/proxy/ let app_data_dir = app .path() .app_data_dir() .unwrap_or_else(|_| std::path::PathBuf::from(".")); let mihomo = MihomoManager::new(app_data_dir.clone()); app.manage(mihomo); // 初始化 DownloadEngine,数据目录: {app_data_dir}/downloader/ let engine = DownloadEngine::new( app_data_dir.join("downloader"), app.handle().clone(), ); let settings = engine.get_settings(); app.manage(engine.clone()); // 启动扩展 HTTP API 服务器 let server_engine = engine.clone(); let server_port = settings.extension_port; let server_secret = settings.extension_secret.clone(); tauri::async_runtime::spawn(async move { ExtensionServer::start(server_engine, server_port, server_secret).await; }); let open = tauri::menu::MenuItem::with_id(app, "open", "设置", true, None::<&str>)?; let quit = tauri::menu::MenuItem::with_id(app, "quit", "退出", true, None::<&str>)?; let menu = tauri::menu::Menu::with_items(app, &[&open, &quit])?; let _tray = tauri::tray::TrayIconBuilder::new() .icon(app.default_window_icon().unwrap().clone()) .menu(&menu) .show_menu_on_left_click(false) .on_menu_event(|app, event| match event.id().as_ref() { "open" => { if let Some(window) = app.get_webview_window("main") { window.show().ok(); window.set_focus().ok(); } } "quit" => { if let Some(mihomo) = app.try_state::() { mihomo.cleanup_on_exit(); } if let Some(engine) = app.try_state::() { engine.cleanup_on_exit(); } if let Some(pm) = app.try_state::() { pm.stop_all(); } app.exit(0); } _ => {} }) .on_tray_icon_event(|tray, event| { if let tauri::tray::TrayIconEvent::Click { button: tauri::tray::MouseButton::Left, .. } = event { let app = tray.app_handle(); if let Some(window) = app.get_webview_window("main") { window.show().ok(); window.set_focus().ok(); } } }) .build(app)?; // 启动进程监控线程 start_monitoring_thread(app.handle().clone()); // 应用启动时自动启动 mihomo(如果用户在设置中开启了自动启动) if let Some(mihomo) = app.try_state::() { if let Some(pm) = app.try_state::() { mihomo.auto_start_on_launch(app.handle(), &pm); } } Ok(()) }) .on_window_event(|window, event| { if let tauri::WindowEvent::CloseRequested { api, .. } = event { window.hide().ok(); api.prevent_close(); } }) .build(tauri::generate_context!()) .expect("error while building tauri application") .run(|app, event| { if let tauri::RunEvent::ExitRequested { .. } = event { if let Some(mihomo) = app.try_state::() { mihomo.cleanup_on_exit(); } if let Some(engine) = app.try_state::() { engine.cleanup_on_exit(); } if let Some(pm) = app.try_state::() { pm.stop_all(); } } }); }