diff --git a/src-tauri/src/feat/window.rs b/src-tauri/src/feat/window.rs
index cd3d95a2..40f3c4ca 100644
--- a/src-tauri/src/feat/window.rs
+++ b/src-tauri/src/feat/window.rs
@@ -188,78 +188,30 @@ async fn clean_async() -> bool {
}
pub fn clean() -> bool {
- use tokio::time::{timeout, Duration};
+ use crate::process::AsyncHandler;
- // 使用异步处理
- let rt = tokio::runtime::Runtime::new().unwrap();
- let cleanup_result = rt.block_on(async {
+ let (tx, rx) = std::sync::mpsc::channel();
+
+ AsyncHandler::spawn(move || async move {
log::info!(target: "app", "开始执行清理操作...");
- // 1. 处理TUN模式 - 并行执行,减少等待时间
- let tun_task = async {
- if Config::verge().data().enable_tun_mode.unwrap_or(false) {
- let disable_tun = serde_json::json!({
- "tun": {
- "enable": false
- }
- });
- timeout(
- Duration::from_secs(2),
- MihomoManager::global().patch_configs(disable_tun),
- )
- .await
- .is_ok()
- } else {
- true
- }
- };
+ // 使用已有的异步清理函数
+ let cleanup_result = clean_async().await;
- // 2. 系统代理重置
- let proxy_task = async {
- timeout(
- Duration::from_secs(2),
- sysopt::Sysopt::global().reset_sysproxy(),
- )
- .await
- .is_ok()
- };
-
- // 3. 核心服务停止
- let core_task = async {
- timeout(Duration::from_secs(2), CoreManager::global().stop_core())
- .await
- .is_ok()
- };
-
- // 4. DNS恢复(仅macOS)
- #[cfg(target_os = "macos")]
- let dns_task = async {
- timeout(Duration::from_millis(800), resolve::restore_public_dns())
- .await
- .is_ok()
- };
-
- // 并行执行所有清理任务,提高效率
- let (tun_success, proxy_success, core_success) =
- tokio::join!(tun_task, 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;
-
- log::info!(
- target: "app",
- "清理操作完成 - TUN: {}, 代理: {}, 核心: {}, DNS: {}, 总体: {}",
- tun_success, proxy_success, core_success, dns_success, all_success
- );
-
- all_success
+ // 发送结果
+ let _ = tx.send(cleanup_result);
});
- cleanup_result
+ match rx.recv_timeout(std::time::Duration::from_secs(8)) {
+ Ok(result) => {
+ log::info!(target: "app", "清理操作完成,结果: {}", result);
+ result
+ }
+ Err(_) => {
+ log::warn!(target: "app", "清理操作超时,返回成功状态避免阻塞");
+ true
+ }
+ }
}
#[cfg(target_os = "macos")]
diff --git a/src-tauri/src/module/lightweight.rs b/src-tauri/src/module/lightweight.rs
index cf8b33c5..529d006b 100644
--- a/src-tauri/src/module/lightweight.rs
+++ b/src-tauri/src/module/lightweight.rs
@@ -172,19 +172,20 @@ fn cancel_window_close_listener() {
fn setup_light_weight_timer() -> Result<()> {
Timer::global().init()?;
-
- let mut timer_map = Timer::global().timer_map.write();
- let delay_timer = Timer::global().delay_timer.write();
- let mut timer_count = Timer::global().timer_count.lock();
-
- let task_id = *timer_count;
- *timer_count += 1;
-
let once_by_minutes = Config::verge()
.latest()
.auto_light_weight_minutes
.unwrap_or(10);
+ // 获取task_id
+ let task_id = {
+ let mut timer_count = Timer::global().timer_count.lock();
+ let id = *timer_count;
+ *timer_count += 1;
+ id
+ };
+
+ // 创建任务
let task = TaskBuilder::default()
.set_task_id(task_id)
.set_maximum_parallel_runnable_num(1)
@@ -195,17 +196,24 @@ fn setup_light_weight_timer() -> Result<()> {
})
.context("failed to create timer task")?;
- delay_timer
- .add_task(task)
- .context("failed to add timer task")?;
+ // 添加任务到定时器
+ {
+ let delay_timer = Timer::global().delay_timer.write();
+ delay_timer
+ .add_task(task)
+ .context("failed to add timer task")?;
+ }
- let timer_task = crate::core::timer::TimerTask {
- task_id,
- interval_minutes: once_by_minutes,
- last_run: chrono::Local::now().timestamp(),
- };
-
- timer_map.insert(LIGHT_WEIGHT_TASK_UID.to_string(), timer_task);
+ // 更新任务映射
+ {
+ let mut timer_map = Timer::global().timer_map.write();
+ let timer_task = crate::core::timer::TimerTask {
+ task_id,
+ interval_minutes: once_by_minutes,
+ last_run: chrono::Local::now().timestamp(),
+ };
+ timer_map.insert(LIGHT_WEIGHT_TASK_UID.to_string(), timer_task);
+ }
logging!(
info,
diff --git a/src-tauri/src/utils/resolve.rs b/src-tauri/src/utils/resolve.rs
index 3932a85f..5af3b56a 100644
--- a/src-tauri/src/utils/resolve.rs
+++ b/src-tauri/src/utils/resolve.rs
@@ -344,49 +344,72 @@ pub fn create_window(is_show: bool) -> bool {
.fullscreen(false)
.inner_size(DEFAULT_WIDTH as f64, DEFAULT_HEIGHT as f64)
.min_inner_size(520.0, 520.0)
- .visible(true) // 立即显示窗口,避免用户等待
- .initialization_script(r#"
- // 添加非侵入式的加载指示器
- document.addEventListener('DOMContentLoaded', function() {
- // 只有在React应用还没有挂载时才显示加载指示器
- if (!document.getElementById('root') || !document.getElementById('root').hasChildNodes()) {
- // 创建加载指示器,但不覆盖整个body
- const loadingDiv = document.createElement('div');
- loadingDiv.id = 'initial-loading-overlay';
- loadingDiv.innerHTML = `
-
-
-
正在加载 Clash Verge...
-
-
- `;
- document.body.appendChild(loadingDiv);
-
- // 设置定时器,如果React应用在5秒内没有挂载,移除加载指示器
- setTimeout(() => {
- const overlay = document.getElementById('initial-loading-overlay');
- if (overlay) {
- overlay.remove();
- }
- }, 5000);
+ .visible(true) // 立即显示窗口,避免用户等待
+ .initialization_script(
+ r#"
+ console.log('[Tauri] 窗口初始化脚本开始执行');
+
+ function createLoadingOverlay() {
+
+ if (document.getElementById('initial-loading-overlay')) {
+ console.log('[Tauri] 加载指示器已存在');
+ return;
}
- });
- "#)
+
+ console.log('[Tauri] 创建加载指示器');
+ const loadingDiv = document.createElement('div');
+ loadingDiv.id = 'initial-loading-overlay';
+ loadingDiv.innerHTML = `
+
+
+
Loading Clash Verge...
+
+
+ `;
+
+ if (document.body) {
+ document.body.appendChild(loadingDiv);
+ } else {
+ document.addEventListener('DOMContentLoaded', () => {
+ if (document.body && !document.getElementById('initial-loading-overlay')) {
+ document.body.appendChild(loadingDiv);
+ }
+ });
+ }
+ }
+
+ createLoadingOverlay();
+
+ if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', createLoadingOverlay);
+ } else {
+ createLoadingOverlay();
+ }
+
+ console.log('[Tauri] 窗口初始化脚本执行完成');
+ "#,
+ )
.build()
{
Ok(newly_created_window) => {
diff --git a/src/pages/_layout.tsx b/src/pages/_layout.tsx
index 57f0730b..eca75fa1 100644
--- a/src/pages/_layout.tsx
+++ b/src/pages/_layout.tsx
@@ -237,49 +237,120 @@ const Layout = () => {
console.log("[Layout] 开始执行初始化代码");
initRef.current = true;
- const notifyUiStage = async (stage: string) => {
+ let isInitialized = false;
+ let initializationAttempts = 0;
+ const maxAttempts = 3;
+
+ const notifyBackend = async (action: string, stage?: string) => {
try {
- console.log(`[Layout] UI加载阶段: ${stage}`);
- await invoke("update_ui_stage", { stage });
+ if (stage) {
+ console.log(`[Layout] 通知后端 ${action}: ${stage}`);
+ await invoke("update_ui_stage", { stage });
+ } else {
+ console.log(`[Layout] 通知后端 ${action}`);
+ await invoke("notify_ui_ready");
+ }
} catch (err) {
- console.error(`[Layout] 通知UI加载阶段(${stage})失败:`, err);
+ console.error(`[Layout] 通知失败 ${action}:`, err);
}
};
- const notifyUiCoreReady = async () => {
- try {
- console.log("[Layout] 核心组件已加载,通知后端");
- await invoke("update_ui_stage", { stage: "DomReady" });
- } catch (err) {
- console.error("[Layout] 通知核心组件加载完成失败:", err);
+ const removeLoadingOverlay = () => {
+ const initialOverlay = document.getElementById("initial-loading-overlay");
+ if (initialOverlay) {
+ console.log("[Layout] 移除加载指示器");
+ initialOverlay.style.opacity = "0";
+ setTimeout(() => {
+ try {
+ initialOverlay.remove();
+ } catch (e) {
+ console.log("[Layout] 加载指示器已被移除");
+ }
+ }, 300);
}
};
- const notifyUiResourcesLoaded = async () => {
+ const performInitialization = async () => {
+ if (isInitialized) {
+ console.log("[Layout] 已经初始化过,跳过");
+ return;
+ }
+
+ initializationAttempts++;
+ console.log(`[Layout] 开始第 ${initializationAttempts} 次初始化尝试`);
+
try {
- console.log("[Layout] 所有资源已加载,通知后端");
- await invoke("update_ui_stage", { stage: "ResourcesLoaded" });
- } catch (err) {
- console.error("[Layout] 通知资源加载完成失败:", err);
+ removeLoadingOverlay();
+
+ await notifyBackend("加载阶段", "Loading");
+
+ await new Promise((resolve) => {
+ const checkReactMount = () => {
+ const rootElement = document.getElementById("root");
+ if (rootElement && rootElement.children.length > 0) {
+ console.log("[Layout] React组件已挂载");
+ resolve();
+ } else {
+ setTimeout(checkReactMount, 50);
+ }
+ };
+
+ checkReactMount();
+
+ setTimeout(() => {
+ console.log("[Layout] React组件挂载检查超时,继续执行");
+ resolve();
+ }, 2000);
+ });
+
+ await notifyBackend("DOM就绪", "DomReady");
+
+ await new Promise((resolve) => {
+ requestAnimationFrame(() => resolve());
+ });
+
+ await notifyBackend("资源加载完成", "ResourcesLoaded");
+
+ await notifyBackend("UI就绪");
+
+ isInitialized = true;
+ console.log(`[Layout] 第 ${initializationAttempts} 次初始化完成`);
+ } catch (error) {
+ console.error(
+ `[Layout] 第 ${initializationAttempts} 次初始化失败:`,
+ error,
+ );
+
+ if (initializationAttempts < maxAttempts) {
+ console.log(
+ `[Layout] 将在500ms后进行第 ${initializationAttempts + 1} 次重试`,
+ );
+ setTimeout(performInitialization, 500);
+ } else {
+ console.error("[Layout] 所有初始化尝试都失败,执行紧急初始化");
+
+ removeLoadingOverlay();
+ try {
+ await notifyBackend("UI就绪");
+ isInitialized = true;
+ } catch (e) {
+ console.error("[Layout] 紧急初始化也失败:", e);
+ }
+ }
}
};
- const notifyUiReady = async () => {
- try {
- console.log("[Layout] UI完全准备就绪,通知后端");
- await invoke("notify_ui_ready");
- } catch (err) {
- console.error("[Layout] 通知UI准备就绪失败:", err);
- }
- };
+ let hasEventTriggered = false;
- // 监听后端发送的启动完成事件
- const listenStartupCompleted = async () => {
+ const setupEventListener = async () => {
try {
console.log("[Layout] 开始监听启动完成事件");
const unlisten = await listen("verge://startup-completed", () => {
- console.log("[Layout] 收到启动完成事件,开始通知UI就绪");
- notifyUiReady();
+ if (!hasEventTriggered) {
+ console.log("[Layout] 收到启动完成事件,开始初始化");
+ hasEventTriggered = true;
+ performInitialization();
+ }
});
return unlisten;
} catch (err) {
@@ -288,61 +359,45 @@ const Layout = () => {
}
};
- // 简化的UI初始化流程
- const initializeUI = async () => {
+ const checkImmediateInitialization = async () => {
try {
- const initialOverlay = document.getElementById(
- "initial-loading-overlay",
- );
- if (initialOverlay) {
- initialOverlay.style.opacity = "0";
- setTimeout(() => initialOverlay.remove(), 200);
- }
-
- await notifyUiStage("Loading");
-
- await new Promise((resolve) => setTimeout(resolve, 100));
-
- console.log("[Layout] 通知后端:DomReady");
- await notifyUiCoreReady();
-
- await new Promise((resolve) => {
- requestAnimationFrame(() => {
- requestAnimationFrame(resolve);
- });
- });
-
- console.log("[Layout] 通知后端:ResourcesLoaded");
- await notifyUiResourcesLoaded();
-
- await new Promise((resolve) => setTimeout(resolve, 100));
-
- await notifyUiReady();
- } catch (error) {
- try {
- await notifyUiReady();
- } catch (e) {
- console.error("[Layout] 通知UI就绪失败:", e);
+ console.log("[Layout] 检查后端是否已就绪");
+ await invoke("update_ui_stage", { stage: "Loading" });
+
+ if (!hasEventTriggered && !isInitialized) {
+ console.log("[Layout] 后端已就绪,立即开始初始化");
+ hasEventTriggered = true;
+ performInitialization();
}
+ } catch (err) {
+ console.log("[Layout] 后端尚未就绪,等待启动完成事件");
}
};
- setTimeout(initializeUI, 50);
+ const backupInitialization = setTimeout(() => {
+ if (!hasEventTriggered && !isInitialized) {
+ console.warn("[Layout] 备用初始化触发:1.5秒内未开始初始化");
+ hasEventTriggered = true;
+ performInitialization();
+ }
+ }, 1500);
- const emergencyTimeout = setTimeout(() => {
- const emergencyNotify = async () => {
- try {
- await invoke("notify_ui_ready");
- } catch (error) {}
- };
- emergencyNotify();
+ const emergencyInitialization = setTimeout(() => {
+ if (!isInitialized) {
+ console.error("[Layout] 紧急初始化触发:5秒内未完成初始化");
+ removeLoadingOverlay();
+ notifyBackend("UI就绪").catch(() => {});
+ isInitialized = true;
+ }
}, 5000);
- // 启动监听器
- const unlistenPromise = listenStartupCompleted();
+ const unlistenPromise = setupEventListener();
+
+ setTimeout(checkImmediateInitialization, 100);
return () => {
- clearTimeout(emergencyTimeout);
+ clearTimeout(backupInitialization);
+ clearTimeout(emergencyInitialization);
unlistenPromise.then((unlisten) => unlisten());
};
}, []);