feat: Support PAC Mode

This commit is contained in:
MystiPanda 2024-05-26 17:59:39 +08:00
parent fc1675575a
commit b9ec94d835
15 changed files with 311 additions and 85 deletions

2
src-tauri/Cargo.lock generated
View File

@ -5169,7 +5169,7 @@ dependencies = [
[[package]] [[package]]
name = "sysproxy" name = "sysproxy"
version = "0.3.0" version = "0.3.0"
source = "git+https://github.com/zzzgydi/sysproxy-rs?branch=main#1402eba27022a2da7b91b3090d2f4936b6260f10" source = "git+https://github.com/zzzgydi/sysproxy-rs?branch=main#24e8d46cb338a6a8e28742dea6ed993cd6450780"
dependencies = [ dependencies = [
"interfaces", "interfaces",
"iptools", "iptools",

View File

@ -8,7 +8,7 @@ use crate::{ret_err, wrap_err};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use serde_yaml::Mapping; use serde_yaml::Mapping;
use std::collections::{HashMap, VecDeque}; use std::collections::{HashMap, VecDeque};
use sysproxy::Sysproxy; use sysproxy::{Autoproxy, Sysproxy};
use tauri::{api, Manager}; use tauri::{api, Manager};
type CmdResult<T = ()> = Result<T, String>; type CmdResult<T = ()> = Result<T, String>;
@ -194,7 +194,6 @@ pub fn grant_permission(_core: String) -> CmdResult {
#[tauri::command] #[tauri::command]
pub fn get_sys_proxy() -> CmdResult<Mapping> { pub fn get_sys_proxy() -> CmdResult<Mapping> {
let current = wrap_err!(Sysproxy::get_system_proxy())?; let current = wrap_err!(Sysproxy::get_system_proxy())?;
let mut map = Mapping::new(); let mut map = Mapping::new();
map.insert("enable".into(), current.enable.into()); map.insert("enable".into(), current.enable.into());
map.insert( map.insert(
@ -206,6 +205,18 @@ pub fn get_sys_proxy() -> CmdResult<Mapping> {
Ok(map) Ok(map)
} }
/// get the system proxy
#[tauri::command]
pub fn get_auto_proxy() -> CmdResult<Mapping> {
let current = wrap_err!(Autoproxy::get_auto_proxy())?;
let mut map = Mapping::new();
map.insert("enable".into(), current.enable.into());
map.insert("url".into(), current.url.into());
Ok(map)
}
#[tauri::command] #[tauri::command]
pub fn get_clash_logs() -> CmdResult<VecDeque<String>> { pub fn get_clash_logs() -> CmdResult<VecDeque<String>> {
Ok(logger::Logger::global().get_log()) Ok(logger::Logger::global().get_log())

View File

@ -13,3 +13,8 @@ pub use self::prfitem::*;
pub use self::profiles::*; pub use self::profiles::*;
pub use self::runtime::*; pub use self::runtime::*;
pub use self::verge::*; pub use self::verge::*;
pub const DEFAULT_PAC: &str = r#"function FindProxyForURL(url, host) {
return "PROXY 127.0.0.1:%mixed-port%; SOCKS5 127.0.0.1:%mixed-port%; DIRECT;"
}
"#;

View File

@ -1,3 +1,4 @@
use crate::config::DEFAULT_PAC;
use crate::utils::{dirs, help}; use crate::utils::{dirs, help};
use anyhow::Result; use anyhow::Result;
use log::LevelFilter; use log::LevelFilter;
@ -80,6 +81,12 @@ pub struct IVerge {
/// proxy guard duration /// proxy guard duration
pub proxy_guard_duration: Option<u64>, pub proxy_guard_duration: Option<u64>,
/// use pac mode
pub proxy_auto_config: Option<bool>,
/// pac script content
pub pac_file_content: Option<String>,
/// theme setting /// theme setting
pub theme_setting: Option<IVergeTheme>, pub theme_setting: Option<IVergeTheme>,
@ -211,6 +218,8 @@ impl IVerge {
enable_auto_launch: Some(false), enable_auto_launch: Some(false),
enable_silent_start: Some(false), enable_silent_start: Some(false),
enable_system_proxy: Some(false), enable_system_proxy: Some(false),
proxy_auto_config: Some(false),
pac_file_content: Some(DEFAULT_PAC.into()),
enable_random_port: Some(false), enable_random_port: Some(false),
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
verge_redir_port: Some(7895), verge_redir_port: Some(7895),
@ -290,6 +299,8 @@ impl IVerge {
patch!(enable_proxy_guard); patch!(enable_proxy_guard);
patch!(system_proxy_bypass); patch!(system_proxy_bypass);
patch!(proxy_guard_duration); patch!(proxy_guard_duration);
patch!(proxy_auto_config);
patch!(pac_file_content);
patch!(theme_setting); patch!(theme_setting);
patch!(web_ui_list); patch!(web_ui_list);

View File

@ -1,11 +1,14 @@
use crate::{config::Config, log_err}; use crate::{
config::{Config, IVerge},
log_err,
};
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use auto_launch::{AutoLaunch, AutoLaunchBuilder}; use auto_launch::{AutoLaunch, AutoLaunchBuilder};
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use parking_lot::Mutex; use parking_lot::Mutex;
use std::env::current_exe; use std::env::current_exe;
use std::sync::Arc; use std::sync::Arc;
use sysproxy::Sysproxy; use sysproxy::{Autoproxy, Sysproxy};
use tauri::async_runtime::Mutex as TokioMutex; use tauri::async_runtime::Mutex as TokioMutex;
pub struct Sysopt { pub struct Sysopt {
@ -16,6 +19,13 @@ pub struct Sysopt {
/// recover it when exit /// recover it when exit
old_sysproxy: Arc<Mutex<Option<Sysproxy>>>, old_sysproxy: Arc<Mutex<Option<Sysproxy>>>,
/// current auto proxy setting
cur_autoproxy: Arc<Mutex<Option<Autoproxy>>>,
/// record the original auto proxy
/// recover it when exit
old_autoproxy: Arc<Mutex<Option<Autoproxy>>>,
/// helps to auto launch the app /// helps to auto launch the app
auto_launch: Arc<Mutex<Option<AutoLaunch>>>, auto_launch: Arc<Mutex<Option<AutoLaunch>>>,
@ -38,6 +48,8 @@ impl Sysopt {
SYSOPT.get_or_init(|| Sysopt { SYSOPT.get_or_init(|| Sysopt {
cur_sysproxy: Arc::new(Mutex::new(None)), cur_sysproxy: Arc::new(Mutex::new(None)),
old_sysproxy: Arc::new(Mutex::new(None)), old_sysproxy: Arc::new(Mutex::new(None)),
cur_autoproxy: Arc::new(Mutex::new(None)),
old_autoproxy: Arc::new(Mutex::new(None)),
auto_launch: Arc::new(Mutex::new(None)), auto_launch: Arc::new(Mutex::new(None)),
guard_state: Arc::new(TokioMutex::new(false)), guard_state: Arc::new(TokioMutex::new(false)),
}) })
@ -49,38 +61,77 @@ impl Sysopt {
.latest() .latest()
.verge_mixed_port .verge_mixed_port
.unwrap_or(Config::clash().data().get_mixed_port()); .unwrap_or(Config::clash().data().get_mixed_port());
let pac_port = IVerge::get_singleton_port();
let (enable, bypass) = { let (enable, bypass, pac) = {
let verge = Config::verge(); let verge = Config::verge();
let verge = verge.latest(); let verge = verge.latest();
( (
verge.enable_system_proxy.unwrap_or(false), verge.enable_system_proxy.unwrap_or(false),
verge.system_proxy_bypass.clone(), verge.system_proxy_bypass.clone(),
verge.proxy_auto_config.unwrap_or(false),
) )
}; };
if pac {
let current = Sysproxy { let sys = Sysproxy {
enable, enable: false,
host: String::from("127.0.0.1"), host: String::from("127.0.0.1"),
port, port,
bypass: match bypass { bypass: match bypass {
Some(bypass) => { Some(bypass) => {
if bypass.is_empty() { if bypass.is_empty() {
DEFAULT_BYPASS.into() DEFAULT_BYPASS.into()
} else { } else {
bypass bypass
}
} }
} None => DEFAULT_BYPASS.into(),
None => DEFAULT_BYPASS.into(), },
}, };
};
if enable {
let old = Sysproxy::get_system_proxy().ok(); let old = Sysproxy::get_system_proxy().ok();
current.set_system_proxy()?; sys.set_system_proxy()?;
*self.old_sysproxy.lock() = old; *self.old_sysproxy.lock() = old;
*self.cur_sysproxy.lock() = Some(current); *self.cur_sysproxy.lock() = Some(sys);
let auto = Autoproxy {
enable,
url: format!("http://127.0.0.1:{pac_port}/commands/pac"),
};
let old = Autoproxy::get_auto_proxy().ok();
auto.set_auto_proxy()?;
*self.old_autoproxy.lock() = old;
*self.cur_autoproxy.lock() = Some(auto);
} else {
let auto = Autoproxy {
enable: false,
url: String::new(),
};
let old = Autoproxy::get_auto_proxy().ok();
auto.set_auto_proxy()?;
*self.old_autoproxy.lock() = old;
*self.cur_autoproxy.lock() = Some(auto);
let sys = Sysproxy {
enable,
host: String::from("127.0.0.1"),
port,
bypass: match bypass {
Some(bypass) => {
if bypass.is_empty() {
DEFAULT_BYPASS.into()
} else {
bypass
}
}
None => DEFAULT_BYPASS.into(),
},
};
let old = Sysproxy::get_system_proxy().ok();
sys.set_system_proxy()?;
*self.old_sysproxy.lock() = old;
*self.cur_sysproxy.lock() = Some(sys);
} }
// run the system proxy guard // run the system proxy guard
@ -92,24 +143,38 @@ impl Sysopt {
pub fn update_sysproxy(&self) -> Result<()> { pub fn update_sysproxy(&self) -> Result<()> {
let mut cur_sysproxy = self.cur_sysproxy.lock(); let mut cur_sysproxy = self.cur_sysproxy.lock();
let old_sysproxy = self.old_sysproxy.lock(); let old_sysproxy = self.old_sysproxy.lock();
let mut cur_autoproxy = self.cur_autoproxy.lock();
let old_autoproxy = self.old_autoproxy.lock();
if cur_sysproxy.is_none() || old_sysproxy.is_none() { let (enable, bypass, pac) = {
drop(cur_sysproxy);
drop(old_sysproxy);
return self.init_sysproxy();
}
let (enable, bypass) = {
let verge = Config::verge(); let verge = Config::verge();
let verge = verge.latest(); let verge = verge.latest();
( (
verge.enable_system_proxy.unwrap_or(false), verge.enable_system_proxy.unwrap_or(false),
verge.system_proxy_bypass.clone(), verge.system_proxy_bypass.clone(),
verge.proxy_auto_config.unwrap_or(false),
) )
}; };
let mut sysproxy = cur_sysproxy.take().unwrap(); if pac {
if cur_autoproxy.is_none() || old_autoproxy.is_none() {
drop(cur_autoproxy);
drop(old_autoproxy);
return self.init_sysproxy();
}
} else {
if cur_sysproxy.is_none() || old_sysproxy.is_none() {
drop(cur_sysproxy);
drop(old_sysproxy);
return self.init_sysproxy();
}
}
let port = Config::verge()
.latest()
.verge_mixed_port
.unwrap_or(Config::clash().data().get_mixed_port());
let pac_port = IVerge::get_singleton_port();
sysproxy.enable = enable; let mut sysproxy = cur_sysproxy.take().unwrap();
sysproxy.bypass = match bypass { sysproxy.bypass = match bypass {
Some(bypass) => { Some(bypass) => {
if bypass.is_empty() { if bypass.is_empty() {
@ -120,15 +185,26 @@ impl Sysopt {
} }
None => DEFAULT_BYPASS.into(), None => DEFAULT_BYPASS.into(),
}; };
let port = Config::verge()
.latest()
.verge_mixed_port
.unwrap_or(Config::clash().data().get_mixed_port());
sysproxy.port = port; sysproxy.port = port;
sysproxy.set_system_proxy()?; let mut autoproxy = cur_autoproxy.take().unwrap();
*cur_sysproxy = Some(sysproxy); autoproxy.url = format!("http://127.0.0.1:{pac_port}/commands/pac");
if pac {
sysproxy.enable = false;
sysproxy.set_system_proxy()?;
*cur_sysproxy = Some(sysproxy);
autoproxy.enable = enable;
autoproxy.set_auto_proxy()?;
*cur_autoproxy = Some(autoproxy);
} else {
autoproxy.enable = false;
autoproxy.set_auto_proxy()?;
*cur_autoproxy = Some(autoproxy);
sysproxy.enable = enable;
sysproxy.set_system_proxy()?;
*cur_sysproxy = Some(sysproxy);
}
Ok(()) Ok(())
} }

View File

@ -177,6 +177,8 @@ pub async fn patch_verge(patch: IVerge) -> Result<()> {
let tun_mode = patch.enable_tun_mode; let tun_mode = patch.enable_tun_mode;
let auto_launch = patch.enable_auto_launch; let auto_launch = patch.enable_auto_launch;
let system_proxy = patch.enable_system_proxy; let system_proxy = patch.enable_system_proxy;
let pac = patch.proxy_auto_config;
let pac_content = patch.pac_file_content;
let proxy_bypass = patch.system_proxy_bypass; let proxy_bypass = patch.system_proxy_bypass;
let language = patch.language; let language = patch.language;
let port = patch.verge_mixed_port; let port = patch.verge_mixed_port;
@ -219,7 +221,12 @@ pub async fn patch_verge(patch: IVerge) -> Result<()> {
if auto_launch.is_some() { if auto_launch.is_some() {
sysopt::Sysopt::global().update_launch()?; sysopt::Sysopt::global().update_launch()?;
} }
if system_proxy.is_some() || proxy_bypass.is_some() || port.is_some() { if system_proxy.is_some()
|| proxy_bypass.is_some()
|| port.is_some()
|| pac.is_some()
|| pac_content.is_some()
{
sysopt::Sysopt::global().update_sysproxy()?; sysopt::Sysopt::global().update_sysproxy()?;
sysopt::Sysopt::global().guard_proxy(); sysopt::Sysopt::global().guard_proxy();
} }

View File

@ -36,6 +36,7 @@ fn main() -> std::io::Result<()> {
.invoke_handler(tauri::generate_handler![ .invoke_handler(tauri::generate_handler![
// common // common
cmds::get_sys_proxy, cmds::get_sys_proxy,
cmds::get_auto_proxy,
cmds::open_app_dir, cmds::open_app_dir,
cmds::open_logs_dir, cmds::open_logs_dir,
cmds::open_web_url, cmds::open_web_url,

View File

@ -1,7 +1,7 @@
extern crate warp; extern crate warp;
use super::resolve; use super::resolve;
use crate::config::IVerge; use crate::config::{Config, IVerge, DEFAULT_PAC};
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use port_scanner::local_port_available; use port_scanner::local_port_available;
use std::convert::Infallible; use std::convert::Infallible;
@ -64,6 +64,18 @@ pub fn embed_server(app_handle: AppHandle) {
"ok" "ok"
}); });
let pac = warp::path!("commands" / "pac").map(move || {
let content = Config::verge()
.latest()
.pac_file_content
.clone()
.unwrap_or(DEFAULT_PAC.to_string());
let port = Config::verge()
.latest()
.verge_mixed_port
.unwrap_or(Config::clash().data().get_mixed_port());
content.replace("%mixed-port%", &format!("{}", port))
});
let scheme = warp::path!("commands" / "scheme") let scheme = warp::path!("commands" / "scheme")
.and(warp::query::<QueryParam>()) .and(warp::query::<QueryParam>())
.and_then(scheme_handler); .and_then(scheme_handler);
@ -72,7 +84,7 @@ pub fn embed_server(app_handle: AppHandle) {
resolve::resolve_scheme(query.param).await; resolve::resolve_scheme(query.param).await;
Ok("ok") Ok("ok")
} }
let commands = ping.or(visible).or(scheme); let commands = ping.or(visible).or(pac).or(scheme);
warp::serve(commands).run(([127, 0, 0, 1], port)).await; warp::serve(commands).run(([127, 0, 0, 1], port)).await;
}); });
} }

View File

@ -10,23 +10,34 @@ import {
styled, styled,
TextField, TextField,
Typography, Typography,
Button,
} from "@mui/material"; } from "@mui/material";
import { useVerge } from "@/hooks/use-verge"; import { useVerge } from "@/hooks/use-verge";
import { getSystemProxy } from "@/services/cmds"; import { getSystemProxy, getAutotemProxy } from "@/services/cmds";
import { BaseDialog, DialogRef, Notice, Switch } from "@/components/base"; import { BaseDialog, DialogRef, Notice, Switch } from "@/components/base";
import { Edit } from "@mui/icons-material";
import { EditorViewer } from "@/components/profile/editor-viewer";
const DEFAULT_PAC = `function FindProxyForURL(url, host) {
return "PROXY 127.0.0.1:%mixed-port%; SOCKS5 127.0.0.1:%mixed-port%; DIRECT;"
}`;
export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => { export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
const { t } = useTranslation(); const { t } = useTranslation();
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [editorOpen, setEditorOpen] = useState(false);
const { verge, patchVerge } = useVerge(); const { verge, patchVerge } = useVerge();
type SysProxy = Awaited<ReturnType<typeof getSystemProxy>>; type SysProxy = Awaited<ReturnType<typeof getSystemProxy>>;
const [sysproxy, setSysproxy] = useState<SysProxy>(); const [sysproxy, setSysproxy] = useState<SysProxy>();
type AutoProxy = Awaited<ReturnType<typeof getAutotemProxy>>;
const [autoproxy, setAutoproxy] = useState<AutoProxy>();
const { const {
enable_system_proxy: enabled, enable_system_proxy: enabled,
proxy_auto_config,
pac_file_content,
enable_proxy_guard, enable_proxy_guard,
system_proxy_bypass, system_proxy_bypass,
proxy_guard_duration, proxy_guard_duration,
@ -36,6 +47,8 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
guard: enable_proxy_guard, guard: enable_proxy_guard,
bypass: system_proxy_bypass, bypass: system_proxy_bypass,
duration: proxy_guard_duration ?? 10, duration: proxy_guard_duration ?? 10,
pac: proxy_auto_config,
pac_content: pac_file_content ?? DEFAULT_PAC,
}); });
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
@ -45,8 +58,11 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
guard: enable_proxy_guard, guard: enable_proxy_guard,
bypass: system_proxy_bypass, bypass: system_proxy_bypass,
duration: proxy_guard_duration ?? 10, duration: proxy_guard_duration ?? 10,
pac: proxy_auto_config,
pac_content: pac_file_content ?? DEFAULT_PAC,
}); });
getSystemProxy().then((p) => setSysproxy(p)); getSystemProxy().then((p) => setSysproxy(p));
getAutotemProxy().then((p) => setAutoproxy(p));
}, },
close: () => setOpen(false), close: () => setOpen(false),
})); }));
@ -68,6 +84,12 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
if (value.bypass !== system_proxy_bypass) { if (value.bypass !== system_proxy_bypass) {
patch.system_proxy_bypass = value.bypass; patch.system_proxy_bypass = value.bypass;
} }
if (value.pac !== proxy_auto_config) {
patch.proxy_auto_config = value.pac;
}
if (value.pac_content !== pac_file_content) {
patch.pac_file_content = value.pac_content;
}
try { try {
await patchVerge(patch); await patchVerge(patch);
@ -89,6 +111,15 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
onOk={onSave} onOk={onSave}
> >
<List> <List>
<ListItem sx={{ padding: "5px 2px" }}>
<ListItemText primary={t("Use PAC Mode")} />
<Switch
edge="end"
disabled={!enabled}
checked={value.pac}
onChange={(_, e) => setValue((v) => ({ ...v, pac: e }))}
/>
</ListItem>
<ListItem sx={{ padding: "5px 2px" }}> <ListItem sx={{ padding: "5px 2px" }}>
<ListItemText primary={t("Proxy Guard")} /> <ListItemText primary={t("Proxy Guard")} />
<Switch <Switch
@ -117,25 +148,63 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
}} }}
/> />
</ListItem> </ListItem>
{!value.pac && (
<ListItem sx={{ padding: "5px 2px", alignItems: "start" }}> <>
<ListItemText primary={t("Proxy Bypass")} sx={{ padding: "3px 0" }} /> <ListItem sx={{ padding: "5px 2px", alignItems: "start" }}>
</ListItem> <ListItemText
<ListItem sx={{ padding: "5px 2px" }}> primary={t("Proxy Bypass")}
<TextField sx={{ padding: "3px 0" }}
disabled={!enabled} />
size="small" </ListItem>
autoComplete="off" <ListItem sx={{ padding: "5px 2px" }}>
multiline <TextField
rows={4} disabled={!enabled}
sx={{ width: "100%" }} size="small"
value={value.bypass} autoComplete="off"
placeholder={sysproxy?.bypass || `-`} multiline
onChange={(e) => rows={4}
setValue((v) => ({ ...v, bypass: e.target.value })) sx={{ width: "100%" }}
} value={value.bypass}
/> placeholder={sysproxy?.bypass || `-`}
</ListItem> onChange={(e) =>
setValue((v) => ({ ...v, bypass: e.target.value }))
}
/>
</ListItem>
</>
)}
{value.pac && (
<>
<ListItem sx={{ padding: "5px 2px", alignItems: "start" }}>
<ListItemText
primary={t("PAC Script Content")}
sx={{ padding: "3px 0" }}
/>
<Button
startIcon={<Edit />}
variant="outlined"
onClick={() => {
setEditorOpen(true);
}}
>
{t("Edit")} PAC
</Button>
<EditorViewer
title={`${t("Edit")} PAC`}
mode="text"
property={value.pac_content ?? ""}
open={editorOpen}
language="javascript"
onChange={(content) => {
setValue((v) => ({ ...v, pac_content: content ?? "" }));
}}
onClose={() => {
setEditorOpen(false);
}}
/>
</ListItem>
</>
)}
</List> </List>
<Box sx={{ mt: 2.5 }}> <Box sx={{ mt: 2.5 }}>
@ -146,29 +215,42 @@ export const SysproxyViewer = forwardRef<DialogRef>((props, ref) => {
<FlexBox> <FlexBox>
<Typography className="label">{t("Enable status")}</Typography> <Typography className="label">{t("Enable status")}</Typography>
<Typography className="value"> <Typography className="value">
{(!!sysproxy?.enable).toString()} {value.pac
? (!!autoproxy?.enable).toString()
: (!!sysproxy?.enable).toString()}
</Typography> </Typography>
</FlexBox> </FlexBox>
{!value.pac && (
<>
<FlexBox>
<Typography className="label">{t("Server Addr")}</Typography>
<Typography className="value">
{sysproxy?.server || "-"}
</Typography>
</FlexBox>
<FlexBox> <FlexBox>
<Typography className="label">{t("Server Addr")}</Typography> <Typography className="label">{t("Bypass")}</Typography>
<Typography className="value">{sysproxy?.server || "-"}</Typography> </FlexBox>
</FlexBox> <FlexBox>
<TextField
<FlexBox> disabled={true}
<Typography className="label">{t("Bypass")}</Typography> size="small"
</FlexBox> autoComplete="off"
<FlexBox> multiline
<TextField rows={4}
disabled={true} sx={{ width: "100%" }}
size="small" value={sysproxy?.bypass || "-"}
autoComplete="off" />
multiline </FlexBox>
rows={4} </>
sx={{ width: "100%" }} )}
value={sysproxy?.bypass || "-"} {value.pac && (
/> <FlexBox>
</FlexBox> <Typography className="label">{t("PAC URL")}</Typography>
<Typography className="value">{autoproxy?.url || "-"}</Typography>
</FlexBox>
)}
</Box> </Box>
</BaseDialog> </BaseDialog>
); );

View File

@ -118,6 +118,9 @@
"System Proxy Setting": "System Proxy Setting", "System Proxy Setting": "System Proxy Setting",
"Open UWP tool": "Open UWP tool", "Open UWP tool": "Open UWP tool",
"Update GeoData": "Update GeoData", "Update GeoData": "Update GeoData",
"Use PAC Mode": "Use PAC Mode",
"PAC URL": "PAC URL",
"PAC Script Content": "PAC Script Content",
"Proxy Guard": "Proxy Guard", "Proxy Guard": "Proxy Guard",
"Guard Duration": "Guard Duration", "Guard Duration": "Guard Duration",
"Proxy Bypass": "Proxy Bypass", "Proxy Bypass": "Proxy Bypass",

View File

@ -118,6 +118,9 @@
"System Proxy Setting": "تنظیمات پراکسی سیستم", "System Proxy Setting": "تنظیمات پراکسی سیستم",
"Open UWP tool": "باز کردن ابزار UWP", "Open UWP tool": "باز کردن ابزار UWP",
"Update GeoData": "به‌روزرسانی GeoData", "Update GeoData": "به‌روزرسانی GeoData",
"Use PAC Mode": "استفاده از حالت PAC",
"PAC URL": "PAC URL",
"PAC Script Content": "محتوای اسکریپت PAC",
"Proxy Guard": "محافظ پراکسی", "Proxy Guard": "محافظ پراکسی",
"Guard Duration": "مدت محافظت", "Guard Duration": "مدت محافظت",
"Proxy Bypass": "دور زدن پراکسی", "Proxy Bypass": "دور زدن پراکسی",

View File

@ -118,6 +118,9 @@
"System Proxy Setting": "Настройка системного прокси", "System Proxy Setting": "Настройка системного прокси",
"Open UWP tool": "Открыть UWP инструмент", "Open UWP tool": "Открыть UWP инструмент",
"Update GeoData": "Обновление GeoData", "Update GeoData": "Обновление GeoData",
"Use PAC Mode": "Используйте режим PAC.",
"PAC URL": "Адрес PAC",
"PAC Script Content": "Содержание сценария PAC",
"Proxy Guard": "Защита прокси", "Proxy Guard": "Защита прокси",
"Guard Duration": "Период защиты", "Guard Duration": "Период защиты",
"Proxy Bypass": "Игнорирование прокси", "Proxy Bypass": "Игнорирование прокси",

View File

@ -118,6 +118,9 @@
"System Proxy Setting": "系统代理设置", "System Proxy Setting": "系统代理设置",
"Open UWP tool": "UWP 工具", "Open UWP tool": "UWP 工具",
"Update GeoData": "更新 GeoData", "Update GeoData": "更新 GeoData",
"Use PAC Mode": "使用PAC模式",
"PAC URL": "PAC 地址",
"PAC Script Content": "PAC 脚本内容",
"Proxy Guard": "系统代理守卫", "Proxy Guard": "系统代理守卫",
"Guard Duration": "代理守卫间隔", "Guard Duration": "代理守卫间隔",
"Proxy Bypass": "代理绕过", "Proxy Bypass": "代理绕过",

View File

@ -127,6 +127,13 @@ export async function getSystemProxy() {
}>("get_sys_proxy"); }>("get_sys_proxy");
} }
export async function getAutotemProxy() {
return invoke<{
enable: boolean;
url: string;
}>("get_auto_proxy");
}
export async function changeClashCore(clashCore: string) { export async function changeClashCore(clashCore: string) {
return invoke<any>("change_clash_core", { clashCore }); return invoke<any>("change_clash_core", { clashCore });
} }

View File

@ -216,6 +216,8 @@ interface IVergeConfig {
enable_service_mode?: boolean; enable_service_mode?: boolean;
enable_silent_start?: boolean; enable_silent_start?: boolean;
enable_system_proxy?: boolean; enable_system_proxy?: boolean;
proxy_auto_config?: boolean;
pac_file_content?: string;
enable_random_port?: boolean; enable_random_port?: boolean;
verge_mixed_port?: number; verge_mixed_port?: number;
verge_socks_port?: number; verge_socks_port?: number;