mirror of
https://github.com/clash-verge-rev/clash-verge-rev
synced 2025-05-05 04:53:44 +08:00
feat: show service mode installation prompts in user mode
This commit is contained in:
parent
fadae3f7dc
commit
dd510b2ee9
@ -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<String, String> {
|
||||
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)
|
||||
}
|
||||
|
@ -17,6 +17,17 @@ pub struct CoreManager {
|
||||
running: Arc<Mutex<bool>>,
|
||||
}
|
||||
|
||||
/// 内核运行模式
|
||||
#[derive(Debug, Clone, serde::Serialize)]
|
||||
pub enum RunningMode {
|
||||
/// 服务模式运行
|
||||
Service,
|
||||
/// Sidecar模式运行
|
||||
Sidecar,
|
||||
/// 未运行
|
||||
NotRunning,
|
||||
}
|
||||
|
||||
impl CoreManager {
|
||||
pub fn global() -> &'static CoreManager {
|
||||
static CORE_MANAGER: OnceCell<CoreManager> = 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
|
@ -279,3 +279,15 @@ pub(super) async fn stop_core_by_service() -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 检查服务是否正在运行
|
||||
pub async fn is_service_running() -> Result<bool> {
|
||||
let resp = check_service().await?;
|
||||
|
||||
// 检查服务状态码和消息
|
||||
if resp.code == 200 && resp.msg == "success" && resp.data.is_some() {
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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<DialogRef>(null);
|
||||
const tunRef = useRef<DialogRef>(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 (
|
||||
<SettingList title={t("System Setting")}>
|
||||
<SysproxyViewer ref={sysproxyRef} />
|
||||
@ -62,11 +91,31 @@ const SettingSystem = ({ onError }: Props) => {
|
||||
<SettingItem
|
||||
label={t("Tun Mode")}
|
||||
extra={
|
||||
<TooltipIcon
|
||||
title={t("Tun Mode Info")}
|
||||
icon={SettingsRounded}
|
||||
onClick={() => tunRef.current?.open()}
|
||||
/>
|
||||
<>
|
||||
<TooltipIcon
|
||||
title={t("Tun Mode Info")}
|
||||
icon={SettingsRounded}
|
||||
onClick={() => tunRef.current?.open()}
|
||||
/>
|
||||
{isSidecarMode && (
|
||||
<Tooltip title={t("TUN requires Service Mode")}>
|
||||
<WarningRounded sx={{ color: "warning.main", mr: 1 }} />
|
||||
</Tooltip>
|
||||
)}
|
||||
{isSidecarMode && (
|
||||
<Tooltip title={t("Install Service")}>
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
size="small"
|
||||
onClick={onInstallService}
|
||||
sx={{ mr: 1, minWidth: "32px", p: "4px" }}
|
||||
>
|
||||
<BuildRounded fontSize="small" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
>
|
||||
<GuardState
|
||||
@ -75,13 +124,20 @@ const SettingSystem = ({ onError }: Props) => {
|
||||
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 });
|
||||
}}
|
||||
>
|
||||
<Switch edge="end" />
|
||||
<Switch edge="end" disabled={isSidecarMode} />
|
||||
</GuardState>
|
||||
</SettingItem>
|
||||
<SettingItem
|
||||
|
@ -195,6 +195,8 @@
|
||||
"Settings": "Settings",
|
||||
"System Setting": "System Setting",
|
||||
"Tun Mode": "Tun (Virtual NIC) Mode",
|
||||
"TUN requires Service Mode": "TUN mode requires service",
|
||||
"Install Service": "Install Service",
|
||||
"Reset to Default": "Reset to Default",
|
||||
"Tun Mode Info": "Tun (Virtual NIC) mode: Captures all system traffic, when enabled, there is no need to enable system proxy.",
|
||||
"Stack": "Tun Stack",
|
||||
@ -365,6 +367,7 @@
|
||||
"Profile Reactivated": "Profile Reactivated",
|
||||
"Only YAML Files Supported": "Only YAML Files Supported",
|
||||
"Settings Applied": "Settings Applied",
|
||||
"Installing Service...": "Installing Service...",
|
||||
"Service Installed Successfully": "Service Installed Successfully",
|
||||
"Service Uninstalled Successfully": "Service Uninstalled Successfully",
|
||||
"Proxy Daemon Duration Cannot be Less than 1 Second": "Proxy Daemon Duration Cannot be Less than 1 Second",
|
||||
|
@ -195,6 +195,8 @@
|
||||
"Settings": "设置",
|
||||
"System Setting": "系统设置",
|
||||
"Tun Mode": "TUN(虚拟网卡)模式",
|
||||
"TUN requires Service Mode": "TUN 模式需要服务",
|
||||
"Install Service": "安装服务",
|
||||
"Reset to Default": "重置为默认值",
|
||||
"Tun Mode Info": "TUN(虚拟网卡)模式接管系统所有流量,启用时无须打开系统代理",
|
||||
"Stack": "TUN 模式堆栈",
|
||||
@ -362,6 +364,7 @@
|
||||
"Profile Reactivated": "订阅已激活",
|
||||
"Only YAML Files Supported": "仅支持 YAML 文件",
|
||||
"Settings Applied": "设置已应用",
|
||||
"Installing Service...": "安装服务中...",
|
||||
"Service Installed Successfully": "已成功安装服务",
|
||||
"Service Uninstalled Successfully": "已成功卸载服务",
|
||||
"Proxy Daemon Duration Cannot be Less than 1 Second": "代理守护间隔时间不得低于 1 秒",
|
||||
|
@ -253,3 +253,13 @@ export async function scriptValidateNotice(status: string, msg: string) {
|
||||
export async function validateScriptFile(filePath: string) {
|
||||
return invoke<boolean>("validate_script_file", { filePath });
|
||||
}
|
||||
|
||||
// 获取当前运行模式
|
||||
export const getRunningMode = async () => {
|
||||
return invoke<string>("get_running_mode");
|
||||
};
|
||||
|
||||
// 安装/重装系统服务
|
||||
export const installService = async () => {
|
||||
return invoke<void>("install_service");
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user