From b91087e1752ba38995838f69f5477e47c1fcfa2a Mon Sep 17 00:00:00 2001 From: oomeow Date: Sun, 12 Oct 2025 22:55:40 +0800 Subject: [PATCH] feat: support for reopen app via desktop shortcuts (#5037) * fix: singleton check * docs: update UPDATELOG.md --------- Co-authored-by: Slinetrac --- UPDATELOG.md | 1 + src-tauri/src/lib.rs | 32 ++++++++++---------------------- src-tauri/src/utils/server.rs | 32 +++++++++++++++++++++++++------- 3 files changed, 36 insertions(+), 29 deletions(-) diff --git a/UPDATELOG.md b/UPDATELOG.md index 15a63afe..b2682b85 100644 --- a/UPDATELOG.md +++ b/UPDATELOG.md @@ -26,6 +26,7 @@ - 更新了 Wayland 合成器检测逻辑,从而在 Hyprland 会话中保留原生 Wayland 后端 - 改进 Windows 和 Unix 的 服务连接方式以及权限,避免无法连接服务或内核 - 修改内核默认日志级别为 Info +- 支持通过桌面快捷方式重新打开应用 ### 🐞 修复问题 diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index f50ffe5e..c9e93e00 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -22,37 +22,23 @@ use tauri::{AppHandle, Manager}; #[cfg(target_os = "macos")] use tauri_plugin_autostart::MacosLauncher; use tauri_plugin_deep_link::DeepLinkExt; -use tokio::time::{Duration, timeout}; use utils::logging::Type; pub static APP_HANDLE: OnceCell = OnceCell::new(); /// Application initialization helper functions mod app_init { + use anyhow::Result; + use super::*; /// Initialize singleton monitoring for other instances - pub fn init_singleton_check() { - AsyncHandler::spawn_blocking(move || async move { + pub fn init_singleton_check() -> Result<()> { + tauri::async_runtime::block_on(async move { logging!(info, Type::Setup, "开始检查单例实例..."); - match timeout(Duration::from_millis(500), server::check_singleton()).await { - Ok(result) => { - if result.is_err() { - logging!(info, Type::Setup, "检测到已有应用实例运行"); - if let Some(app_handle) = APP_HANDLE.get() { - app_handle.exit(0); - } else { - std::process::exit(0); - } - } else { - logging!(info, Type::Setup, "未检测到其他应用实例"); - } - } - Err(_) => { - logging!(warn, Type::Setup, "单例检查超时,假定没有其他实例运行"); - } - } - }); + server::check_singleton().await?; + Ok(()) + }) } /// Setup plugins for the Tauri builder @@ -235,7 +221,9 @@ mod app_init { pub fn run() { // Setup singleton check - app_init::init_singleton_check(); + if app_init::init_singleton_check().is_err() { + return; + } let _ = utils::dirs::init_portable_flag(); diff --git a/src-tauri/src/utils/server.rs b/src-tauri/src/utils/server.rs index 97be9e9b..93aa9804 100644 --- a/src-tauri/src/utils/server.rs +++ b/src-tauri/src/utils/server.rs @@ -1,14 +1,18 @@ +use std::time::Duration; + use super::resolve; use crate::{ config::{Config, DEFAULT_PAC, IVerge}, - logging_error, + logging, logging_error, + module::lightweight, process::AsyncHandler, - utils::logging::Type, + utils::{logging::Type, window_manager::WindowManager}, }; use anyhow::{Result, bail}; use once_cell::sync::OnceCell; use parking_lot::Mutex; use port_scanner::local_port_available; +use reqwest::ClientBuilder; use tokio::sync::oneshot; use warp::Filter; @@ -24,20 +28,28 @@ static SHUTDOWN_SENDER: OnceCell>>> = OnceCell: pub async fn check_singleton() -> Result<()> { let port = IVerge::get_singleton_port(); if !local_port_available(port) { + let client = ClientBuilder::new() + .timeout(Duration::from_millis(1000)) + .build()?; let argvs: Vec = std::env::args().collect(); if argvs.len() > 1 { #[cfg(not(target_os = "macos"))] { let param = argvs[1].as_str(); if param.starts_with("clash:") { - let _ = reqwest::get(format!( - "http://127.0.0.1:{port}/commands/scheme?param={param}" - )) - .await; + client + .get(format!( + "http://127.0.0.1:{port}/commands/scheme?param={param}" + )) + .send() + .await?; } } } else { - let _ = reqwest::get(format!("http://127.0.0.1:{port}/commands/visible")).await; + client + .get(format!("http://127.0.0.1:{port}/commands/visible")) + .send() + .await?; } log::error!("failed to setup singleton listen server"); bail!("app exists"); @@ -57,6 +69,12 @@ pub fn embed_server() { AsyncHandler::spawn(move || async move { let visible = warp::path!("commands" / "visible").and_then(|| async { + logging!(info, Type::Window, "检测到从单例模式恢复应用窗口"); + if !lightweight::exit_lightweight_mode().await { + WindowManager::show_main_window().await; + } else { + logging!(error, Type::Window, "轻量模式退出失败,无法恢复应用窗口"); + }; Ok::<_, warp::Rejection>(warp::reply::with_status( "ok".to_string(), warp::http::StatusCode::OK,