Files
clash-verge-rev-lite/src-tauri/src/feat/window.rs
oomeow 1357913f8b fix: restart app failed (#4974)
* fix: failed to restart app

* chore: cleanup

* chore: cargo fmt

* chore: use AsyncHandler

* chore: clippy

* chore: update
2025-10-09 20:08:25 +08:00

327 lines
9.8 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use crate::utils;
use crate::utils::window_manager::WindowManager;
use crate::{
config::Config,
core::{CoreManager, handle, sysopt},
logging,
module::lightweight,
utils::logging::Type,
};
/// Open or close the dashboard window
pub async fn open_or_close_dashboard() {
open_or_close_dashboard_internal().await
}
/// Internal implementation for opening/closing dashboard
async fn open_or_close_dashboard_internal() {
let _ = lightweight::exit_lightweight_mode().await;
let result = WindowManager::toggle_main_window().await;
log::info!(target: "app", "Window toggle result: {result:?}");
}
pub async fn quit() {
logging!(debug, Type::System, true, "启动退出流程");
utils::server::shutdown_embedded_server();
// 获取应用句柄并设置退出标志
let app_handle = handle::Handle::app_handle();
handle::Handle::global().set_is_exiting();
// 优先关闭窗口,提供立即反馈
if let Some(window) = handle::Handle::get_window() {
let _ = window.hide();
log::info!(target: "app", "窗口已隐藏");
}
logging!(info, Type::System, true, "开始异步清理资源");
let cleanup_result = clean_async().await;
logging!(
info,
Type::System,
true,
"资源清理完成,退出代码: {}",
if cleanup_result { 0 } else { 1 }
);
app_handle.exit(if cleanup_result { 0 } else { 1 });
}
async fn clean_async() -> bool {
use tokio::time::{Duration, timeout};
logging!(info, Type::System, true, "开始执行异步清理操作...");
// 1. 处理TUN模式
let tun_success = if Config::verge()
.await
.data_mut()
.enable_tun_mode
.unwrap_or(false)
{
let disable_tun = serde_json::json!({"tun": {"enable": false}});
#[cfg(target_os = "windows")]
let tun_timeout = Duration::from_secs(2);
#[cfg(not(target_os = "windows"))]
let tun_timeout = Duration::from_secs(2);
match timeout(
tun_timeout,
handle::Handle::mihomo()
.await
.patch_base_config(&disable_tun),
)
.await
{
Ok(Ok(_)) => {
log::info!(target: "app", "TUN模式已禁用");
tokio::time::sleep(Duration::from_millis(300)).await;
true
}
Ok(Err(e)) => {
log::warn!(target: "app", "禁用TUN模式失败: {e}");
// 超时不阻塞退出
true
}
Err(_) => {
log::warn!(target: "app", "禁用TUN模式超时可能系统正在关机继续退出流程");
true
}
}
} else {
true
};
// 2. 系统代理重置
let proxy_task = async {
#[cfg(target_os = "windows")]
{
use sysproxy::{Autoproxy, Sysproxy};
use winapi::um::winuser::{GetSystemMetrics, SM_SHUTTINGDOWN};
// 检查系统代理是否开启
let sys_proxy_enabled = Config::verge()
.await
.latest_ref()
.enable_system_proxy
.unwrap_or(false);
if !sys_proxy_enabled {
log::info!(target: "app", "系统代理未启用,跳过重置");
return true;
}
// 检查是否正在关机
let is_shutting_down = unsafe { GetSystemMetrics(SM_SHUTTINGDOWN) != 0 };
if is_shutting_down {
// sysproxy-rs 操作注册表(避免.exe的dll错误)
log::info!(target: "app", "检测到正在关机syspro-rs操作注册表关闭系统代理");
match Sysproxy::get_system_proxy() {
Ok(mut sysproxy) => {
sysproxy.enable = false;
if let Err(e) = sysproxy.set_system_proxy() {
log::warn!(target: "app", "关机时关闭系统代理失败: {e}");
} else {
log::info!(target: "app", "系统代理已关闭(通过注册表)");
}
}
Err(e) => {
log::warn!(target: "app", "关机时获取代理设置失败: {e}");
}
}
// 关闭自动代理配置
if let Ok(mut autoproxy) = Autoproxy::get_auto_proxy() {
autoproxy.enable = false;
let _ = autoproxy.set_auto_proxy();
}
return true;
}
// 正常退出:使用 sysproxy.exe 重置代理
log::info!(target: "app", "sysproxy.exe重置系统代理");
match timeout(
Duration::from_secs(2),
sysopt::Sysopt::global().reset_sysproxy(),
)
.await
{
Ok(Ok(_)) => {
log::info!(target: "app", "系统代理已重置");
true
}
Ok(Err(e)) => {
log::warn!(target: "app", "重置系统代理失败: {e}");
true
}
Err(_) => {
log::warn!(target: "app", "重置系统代理超时,继续退出流程");
true
}
}
}
// 非 Windows 平台:正常重置代理
#[cfg(not(target_os = "windows"))]
{
let sys_proxy_enabled = Config::verge()
.await
.latest_ref()
.enable_system_proxy
.unwrap_or(false);
if !sys_proxy_enabled {
log::info!(target: "app", "系统代理未启用,跳过重置");
return true;
}
log::info!(target: "app", "开始重置系统代理...");
match timeout(
Duration::from_millis(1500),
sysopt::Sysopt::global().reset_sysproxy(),
)
.await
{
Ok(Ok(_)) => {
log::info!(target: "app", "系统代理已重置");
true
}
Ok(Err(e)) => {
log::warn!(target: "app", "重置系统代理失败: {e}");
true
}
Err(_) => {
log::warn!(target: "app", "重置系统代理超时,继续退出");
true
}
}
}
};
// 3. 核心服务停止
let core_task = async {
#[cfg(target_os = "windows")]
let stop_timeout = Duration::from_secs(2);
#[cfg(not(target_os = "windows"))]
let stop_timeout = Duration::from_secs(3);
match timeout(stop_timeout, CoreManager::global().stop_core()).await {
Ok(_) => {
log::info!(target: "app", "core已停止");
true
}
Err(_) => {
log::warn!(target: "app", "停止core超时可能系统正在关机继续退出");
true
}
}
};
// 4. DNS恢复仅macOS
#[cfg(target_os = "macos")]
let dns_task = async {
match timeout(
Duration::from_millis(1000),
crate::utils::resolve::dns::restore_public_dns(),
)
.await
{
Ok(_) => {
log::info!(target: "app", "DNS设置已恢复");
true
}
Err(_) => {
log::warn!(target: "app", "恢复DNS设置超时");
false
}
}
};
// 并行执行剩余清理任务
let (proxy_success, core_success) = tokio::join!(proxy_task, core_task);
#[cfg(target_os = "macos")]
let dns_success = dns_task.await;
#[cfg(not(target_os = "macos"))]
let dns_success = true;
let all_success = tun_success && proxy_success && core_success && dns_success;
logging!(
info,
Type::System,
true,
"异步关闭操作完成 - TUN: {}, 代理: {}, 核心: {}, DNS: {}, 总体: {}",
tun_success,
proxy_success,
core_success,
dns_success,
all_success
);
all_success
}
pub fn clean() -> bool {
use crate::process::AsyncHandler;
let (tx, rx) = std::sync::mpsc::channel();
AsyncHandler::spawn(move || async move {
logging!(info, Type::System, true, "开始执行关闭操作...");
// 使用已有的异步清理函数
let cleanup_result = clean_async().await;
let _ = tx.send(cleanup_result);
});
#[cfg(target_os = "windows")]
let total_timeout = std::time::Duration::from_secs(5);
#[cfg(not(target_os = "windows"))]
let total_timeout = std::time::Duration::from_secs(8);
match rx.recv_timeout(total_timeout) {
Ok(result) => {
logging!(info, Type::System, true, "关闭操作完成,结果: {}", result);
result
}
Err(_) => {
logging!(
warn,
Type::System,
true,
"清理操作超时(可能正在关机),返回成功避免阻塞"
);
true
}
}
}
#[cfg(target_os = "macos")]
pub async fn hide() {
use crate::module::lightweight::add_light_weight_timer;
let enable_auto_light_weight_mode = Config::verge()
.await
.data_mut()
.enable_auto_light_weight_mode
.unwrap_or(false);
if enable_auto_light_weight_mode {
add_light_weight_timer().await;
}
if let Some(window) = handle::Handle::get_window()
&& window.is_visible().unwrap_or(false)
{
let _ = window.hide();
}
handle::Handle::global().set_activation_policy_accessory();
}