mirror of
https://github.com/clash-verge-rev/clash-verge-rev
synced 2025-05-05 05:13:44 +08:00
feat: Try support service mode for MacOS
This commit is contained in:
parent
9fc819a410
commit
e95808e6be
2
.gitignore
vendored
2
.gitignore
vendored
@ -7,4 +7,4 @@ dist-ssr
|
|||||||
update.json
|
update.json
|
||||||
scripts/_env.sh
|
scripts/_env.sh
|
||||||
.vscode
|
.vscode
|
||||||
.tool-version
|
.tool-versions
|
@ -353,8 +353,8 @@ const resolvePlugin = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Linux service chmod
|
// service chmod
|
||||||
const resolveLinuxServicePermission = async () => {
|
const resolveServicePermission = async () => {
|
||||||
const serviceExecutables = [
|
const serviceExecutables = [
|
||||||
"clash-verge-service",
|
"clash-verge-service",
|
||||||
"install-service",
|
"install-service",
|
||||||
@ -376,37 +376,30 @@ const resolveLinuxServicePermission = async () => {
|
|||||||
|
|
||||||
const SERVICE_URL = `https://github.com/clash-verge-rev/clash-verge-service/releases/download/${SIDECAR_HOST}`;
|
const SERVICE_URL = `https://github.com/clash-verge-rev/clash-verge-service/releases/download/${SIDECAR_HOST}`;
|
||||||
|
|
||||||
const resolveService = () =>
|
const resolveService = () => {
|
||||||
|
let ext = platform === "win32" ? ".exe" : "";
|
||||||
resolveResource({
|
resolveResource({
|
||||||
file: "clash-verge-service.exe",
|
file: "clash-verge-service" + ext,
|
||||||
downloadURL: `${SERVICE_URL}/clash-verge-service.exe`,
|
downloadURL: `${SERVICE_URL}/clash-verge-service${ext}`,
|
||||||
});
|
|
||||||
const resolveLinuxService = () => {
|
|
||||||
resolveResource({
|
|
||||||
file: "clash-verge-service",
|
|
||||||
downloadURL: `${SERVICE_URL}/clash-verge-service`,
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const resolveInstall = () =>
|
|
||||||
|
const resolveInstall = () => {
|
||||||
|
let ext = platform === "win32" ? ".exe" : "";
|
||||||
resolveResource({
|
resolveResource({
|
||||||
file: "install-service.exe",
|
file: "install-service" + ext,
|
||||||
downloadURL: `${SERVICE_URL}/install-service.exe`,
|
downloadURL: `${SERVICE_URL}/install-service.exe${ext}`,
|
||||||
});
|
});
|
||||||
const resolveLinuxInstall = () =>
|
};
|
||||||
|
|
||||||
|
const resolveUninstall = () => {
|
||||||
|
let ext = platform === "win32" ? ".exe" : "";
|
||||||
resolveResource({
|
resolveResource({
|
||||||
file: "install-service",
|
file: "uninstall-service" + ext,
|
||||||
downloadURL: `${SERVICE_URL}/install-service`,
|
downloadURL: `${SERVICE_URL}/uninstall-service${ext}`,
|
||||||
});
|
|
||||||
const resolveUninstall = () =>
|
|
||||||
resolveResource({
|
|
||||||
file: "uninstall-service.exe",
|
|
||||||
downloadURL: `${SERVICE_URL}/uninstall-service.exe`,
|
|
||||||
});
|
|
||||||
const resolveLinuxUninstall = () =>
|
|
||||||
resolveResource({
|
|
||||||
file: "uninstall-service",
|
|
||||||
downloadURL: `${SERVICE_URL}/uninstall-service`,
|
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const resolveSetDnsScript = () =>
|
const resolveSetDnsScript = () =>
|
||||||
resolveResource({
|
resolveResource({
|
||||||
file: "set_dns.sh",
|
file: "set_dns.sh",
|
||||||
@ -453,27 +446,9 @@ const tasks = [
|
|||||||
retry: 5,
|
retry: 5,
|
||||||
},
|
},
|
||||||
{ name: "plugin", func: resolvePlugin, retry: 5, winOnly: true },
|
{ name: "plugin", func: resolvePlugin, retry: 5, winOnly: true },
|
||||||
{ name: "service", func: resolveService, retry: 5, winOnly: true },
|
{ name: "service", func: resolveService, retry: 5 },
|
||||||
{
|
{ name: "install", func: resolveInstall, retry: 5 },
|
||||||
name: "linux_service",
|
{ name: "uninstall", func: resolveUninstall, retry: 5 },
|
||||||
func: resolveLinuxService,
|
|
||||||
retry: 5,
|
|
||||||
linuxOnly: true,
|
|
||||||
},
|
|
||||||
{ name: "install", func: resolveInstall, retry: 5, winOnly: true },
|
|
||||||
{
|
|
||||||
name: "linux_install",
|
|
||||||
func: resolveLinuxInstall,
|
|
||||||
retry: 5,
|
|
||||||
linuxOnly: true,
|
|
||||||
},
|
|
||||||
{ name: "uninstall", func: resolveUninstall, retry: 5, winOnly: true },
|
|
||||||
{
|
|
||||||
name: "linux_uninstall",
|
|
||||||
func: resolveLinuxUninstall,
|
|
||||||
retry: 5,
|
|
||||||
linuxOnly: true,
|
|
||||||
},
|
|
||||||
{ name: "set_dns_script", func: resolveSetDnsScript, retry: 5 },
|
{ name: "set_dns_script", func: resolveSetDnsScript, retry: 5 },
|
||||||
{ name: "unset_dns_script", func: resolveUnSetDnsScript, retry: 5 },
|
{ name: "unset_dns_script", func: resolveUnSetDnsScript, retry: 5 },
|
||||||
{ name: "mmdb", func: resolveMmdb, retry: 5 },
|
{ name: "mmdb", func: resolveMmdb, retry: 5 },
|
||||||
@ -486,18 +461,19 @@ const tasks = [
|
|||||||
winOnly: true,
|
winOnly: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "linux_service_chmod",
|
name: "service_chmod",
|
||||||
func: resolveLinuxServicePermission,
|
func: resolveServicePermission,
|
||||||
retry: 1,
|
retry: 1,
|
||||||
linuxOnly: true,
|
unixOnly: true,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
async function runTask() {
|
async function runTask() {
|
||||||
const task = tasks.shift();
|
const task = tasks.shift();
|
||||||
if (!task) return;
|
if (!task) return;
|
||||||
if (task.winOnly && process.platform !== "win32") return runTask();
|
if (task.winOnly && platform !== "win32") return runTask();
|
||||||
if (task.linuxOnly && process.platform !== "linux") return runTask();
|
if (task.linuxOnly && platform !== "linux") return runTask();
|
||||||
|
if (task.unixOnly && platform === "win32") return runTask();
|
||||||
|
|
||||||
for (let i = 0; i < task.retry; i++) {
|
for (let i = 0; i < task.retry; i++) {
|
||||||
try {
|
try {
|
||||||
|
@ -331,7 +331,6 @@ pub fn exit_app(app_handle: tauri::AppHandle) {
|
|||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(windows, target_os = "linux"))]
|
|
||||||
pub mod service {
|
pub mod service {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::core::service;
|
use crate::core::service;
|
||||||
@ -352,24 +351,6 @@ pub mod service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(windows, target_os = "linux")))]
|
|
||||||
pub mod service {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[tauri::command]
|
|
||||||
pub async fn check_service() -> CmdResult {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
#[tauri::command]
|
|
||||||
pub async fn install_service() -> CmdResult {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
#[tauri::command]
|
|
||||||
pub async fn uninstall_service() -> CmdResult {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
pub mod uwp {
|
pub mod uwp {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use super::service;
|
||||||
use super::{clash_api, logger::Logger};
|
use super::{clash_api, logger::Logger};
|
||||||
use crate::log_err;
|
use crate::log_err;
|
||||||
use crate::{config::*, utils::dirs};
|
use crate::{config::*, utils::dirs};
|
||||||
@ -93,10 +94,9 @@ impl CoreManager {
|
|||||||
None => false,
|
None => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux"))]
|
|
||||||
if *self.use_service_mode.lock() {
|
if *self.use_service_mode.lock() {
|
||||||
log::debug!(target: "app", "stop the core by service");
|
log::debug!(target: "app", "stop the core by service");
|
||||||
log_err!(super::service::stop_core_by_service().await);
|
log_err!(service::stop_core_by_service().await);
|
||||||
should_kill = true;
|
should_kill = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,32 +105,27 @@ impl CoreManager {
|
|||||||
sleep(Duration::from_millis(500)).await;
|
sleep(Duration::from_millis(500)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux"))]
|
// 服务模式
|
||||||
{
|
let enable = { Config::verge().latest().enable_service_mode };
|
||||||
use super::service;
|
let enable = enable.unwrap_or(false);
|
||||||
|
|
||||||
// 服务模式
|
*self.use_service_mode.lock() = enable;
|
||||||
let enable = { Config::verge().latest().enable_service_mode };
|
|
||||||
let enable = enable.unwrap_or(false);
|
|
||||||
|
|
||||||
*self.use_service_mode.lock() = enable;
|
if enable {
|
||||||
|
// 服务模式启动失败就直接运行sidecar
|
||||||
|
log::debug!(target: "app", "try to run core in service mode");
|
||||||
|
|
||||||
if enable {
|
match (|| async {
|
||||||
// 服务模式启动失败就直接运行sidecar
|
service::check_service().await?;
|
||||||
log::debug!(target: "app", "try to run core in service mode");
|
service::run_core_by_service(&config_path).await
|
||||||
|
})()
|
||||||
match (|| async {
|
.await
|
||||||
service::check_service().await?;
|
{
|
||||||
service::run_core_by_service(&config_path).await
|
Ok(_) => return Ok(()),
|
||||||
})()
|
Err(err) => {
|
||||||
.await
|
// 修改这个值,免得stop出错
|
||||||
{
|
*self.use_service_mode.lock() = false;
|
||||||
Ok(_) => return Ok(()),
|
log::error!(target: "app", "{err}");
|
||||||
Err(err) => {
|
|
||||||
// 修改这个值,免得stop出错
|
|
||||||
*self.use_service_mode.lock() = false;
|
|
||||||
log::error!(target: "app", "{err}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,7 +200,6 @@ impl CoreManager {
|
|||||||
/// 重启内核
|
/// 重启内核
|
||||||
pub fn recover_core(&'static self) -> Result<()> {
|
pub fn recover_core(&'static self) -> Result<()> {
|
||||||
// 服务模式不管
|
// 服务模式不管
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux"))]
|
|
||||||
if *self.use_service_mode.lock() {
|
if *self.use_service_mode.lock() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -238,11 +232,10 @@ impl CoreManager {
|
|||||||
|
|
||||||
/// 停止核心运行
|
/// 停止核心运行
|
||||||
pub fn stop_core(&self) -> Result<()> {
|
pub fn stop_core(&self) -> Result<()> {
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux"))]
|
|
||||||
if *self.use_service_mode.lock() {
|
if *self.use_service_mode.lock() {
|
||||||
log::debug!(target: "app", "stop the core by service");
|
log::debug!(target: "app", "stop the core by service");
|
||||||
tauri::async_runtime::block_on(async move {
|
tauri::async_runtime::block_on(async move {
|
||||||
log_err!(super::service::stop_core_by_service().await);
|
log_err!(service::stop_core_by_service().await);
|
||||||
});
|
});
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#![cfg(any(target_os = "windows", target_os = "linux"))]
|
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::utils::dirs;
|
use crate::utils::dirs;
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
@ -31,14 +29,13 @@ pub struct JsonResponse {
|
|||||||
|
|
||||||
/// Install the Clash Verge Service
|
/// Install the Clash Verge Service
|
||||||
/// 该函数应该在协程或者线程中执行,避免UAC弹窗阻塞主线程
|
/// 该函数应该在协程或者线程中执行,避免UAC弹窗阻塞主线程
|
||||||
///
|
///
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub async fn install_service() -> Result<()> {
|
pub async fn install_service() -> Result<()> {
|
||||||
use deelevate::{PrivilegeLevel, Token};
|
use deelevate::{PrivilegeLevel, Token};
|
||||||
use runas::Command as RunasCommand;
|
use runas::Command as RunasCommand;
|
||||||
use std::os::windows::process::CommandExt;
|
use std::os::windows::process::CommandExt;
|
||||||
|
|
||||||
|
|
||||||
let binary_path = dirs::service_path()?;
|
let binary_path = dirs::service_path()?;
|
||||||
let install_path = binary_path.with_file_name("install-service.exe");
|
let install_path = binary_path.with_file_name("install-service.exe");
|
||||||
|
|
||||||
@ -80,7 +77,11 @@ pub async fn install_service() -> Result<()> {
|
|||||||
let elevator = crate::utils::unix_helper::linux_elevator();
|
let elevator = crate::utils::unix_helper::linux_elevator();
|
||||||
let status = match get_effective_uid() {
|
let status = match get_effective_uid() {
|
||||||
0 => StdCommand::new(installer_path).status()?,
|
0 => StdCommand::new(installer_path).status()?,
|
||||||
_ => StdCommand::new(elevator).arg("sh").arg("-c").arg(installer_path).status()?,
|
_ => StdCommand::new(elevator)
|
||||||
|
.arg("sh")
|
||||||
|
.arg("-c")
|
||||||
|
.arg(installer_path)
|
||||||
|
.status()?,
|
||||||
};
|
};
|
||||||
|
|
||||||
if !status.success() {
|
if !status.success() {
|
||||||
@ -93,6 +94,30 @@ pub async fn install_service() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
pub async fn install_service() -> Result<()> {
|
||||||
|
let binary_path = dirs::service_path()?;
|
||||||
|
let installer_path = binary_path.with_file_name("install-service");
|
||||||
|
|
||||||
|
if !installer_path.exists() {
|
||||||
|
bail!("installer not found");
|
||||||
|
}
|
||||||
|
let shell = installer_path.to_string_lossy();
|
||||||
|
let command = format!(r#"do shell script "{shell}" with administrator privileges"#);
|
||||||
|
|
||||||
|
let status = StdCommand::new("osascript")
|
||||||
|
.args(vec!["-e", &command])
|
||||||
|
.status()?;
|
||||||
|
|
||||||
|
if !status.success() {
|
||||||
|
bail!(
|
||||||
|
"failed to install service with status {}",
|
||||||
|
status.code().unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
/// Uninstall the Clash Verge Service
|
/// Uninstall the Clash Verge Service
|
||||||
/// 该函数应该在协程或者线程中执行,避免UAC弹窗阻塞主线程
|
/// 该函数应该在协程或者线程中执行,避免UAC弹窗阻塞主线程
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
@ -101,7 +126,6 @@ pub async fn uninstall_service() -> Result<()> {
|
|||||||
use runas::Command as RunasCommand;
|
use runas::Command as RunasCommand;
|
||||||
use std::os::windows::process::CommandExt;
|
use std::os::windows::process::CommandExt;
|
||||||
|
|
||||||
|
|
||||||
let binary_path = dirs::service_path()?;
|
let binary_path = dirs::service_path()?;
|
||||||
let uninstall_path = binary_path.with_file_name("uninstall-service.exe");
|
let uninstall_path = binary_path.with_file_name("uninstall-service.exe");
|
||||||
|
|
||||||
@ -143,7 +167,11 @@ pub async fn uninstall_service() -> Result<()> {
|
|||||||
let elevator = crate::utils::unix_helper::linux_elevator();
|
let elevator = crate::utils::unix_helper::linux_elevator();
|
||||||
let status = match get_effective_uid() {
|
let status = match get_effective_uid() {
|
||||||
0 => StdCommand::new(uninstaller_path).status()?,
|
0 => StdCommand::new(uninstaller_path).status()?,
|
||||||
_ => StdCommand::new(elevator).arg("sh").arg("-c").arg(uninstaller_path).status()?,
|
_ => StdCommand::new(elevator)
|
||||||
|
.arg("sh")
|
||||||
|
.arg("-c")
|
||||||
|
.arg(uninstaller_path)
|
||||||
|
.status()?,
|
||||||
};
|
};
|
||||||
|
|
||||||
if !status.success() {
|
if !status.success() {
|
||||||
@ -156,6 +184,32 @@ pub async fn uninstall_service() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
pub async fn uninstall_service() -> Result<()> {
|
||||||
|
let binary_path = dirs::service_path()?;
|
||||||
|
let uninstaller_path = binary_path.with_file_name("uninstall-service");
|
||||||
|
|
||||||
|
if !uninstaller_path.exists() {
|
||||||
|
bail!("uninstaller not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
let shell = uninstaller_path.to_string_lossy();
|
||||||
|
let command = format!(r#"do shell script "{shell}" with administrator privileges"#);
|
||||||
|
|
||||||
|
let status = StdCommand::new("osascript")
|
||||||
|
.args(vec!["-e", &command])
|
||||||
|
.status()?;
|
||||||
|
|
||||||
|
if !status.success() {
|
||||||
|
bail!(
|
||||||
|
"failed to install service with status {}",
|
||||||
|
status.code().unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// check the windows service status
|
/// check the windows service status
|
||||||
pub async fn check_service() -> Result<JsonResponse> {
|
pub async fn check_service() -> Result<JsonResponse> {
|
||||||
let url = format!("{SERVICE_URL}/get_clash");
|
let url = format!("{SERVICE_URL}/get_clash");
|
||||||
@ -185,7 +239,7 @@ pub(super) async fn run_core_by_service(config_file: &PathBuf) -> Result<()> {
|
|||||||
let clash_core = { Config::verge().latest().clash_core.clone() };
|
let clash_core = { Config::verge().latest().clash_core.clone() };
|
||||||
let clash_core = clash_core.unwrap_or("clash".into());
|
let clash_core = clash_core.unwrap_or("clash".into());
|
||||||
|
|
||||||
let bin_ext = if cfg!(windows) {".exe"} else {""};
|
let bin_ext = if cfg!(windows) { ".exe" } else { "" };
|
||||||
let clash_bin = format!("{clash_core}{bin_ext}");
|
let clash_bin = format!("{clash_core}{bin_ext}");
|
||||||
let bin_path = current_exe()?.with_file_name(clash_bin);
|
let bin_path = current_exe()?.with_file_name(clash_bin);
|
||||||
let bin_path = dirs::path_to_str(&bin_path)?;
|
let bin_path = dirs::path_to_str(&bin_path)?;
|
||||||
|
@ -92,17 +92,16 @@ pub fn clash_pid_path() -> Result<PathBuf> {
|
|||||||
Ok(app_home_dir()?.join("clash.pid"))
|
Ok(app_home_dir()?.join("clash.pid"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(not(target_os = "windows"))]
|
||||||
pub fn service_path() -> Result<PathBuf> {
|
pub fn service_path() -> Result<PathBuf> {
|
||||||
Ok(app_resources_dir()?.join("clash-verge-service"))
|
Ok(app_resources_dir()?.join("clash-verge-service"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
pub fn service_path() -> Result<PathBuf> {
|
pub fn service_path() -> Result<PathBuf> {
|
||||||
Ok(app_resources_dir()?.join("clash-verge-service.exe"))
|
Ok(app_resources_dir()?.join("clash-verge-service.exe"))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(windows, target_os = "linux"))]
|
|
||||||
pub fn service_log_file() -> Result<PathBuf> {
|
pub fn service_log_file() -> Result<PathBuf> {
|
||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
|
|
||||||
|
@ -135,13 +135,12 @@ pub fn delete_log() -> Result<()> {
|
|||||||
for file in fs::read_dir(&log_dir)?.flatten() {
|
for file in fs::read_dir(&log_dir)?.flatten() {
|
||||||
let _ = process_file(file);
|
let _ = process_file(file);
|
||||||
}
|
}
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
{
|
let service_log_dir = log_dir.join("service");
|
||||||
let service_log_dir = log_dir.join("service");
|
for file in fs::read_dir(&service_log_dir)?.flatten() {
|
||||||
for file in fs::read_dir(&service_log_dir)?.flatten() {
|
let _ = process_file(file);
|
||||||
let _ = process_file(file);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use std::process::Command;
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub fn linux_elevator() -> &'static str {
|
pub fn linux_elevator() -> &'static str {
|
||||||
|
use std::process::Command;
|
||||||
match Command::new("which").arg("pkexec").output() {
|
match Command::new("which").arg("pkexec").output() {
|
||||||
Ok(output) => {
|
Ok(output) => {
|
||||||
if output.stdout.is_empty() {
|
if output.stdout.is_empty() {
|
||||||
|
@ -17,24 +17,17 @@ interface Props {
|
|||||||
onError?: (err: Error) => void;
|
onError?: (err: Error) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isServiceModeAvailable =
|
|
||||||
getSystem() === "windows" || getSystem() === "linux";
|
|
||||||
|
|
||||||
const SettingSystem = ({ onError }: Props) => {
|
const SettingSystem = ({ onError }: Props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { verge, mutateVerge, patchVerge } = useVerge();
|
const { verge, mutateVerge, patchVerge } = useVerge();
|
||||||
|
|
||||||
// service mode
|
// service mode
|
||||||
const { data: serviceStatus } = useSWR(
|
const { data: serviceStatus } = useSWR("checkService", checkService, {
|
||||||
isServiceModeAvailable ? "checkService" : null,
|
revalidateIfStale: false,
|
||||||
checkService,
|
shouldRetryOnError: false,
|
||||||
{
|
focusThrottleInterval: 36e5, // 1 hour
|
||||||
revalidateIfStale: false,
|
});
|
||||||
shouldRetryOnError: false,
|
|
||||||
focusThrottleInterval: 36e5, // 1 hour
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const serviceRef = useRef<DialogRef>(null);
|
const serviceRef = useRef<DialogRef>(null);
|
||||||
const sysproxyRef = useRef<DialogRef>(null);
|
const sysproxyRef = useRef<DialogRef>(null);
|
||||||
@ -57,22 +50,13 @@ const SettingSystem = ({ onError }: Props) => {
|
|||||||
<SettingList title={t("System Setting")}>
|
<SettingList title={t("System Setting")}>
|
||||||
<SysproxyViewer ref={sysproxyRef} />
|
<SysproxyViewer ref={sysproxyRef} />
|
||||||
<TunViewer ref={tunRef} />
|
<TunViewer ref={tunRef} />
|
||||||
{isServiceModeAvailable && (
|
<ServiceViewer ref={serviceRef} enable={!!enable_service_mode} />
|
||||||
<ServiceViewer ref={serviceRef} enable={!!enable_service_mode} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
<SettingItem
|
<SettingItem
|
||||||
label={t("Tun Mode")}
|
label={t("Tun Mode")}
|
||||||
extra={
|
extra={
|
||||||
<>
|
<>
|
||||||
<Tooltip
|
<Tooltip title={t("Tun Mode Info")} placement="top">
|
||||||
title={
|
|
||||||
isServiceModeAvailable
|
|
||||||
? t("Tun Mode Info Windows")
|
|
||||||
: t("Tun Mode Info Unix")
|
|
||||||
}
|
|
||||||
placement="top"
|
|
||||||
>
|
|
||||||
<IconButton color="inherit" size="small">
|
<IconButton color="inherit" size="small">
|
||||||
<InfoRounded
|
<InfoRounded
|
||||||
fontSize="inherit"
|
fontSize="inherit"
|
||||||
@ -105,39 +89,37 @@ const SettingSystem = ({ onError }: Props) => {
|
|||||||
</GuardState>
|
</GuardState>
|
||||||
</SettingItem>
|
</SettingItem>
|
||||||
|
|
||||||
{isServiceModeAvailable && (
|
<SettingItem
|
||||||
<SettingItem
|
label={t("Service Mode")}
|
||||||
label={t("Service Mode")}
|
extra={
|
||||||
extra={
|
<IconButton
|
||||||
<IconButton
|
color="inherit"
|
||||||
color="inherit"
|
size="small"
|
||||||
size="small"
|
onClick={() => serviceRef.current?.open()}
|
||||||
onClick={() => serviceRef.current?.open()}
|
|
||||||
>
|
|
||||||
<PrivacyTipRounded
|
|
||||||
fontSize="inherit"
|
|
||||||
style={{ cursor: "pointer", opacity: 0.75 }}
|
|
||||||
/>
|
|
||||||
</IconButton>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<GuardState
|
|
||||||
value={enable_service_mode ?? false}
|
|
||||||
valueProps="checked"
|
|
||||||
onCatch={onError}
|
|
||||||
onFormat={onSwitchFormat}
|
|
||||||
onChange={(e) => onChangeData({ enable_service_mode: e })}
|
|
||||||
onGuard={(e) => patchVerge({ enable_service_mode: e })}
|
|
||||||
>
|
>
|
||||||
<Switch
|
<PrivacyTipRounded
|
||||||
edge="end"
|
fontSize="inherit"
|
||||||
disabled={
|
style={{ cursor: "pointer", opacity: 0.75 }}
|
||||||
serviceStatus !== "active" && serviceStatus !== "installed"
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</GuardState>
|
</IconButton>
|
||||||
</SettingItem>
|
}
|
||||||
)}
|
>
|
||||||
|
<GuardState
|
||||||
|
value={enable_service_mode ?? false}
|
||||||
|
valueProps="checked"
|
||||||
|
onCatch={onError}
|
||||||
|
onFormat={onSwitchFormat}
|
||||||
|
onChange={(e) => onChangeData({ enable_service_mode: e })}
|
||||||
|
onGuard={(e) => patchVerge({ enable_service_mode: e })}
|
||||||
|
>
|
||||||
|
<Switch
|
||||||
|
edge="end"
|
||||||
|
disabled={
|
||||||
|
serviceStatus !== "active" && serviceStatus !== "installed"
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</GuardState>
|
||||||
|
</SettingItem>
|
||||||
|
|
||||||
<SettingItem
|
<SettingItem
|
||||||
label={t("System Proxy")}
|
label={t("System Proxy")}
|
||||||
|
@ -169,7 +169,6 @@
|
|||||||
"MTU": "Max Transmission Unit",
|
"MTU": "Max Transmission Unit",
|
||||||
|
|
||||||
"Portable Updater Error": "The portable version does not support in-app updates. Please manually download and replace it",
|
"Portable Updater Error": "The portable version does not support in-app updates. Please manually download and replace it",
|
||||||
"Tun Mode Info Windows": "The Tun mode requires granting core-related permissions. Please enable service mode before using it",
|
"Tun Mode Info": "The Tun mode requires granting core-related permissions. Please enable service mode before using it",
|
||||||
"Tun Mode Info Unix": "The Tun mode requires granting core-related permissions. Before using it, please authorize the core in the core settings",
|
|
||||||
"System and Mixed Can Only be Used in Service Mode": "System and Mixed Can Only be Used in Service Mode"
|
"System and Mixed Can Only be Used in Service Mode": "System and Mixed Can Only be Used in Service Mode"
|
||||||
}
|
}
|
||||||
|
@ -177,7 +177,6 @@
|
|||||||
"Reset to Default": "重置为默认值",
|
"Reset to Default": "重置为默认值",
|
||||||
|
|
||||||
"Portable Updater Error": "便携版不支持应用内更新,请手动下载替换",
|
"Portable Updater Error": "便携版不支持应用内更新,请手动下载替换",
|
||||||
"Tun Mode Info Windows": "Tun模式需要授予内核相关权限,使用前请先开启服务模式",
|
"Tun Mode Info": "Tun模式需要授予内核相关权限,使用前请先开启服务模式",
|
||||||
"Tun Mode Info Unix": "Tun模式需要授予内核相关权限,使用前请先在内核设置中给内核授权",
|
|
||||||
"System and Mixed Can Only be Used in Service Mode": "System和Mixed只能在服务模式下使用"
|
"System and Mixed Can Only be Used in Service Mode": "System和Mixed只能在服务模式下使用"
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user