diff --git a/src-tauri/src/cmd/system.rs b/src-tauri/src/cmd/system.rs index a0651a6e..2c875e77 100644 --- a/src-tauri/src/cmd/system.rs +++ b/src-tauri/src/cmd/system.rs @@ -1,6 +1,7 @@ use super::CmdResult; use crate::{core::handle, model::sysinfo::PlatformSpecification}; use tauri_plugin_clipboard_manager::ClipboardExt; +use crate::{core::{self, CoreManager, service}, wrap_err}; #[tauri::command] pub async fn export_diagnostic_info() -> CmdResult<()> { @@ -15,3 +16,19 @@ pub async fn export_diagnostic_info() -> CmdResult<()> { } Ok(()) } + +/// 获取当前内核运行模式 +#[tauri::command] +pub async fn get_running_mode() -> Result { + match CoreManager::global().get_running_mode().await { + core::RunningMode::Service => Ok("service".to_string()), + core::RunningMode::Sidecar => Ok("sidecar".to_string()), + core::RunningMode::NotRunning => Ok("not_running".to_string()), + } +} + +/// 安装/重装系统服务 +#[tauri::command] +pub async fn install_service() -> CmdResult { + wrap_err!(service::reinstall_service().await) +} diff --git a/src-tauri/src/core/core.rs b/src-tauri/src/core/core.rs index 5cd9953d..77cd9704 100644 --- a/src-tauri/src/core/core.rs +++ b/src-tauri/src/core/core.rs @@ -17,6 +17,17 @@ pub struct CoreManager { running: Arc>, } +/// 内核运行模式 +#[derive(Debug, Clone, serde::Serialize)] +pub enum RunningMode { + /// 服务模式运行 + Service, + /// Sidecar模式运行 + Sidecar, + /// 未运行 + NotRunning, +} + impl CoreManager { pub fn global() -> &'static CoreManager { static CORE_MANAGER: OnceCell = OnceCell::new(); @@ -571,4 +582,38 @@ impl CoreManager { } } } + + /// 获取当前内核运行模式 + pub async fn get_running_mode(&self) -> RunningMode { + let running = self.running.lock().await; + if !*running { + return RunningMode::NotRunning; + } + + // 检查服务状态 + match service::check_service().await { + Ok(_) => { + // 检查服务是否实际运行核心 + match service::is_service_running().await { + Ok(true) => RunningMode::Service, + _ => { + // 服务存在但可能没有运行,检查是否有sidecar进程 + if handle::Handle::global().has_core_process() { + RunningMode::Sidecar + } else { + RunningMode::NotRunning + } + } + } + }, + Err(_) => { + // 服务不可用,检查是否有sidecar进程 + if handle::Handle::global().has_core_process() { + RunningMode::Sidecar + } else { + RunningMode::NotRunning + } + } + } + } } \ No newline at end of file diff --git a/src-tauri/src/core/handle.rs b/src-tauri/src/core/handle.rs index 2178b2e6..4fabfaba 100644 --- a/src-tauri/src/core/handle.rs +++ b/src-tauri/src/core/handle.rs @@ -81,6 +81,11 @@ impl Handle { core_process.take() } + /// 检查是否有运行中的核心进程 + pub fn has_core_process(&self) -> bool { + self.core_process.read().is_some() + } + pub fn is_exiting(&self) -> bool { *self.is_exiting.read() } diff --git a/src-tauri/src/core/service.rs b/src-tauri/src/core/service.rs index 32d9b77b..2426c081 100644 --- a/src-tauri/src/core/service.rs +++ b/src-tauri/src/core/service.rs @@ -279,3 +279,15 @@ pub(super) async fn stop_core_by_service() -> Result<()> { Ok(()) } + +/// 检查服务是否正在运行 +pub async fn is_service_running() -> Result { + let resp = check_service().await?; + + // 检查服务状态码和消息 + if resp.code == 200 && resp.msg == "success" && resp.data.is_some() { + Ok(true) + } else { + Ok(false) + } +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 903c10b3..f5b7ea68 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -148,6 +148,9 @@ pub fn run() { cmd::get_network_interfaces, cmd::restart_core, cmd::restart_app, + // 添加新的命令 + cmd::get_running_mode, + cmd::install_service, // clash cmd::get_clash_info, cmd::patch_clash_config, diff --git a/src/components/setting/setting-system.tsx b/src/components/setting/setting-system.tsx index 3e13b144..fdb4325b 100644 --- a/src/components/setting/setting-system.tsx +++ b/src/components/setting/setting-system.tsx @@ -5,6 +5,8 @@ import { SettingsRounded, PlayArrowRounded, PauseRounded, + WarningRounded, + BuildRounded, } from "@mui/icons-material"; import { useVerge } from "@/hooks/use-verge"; import { DialogRef, Notice, Switch } from "@/components/base"; @@ -13,7 +15,14 @@ import { GuardState } from "./mods/guard-state"; import { SysproxyViewer } from "./mods/sysproxy-viewer"; import { TunViewer } from "./mods/tun-viewer"; import { TooltipIcon } from "@/components/base/base-tooltip-icon"; -import { getSystemProxy, getAutotemProxy } from "@/services/cmds"; +import { + getSystemProxy, + getAutotemProxy, + getRunningMode, + installService, +} from "@/services/cmds"; +import { useLockFn } from "ahooks"; +import { Box, Button, Tooltip } from "@mui/material"; interface Props { onError?: (err: Error) => void; @@ -26,6 +35,13 @@ const SettingSystem = ({ onError }: Props) => { const { data: sysproxy } = useSWR("getSystemProxy", getSystemProxy); const { data: autoproxy } = useSWR("getAutotemProxy", getAutotemProxy); + const { data: runningMode, mutate: mutateRunningMode } = useSWR( + "getRunningMode", + getRunningMode, + ); + + // 是否以sidecar模式运行 + const isSidecarMode = runningMode === "sidecar"; const sysproxyRef = useRef(null); const tunRef = useRef(null); @@ -54,6 +70,19 @@ const SettingSystem = ({ onError }: Props) => { await mutate("getAutotemProxy"); }; + // 安装系统服务 + const onInstallService = useLockFn(async () => { + try { + Notice.info(t("Installing Service..."), 1000); + await installService(); + Notice.success(t("Service Installed Successfully"), 2000); + // 重新获取运行模式 + await mutateRunningMode(); + } catch (err: any) { + Notice.error(err.message || err.toString(), 3000); + } + }); + return ( @@ -62,11 +91,31 @@ const SettingSystem = ({ onError }: Props) => { tunRef.current?.open()} - /> + <> + tunRef.current?.open()} + /> + {isSidecarMode && ( + + + + )} + {isSidecarMode && ( + + + + )} + } > { onCatch={onError} onFormat={onSwitchFormat} onChange={(e) => { + // 当在sidecar模式下禁用切换 + if (isSidecarMode) return; onChangeData({ enable_tun_mode: e }); }} onGuard={(e) => { + // 当在sidecar模式下禁用切换 + if (isSidecarMode) { + Notice.error(t("TUN requires Service Mode"), 2000); + return Promise.reject(new Error(t("TUN requires Service Mode"))); + } return patchVerge({ enable_tun_mode: e }); }} > - + ("validate_script_file", { filePath }); } + +// 获取当前运行模式 +export const getRunningMode = async () => { + return invoke("get_running_mode"); +}; + +// 安装/重装系统服务 +export const installService = async () => { + return invoke("install_service"); +};