mirror of
https://github.com/clash-verge-rev/clash-verge-rev
synced 2025-05-05 12:23: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 super::CmdResult;
|
||||||
use crate::{core::handle, model::sysinfo::PlatformSpecification};
|
use crate::{core::handle, model::sysinfo::PlatformSpecification};
|
||||||
use tauri_plugin_clipboard_manager::ClipboardExt;
|
use tauri_plugin_clipboard_manager::ClipboardExt;
|
||||||
|
use crate::{core::{self, CoreManager, service}, wrap_err};
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn export_diagnostic_info() -> CmdResult<()> {
|
pub async fn export_diagnostic_info() -> CmdResult<()> {
|
||||||
@ -15,3 +16,19 @@ pub async fn export_diagnostic_info() -> CmdResult<()> {
|
|||||||
}
|
}
|
||||||
Ok(())
|
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>>,
|
running: Arc<Mutex<bool>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 内核运行模式
|
||||||
|
#[derive(Debug, Clone, serde::Serialize)]
|
||||||
|
pub enum RunningMode {
|
||||||
|
/// 服务模式运行
|
||||||
|
Service,
|
||||||
|
/// Sidecar模式运行
|
||||||
|
Sidecar,
|
||||||
|
/// 未运行
|
||||||
|
NotRunning,
|
||||||
|
}
|
||||||
|
|
||||||
impl CoreManager {
|
impl CoreManager {
|
||||||
pub fn global() -> &'static CoreManager {
|
pub fn global() -> &'static CoreManager {
|
||||||
static CORE_MANAGER: OnceCell<CoreManager> = OnceCell::new();
|
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()
|
core_process.take()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 检查是否有运行中的核心进程
|
||||||
|
pub fn has_core_process(&self) -> bool {
|
||||||
|
self.core_process.read().is_some()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_exiting(&self) -> bool {
|
pub fn is_exiting(&self) -> bool {
|
||||||
*self.is_exiting.read()
|
*self.is_exiting.read()
|
||||||
}
|
}
|
||||||
|
@ -279,3 +279,15 @@ pub(super) async fn stop_core_by_service() -> Result<()> {
|
|||||||
|
|
||||||
Ok(())
|
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::get_network_interfaces,
|
||||||
cmd::restart_core,
|
cmd::restart_core,
|
||||||
cmd::restart_app,
|
cmd::restart_app,
|
||||||
|
// 添加新的命令
|
||||||
|
cmd::get_running_mode,
|
||||||
|
cmd::install_service,
|
||||||
// clash
|
// clash
|
||||||
cmd::get_clash_info,
|
cmd::get_clash_info,
|
||||||
cmd::patch_clash_config,
|
cmd::patch_clash_config,
|
||||||
|
@ -5,6 +5,8 @@ import {
|
|||||||
SettingsRounded,
|
SettingsRounded,
|
||||||
PlayArrowRounded,
|
PlayArrowRounded,
|
||||||
PauseRounded,
|
PauseRounded,
|
||||||
|
WarningRounded,
|
||||||
|
BuildRounded,
|
||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
import { useVerge } from "@/hooks/use-verge";
|
import { useVerge } from "@/hooks/use-verge";
|
||||||
import { DialogRef, Notice, Switch } from "@/components/base";
|
import { DialogRef, Notice, Switch } from "@/components/base";
|
||||||
@ -13,7 +15,14 @@ import { GuardState } from "./mods/guard-state";
|
|||||||
import { SysproxyViewer } from "./mods/sysproxy-viewer";
|
import { SysproxyViewer } from "./mods/sysproxy-viewer";
|
||||||
import { TunViewer } from "./mods/tun-viewer";
|
import { TunViewer } from "./mods/tun-viewer";
|
||||||
import { TooltipIcon } from "@/components/base/base-tooltip-icon";
|
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 {
|
interface Props {
|
||||||
onError?: (err: Error) => void;
|
onError?: (err: Error) => void;
|
||||||
@ -26,6 +35,13 @@ const SettingSystem = ({ onError }: Props) => {
|
|||||||
|
|
||||||
const { data: sysproxy } = useSWR("getSystemProxy", getSystemProxy);
|
const { data: sysproxy } = useSWR("getSystemProxy", getSystemProxy);
|
||||||
const { data: autoproxy } = useSWR("getAutotemProxy", getAutotemProxy);
|
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 sysproxyRef = useRef<DialogRef>(null);
|
||||||
const tunRef = useRef<DialogRef>(null);
|
const tunRef = useRef<DialogRef>(null);
|
||||||
@ -54,6 +70,19 @@ const SettingSystem = ({ onError }: Props) => {
|
|||||||
await mutate("getAutotemProxy");
|
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 (
|
return (
|
||||||
<SettingList title={t("System Setting")}>
|
<SettingList title={t("System Setting")}>
|
||||||
<SysproxyViewer ref={sysproxyRef} />
|
<SysproxyViewer ref={sysproxyRef} />
|
||||||
@ -62,11 +91,31 @@ const SettingSystem = ({ onError }: Props) => {
|
|||||||
<SettingItem
|
<SettingItem
|
||||||
label={t("Tun Mode")}
|
label={t("Tun Mode")}
|
||||||
extra={
|
extra={
|
||||||
<TooltipIcon
|
<>
|
||||||
title={t("Tun Mode Info")}
|
<TooltipIcon
|
||||||
icon={SettingsRounded}
|
title={t("Tun Mode Info")}
|
||||||
onClick={() => tunRef.current?.open()}
|
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
|
<GuardState
|
||||||
@ -75,13 +124,20 @@ const SettingSystem = ({ onError }: Props) => {
|
|||||||
onCatch={onError}
|
onCatch={onError}
|
||||||
onFormat={onSwitchFormat}
|
onFormat={onSwitchFormat}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
|
// 当在sidecar模式下禁用切换
|
||||||
|
if (isSidecarMode) return;
|
||||||
onChangeData({ enable_tun_mode: e });
|
onChangeData({ enable_tun_mode: e });
|
||||||
}}
|
}}
|
||||||
onGuard={(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 });
|
return patchVerge({ enable_tun_mode: e });
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Switch edge="end" />
|
<Switch edge="end" disabled={isSidecarMode} />
|
||||||
</GuardState>
|
</GuardState>
|
||||||
</SettingItem>
|
</SettingItem>
|
||||||
<SettingItem
|
<SettingItem
|
||||||
|
@ -195,6 +195,8 @@
|
|||||||
"Settings": "Settings",
|
"Settings": "Settings",
|
||||||
"System Setting": "System Setting",
|
"System Setting": "System Setting",
|
||||||
"Tun Mode": "Tun (Virtual NIC) Mode",
|
"Tun Mode": "Tun (Virtual NIC) Mode",
|
||||||
|
"TUN requires Service Mode": "TUN mode requires service",
|
||||||
|
"Install Service": "Install Service",
|
||||||
"Reset to Default": "Reset to Default",
|
"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.",
|
"Tun Mode Info": "Tun (Virtual NIC) mode: Captures all system traffic, when enabled, there is no need to enable system proxy.",
|
||||||
"Stack": "Tun Stack",
|
"Stack": "Tun Stack",
|
||||||
@ -365,6 +367,7 @@
|
|||||||
"Profile Reactivated": "Profile Reactivated",
|
"Profile Reactivated": "Profile Reactivated",
|
||||||
"Only YAML Files Supported": "Only YAML Files Supported",
|
"Only YAML Files Supported": "Only YAML Files Supported",
|
||||||
"Settings Applied": "Settings Applied",
|
"Settings Applied": "Settings Applied",
|
||||||
|
"Installing Service...": "Installing Service...",
|
||||||
"Service Installed Successfully": "Service Installed Successfully",
|
"Service Installed Successfully": "Service Installed Successfully",
|
||||||
"Service Uninstalled Successfully": "Service Uninstalled 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",
|
"Proxy Daemon Duration Cannot be Less than 1 Second": "Proxy Daemon Duration Cannot be Less than 1 Second",
|
||||||
|
@ -195,6 +195,8 @@
|
|||||||
"Settings": "设置",
|
"Settings": "设置",
|
||||||
"System Setting": "系统设置",
|
"System Setting": "系统设置",
|
||||||
"Tun Mode": "TUN(虚拟网卡)模式",
|
"Tun Mode": "TUN(虚拟网卡)模式",
|
||||||
|
"TUN requires Service Mode": "TUN 模式需要服务",
|
||||||
|
"Install Service": "安装服务",
|
||||||
"Reset to Default": "重置为默认值",
|
"Reset to Default": "重置为默认值",
|
||||||
"Tun Mode Info": "TUN(虚拟网卡)模式接管系统所有流量,启用时无须打开系统代理",
|
"Tun Mode Info": "TUN(虚拟网卡)模式接管系统所有流量,启用时无须打开系统代理",
|
||||||
"Stack": "TUN 模式堆栈",
|
"Stack": "TUN 模式堆栈",
|
||||||
@ -362,6 +364,7 @@
|
|||||||
"Profile Reactivated": "订阅已激活",
|
"Profile Reactivated": "订阅已激活",
|
||||||
"Only YAML Files Supported": "仅支持 YAML 文件",
|
"Only YAML Files Supported": "仅支持 YAML 文件",
|
||||||
"Settings Applied": "设置已应用",
|
"Settings Applied": "设置已应用",
|
||||||
|
"Installing Service...": "安装服务中...",
|
||||||
"Service Installed Successfully": "已成功安装服务",
|
"Service Installed Successfully": "已成功安装服务",
|
||||||
"Service Uninstalled Successfully": "已成功卸载服务",
|
"Service Uninstalled Successfully": "已成功卸载服务",
|
||||||
"Proxy Daemon Duration Cannot be Less than 1 Second": "代理守护间隔时间不得低于 1 秒",
|
"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) {
|
export async function validateScriptFile(filePath: string) {
|
||||||
return invoke<boolean>("validate_script_file", { filePath });
|
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