mirror of
https://github.com/clash-verge-rev/clash-verge-rev
synced 2025-05-05 06:53:44 +08:00
feat: support random mixed port
This commit is contained in:
parent
2d8da45bda
commit
e9f14de05d
@ -194,7 +194,10 @@ impl PrfItem {
|
|||||||
|
|
||||||
// 使用软件自己的代理
|
// 使用软件自己的代理
|
||||||
if self_proxy {
|
if self_proxy {
|
||||||
let port = Config::clash().data().get_mixed_port();
|
let port = Config::verge()
|
||||||
|
.latest()
|
||||||
|
.verge_mixed_port
|
||||||
|
.unwrap_or(Config::clash().data().get_mixed_port());
|
||||||
|
|
||||||
let proxy_scheme = format!("http://127.0.0.1:{port}");
|
let proxy_scheme = format!("http://127.0.0.1:{port}");
|
||||||
|
|
||||||
|
@ -93,6 +93,12 @@ pub struct IVerge {
|
|||||||
/// window size and position
|
/// window size and position
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub window_size_position: Option<Vec<f64>>,
|
pub window_size_position: Option<Vec<f64>>,
|
||||||
|
|
||||||
|
/// 是否启用随机端口
|
||||||
|
pub enable_random_port: Option<bool>,
|
||||||
|
|
||||||
|
/// verge mixed port 用于覆盖 clash 的 mixed port
|
||||||
|
pub verge_mixed_port: Option<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
|
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
|
||||||
@ -139,6 +145,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),
|
||||||
|
enable_random_port: Some(false),
|
||||||
|
verge_mixed_port: Some(7890),
|
||||||
enable_proxy_guard: Some(false),
|
enable_proxy_guard: Some(false),
|
||||||
proxy_guard_duration: Some(30),
|
proxy_guard_duration: Some(30),
|
||||||
auto_close_connection: Some(true),
|
auto_close_connection: Some(true),
|
||||||
@ -177,6 +185,8 @@ impl IVerge {
|
|||||||
patch!(enable_service_mode);
|
patch!(enable_service_mode);
|
||||||
patch!(enable_auto_launch);
|
patch!(enable_auto_launch);
|
||||||
patch!(enable_silent_start);
|
patch!(enable_silent_start);
|
||||||
|
patch!(enable_random_port);
|
||||||
|
patch!(verge_mixed_port);
|
||||||
patch!(enable_system_proxy);
|
patch!(enable_system_proxy);
|
||||||
patch!(enable_proxy_guard);
|
patch!(enable_proxy_guard);
|
||||||
patch!(system_proxy_bypass);
|
patch!(system_proxy_bypass);
|
||||||
|
@ -27,7 +27,8 @@ static DEFAULT_BYPASS: &str = "localhost;127.*;192.168.*;10.*;172.16.*;<local>";
|
|||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
static DEFAULT_BYPASS: &str = "localhost,127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,::1";
|
static DEFAULT_BYPASS: &str = "localhost,127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,::1";
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
static DEFAULT_BYPASS: &str = "127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,localhost,*.local,*.crashlytics.com,<local>";
|
static DEFAULT_BYPASS: &str =
|
||||||
|
"127.0.0.1,192.168.0.0/16,10.0.0.0/8,172.16.0.0/12,localhost,*.local,*.crashlytics.com,<local>";
|
||||||
|
|
||||||
impl Sysopt {
|
impl Sysopt {
|
||||||
pub fn global() -> &'static Sysopt {
|
pub fn global() -> &'static Sysopt {
|
||||||
@ -43,7 +44,10 @@ impl Sysopt {
|
|||||||
|
|
||||||
/// init the sysproxy
|
/// init the sysproxy
|
||||||
pub fn init_sysproxy(&self) -> Result<()> {
|
pub fn init_sysproxy(&self) -> Result<()> {
|
||||||
let port = { Config::clash().latest().get_mixed_port() };
|
let port = Config::verge()
|
||||||
|
.latest()
|
||||||
|
.verge_mixed_port
|
||||||
|
.unwrap_or(Config::clash().data().get_mixed_port());
|
||||||
|
|
||||||
let (enable, bypass) = {
|
let (enable, bypass) = {
|
||||||
let verge = Config::verge();
|
let verge = Config::verge();
|
||||||
@ -284,7 +288,12 @@ impl Sysopt {
|
|||||||
|
|
||||||
log::debug!(target: "app", "try to guard the system proxy");
|
log::debug!(target: "app", "try to guard the system proxy");
|
||||||
|
|
||||||
let port = { Config::clash().latest().get_mixed_port() };
|
let port = {
|
||||||
|
Config::verge()
|
||||||
|
.latest()
|
||||||
|
.verge_mixed_port
|
||||||
|
.unwrap_or(Config::clash().data().get_mixed_port())
|
||||||
|
};
|
||||||
|
|
||||||
let sysproxy = Sysproxy {
|
let sysproxy = Sysproxy {
|
||||||
enable: true,
|
enable: true,
|
||||||
|
@ -162,8 +162,13 @@ pub async fn patch_clash(patch: Mapping) -> Result<()> {
|
|||||||
|
|
||||||
match {
|
match {
|
||||||
let mixed_port = patch.get("mixed-port");
|
let mixed_port = patch.get("mixed-port");
|
||||||
if mixed_port.is_some() {
|
let enable_random_port = Config::verge().latest().enable_random_port.unwrap_or(false);
|
||||||
let changed = mixed_port != Config::clash().data().0.get("mixed-port");
|
if mixed_port.is_some() && !enable_random_port {
|
||||||
|
let changed = mixed_port.clone().unwrap()
|
||||||
|
!= Config::verge()
|
||||||
|
.latest()
|
||||||
|
.verge_mixed_port
|
||||||
|
.unwrap_or(Config::clash().data().get_mixed_port());
|
||||||
// 检查端口占用
|
// 检查端口占用
|
||||||
if changed {
|
if changed {
|
||||||
if let Some(port) = mixed_port.clone().unwrap().as_u64() {
|
if let Some(port) = mixed_port.clone().unwrap().as_u64() {
|
||||||
@ -333,11 +338,12 @@ async fn update_core_config() -> Result<()> {
|
|||||||
|
|
||||||
/// copy env variable
|
/// copy env variable
|
||||||
pub fn copy_clash_env(option: &str) {
|
pub fn copy_clash_env(option: &str) {
|
||||||
let port = { Config::clash().data().get_client_info().port };
|
let port = { Config::verge().latest().verge_mixed_port.unwrap_or(7890) };
|
||||||
let http_proxy = format!("http://127.0.0.1:{}", port);
|
let http_proxy = format!("http://127.0.0.1:{}", port);
|
||||||
let socks5_proxy = format!("socks5://127.0.0.1:{}", port);
|
let socks5_proxy = format!("socks5://127.0.0.1:{}", port);
|
||||||
|
|
||||||
let sh = format!("export https_proxy={http_proxy} http_proxy={http_proxy} all_proxy={socks5_proxy}");
|
let sh =
|
||||||
|
format!("export https_proxy={http_proxy} http_proxy={http_proxy} all_proxy={socks5_proxy}");
|
||||||
let cmd: String = format!("set http_proxy={http_proxy} \n set https_proxy={http_proxy}");
|
let cmd: String = format!("set http_proxy={http_proxy} \n set https_proxy={http_proxy}");
|
||||||
let ps: String = format!("$env:HTTP_PROXY=\"{http_proxy}\"; $env:HTTPS_PROXY=\"{http_proxy}\"");
|
let ps: String = format!("$env:HTTP_PROXY=\"{http_proxy}\"; $env:HTTPS_PROXY=\"{http_proxy}\"");
|
||||||
|
|
||||||
|
@ -1,8 +1,28 @@
|
|||||||
|
use crate::config::IVerge;
|
||||||
use crate::{config::Config, core::*, utils::init, utils::server};
|
use crate::{config::Config, core::*, utils::init, utils::server};
|
||||||
use crate::{log_err, trace_err};
|
use crate::{log_err, trace_err};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use serde_yaml::Mapping;
|
||||||
|
use std::net::TcpListener;
|
||||||
use tauri::{App, AppHandle, Manager};
|
use tauri::{App, AppHandle, Manager};
|
||||||
|
|
||||||
|
pub fn find_unused_port() -> Result<u16> {
|
||||||
|
match TcpListener::bind("127.0.0.1:0") {
|
||||||
|
Ok(listener) => {
|
||||||
|
let port = listener.local_addr()?.port();
|
||||||
|
Ok(port)
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
let port = Config::verge()
|
||||||
|
.latest()
|
||||||
|
.verge_mixed_port
|
||||||
|
.unwrap_or(Config::clash().data().get_mixed_port());
|
||||||
|
log::warn!(target: "app", "use default port: {}", port);
|
||||||
|
Ok(port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// handle something when start app
|
/// handle something when start app
|
||||||
pub fn resolve_setup(app: &mut App) {
|
pub fn resolve_setup(app: &mut App) {
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
@ -12,6 +32,33 @@ pub fn resolve_setup(app: &mut App) {
|
|||||||
|
|
||||||
log_err!(init::init_resources(app.package_info()));
|
log_err!(init::init_resources(app.package_info()));
|
||||||
|
|
||||||
|
// 处理随机端口
|
||||||
|
let enable_random_port = Config::verge().latest().enable_random_port.unwrap_or(false);
|
||||||
|
|
||||||
|
let mut port = Config::verge()
|
||||||
|
.latest()
|
||||||
|
.verge_mixed_port
|
||||||
|
.unwrap_or(Config::clash().data().get_mixed_port());
|
||||||
|
|
||||||
|
if enable_random_port {
|
||||||
|
port = find_unused_port().unwrap_or(
|
||||||
|
Config::verge()
|
||||||
|
.latest()
|
||||||
|
.verge_mixed_port
|
||||||
|
.unwrap_or(Config::clash().data().get_mixed_port()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Config::verge().data().patch_config(IVerge {
|
||||||
|
verge_mixed_port: Some(port),
|
||||||
|
..IVerge::default()
|
||||||
|
});
|
||||||
|
let _ = Config::verge().data().save_file();
|
||||||
|
let mut mapping = Mapping::new();
|
||||||
|
mapping.insert("mixed-port".into(), port.into());
|
||||||
|
Config::clash().data().patch_config(mapping);
|
||||||
|
let _ = Config::clash().data().save_config();
|
||||||
|
|
||||||
// 启动核心
|
// 启动核心
|
||||||
log::trace!("init config");
|
log::trace!("init config");
|
||||||
log_err!(Config::init_config());
|
log_err!(Config::init_config());
|
||||||
|
@ -4,30 +4,35 @@ import { useLockFn } from "ahooks";
|
|||||||
import { List, ListItem, ListItemText, TextField } from "@mui/material";
|
import { List, ListItem, ListItemText, TextField } from "@mui/material";
|
||||||
import { useClashInfo } from "@/hooks/use-clash";
|
import { useClashInfo } from "@/hooks/use-clash";
|
||||||
import { BaseDialog, DialogRef, Notice } from "@/components/base";
|
import { BaseDialog, DialogRef, Notice } from "@/components/base";
|
||||||
|
import { useVerge } from "@/hooks/use-verge";
|
||||||
|
|
||||||
export const ClashPortViewer = forwardRef<DialogRef>((props, ref) => {
|
export const ClashPortViewer = forwardRef<DialogRef>((props, ref) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { clashInfo, patchInfo } = useClashInfo();
|
const { clashInfo, patchInfo } = useClashInfo();
|
||||||
|
const { verge, patchVerge } = useVerge();
|
||||||
|
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [port, setPort] = useState(clashInfo?.port ?? 7890);
|
const [port, setPort] = useState(
|
||||||
|
verge?.verge_mixed_port ?? clashInfo?.port ?? 7890
|
||||||
|
);
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
open: () => {
|
open: () => {
|
||||||
if (clashInfo?.port) setPort(clashInfo?.port);
|
if (verge?.verge_mixed_port) setPort(verge?.verge_mixed_port);
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
},
|
},
|
||||||
close: () => setOpen(false),
|
close: () => setOpen(false),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const onSave = useLockFn(async () => {
|
const onSave = useLockFn(async () => {
|
||||||
if (port === clashInfo?.port) {
|
if (port === verge?.verge_mixed_port) {
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await patchInfo({ "mixed-port": port });
|
await patchInfo({ "mixed-port": port });
|
||||||
|
await patchVerge({ verge_mixed_port: port });
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
Notice.success("Change Clash port successfully!", 1000);
|
Notice.success("Change Clash port successfully!", 1000);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
|
@ -7,9 +7,10 @@ import {
|
|||||||
MenuItem,
|
MenuItem,
|
||||||
Typography,
|
Typography,
|
||||||
IconButton,
|
IconButton,
|
||||||
|
Tooltip,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { ArrowForward, Settings } from "@mui/icons-material";
|
import { ArrowForward, Settings, Shuffle } from "@mui/icons-material";
|
||||||
import { DialogRef } from "@/components/base";
|
import { DialogRef, Notice } from "@/components/base";
|
||||||
import { useClash } from "@/hooks/use-clash";
|
import { useClash } from "@/hooks/use-clash";
|
||||||
import { GuardState } from "./mods/guard-state";
|
import { GuardState } from "./mods/guard-state";
|
||||||
import { WebUIViewer } from "./mods/web-ui-viewer";
|
import { WebUIViewer } from "./mods/web-ui-viewer";
|
||||||
@ -20,6 +21,7 @@ import { SettingList, SettingItem } from "./mods/setting-comp";
|
|||||||
import { ClashCoreViewer } from "./mods/clash-core-viewer";
|
import { ClashCoreViewer } from "./mods/clash-core-viewer";
|
||||||
import { invoke_uwp_tool } from "@/services/cmds";
|
import { invoke_uwp_tool } from "@/services/cmds";
|
||||||
import getSystem from "@/utils/get-system";
|
import getSystem from "@/utils/get-system";
|
||||||
|
import { useVerge } from "@/hooks/use-verge";
|
||||||
|
|
||||||
const isWIN = getSystem() === "windows";
|
const isWIN = getSystem() === "windows";
|
||||||
|
|
||||||
@ -32,12 +34,11 @@ const SettingClash = ({ onError }: Props) => {
|
|||||||
|
|
||||||
const { clash, version, mutateClash, patchClash } = useClash();
|
const { clash, version, mutateClash, patchClash } = useClash();
|
||||||
|
|
||||||
const {
|
const { verge, mutateVerge, patchVerge } = useVerge();
|
||||||
ipv6,
|
|
||||||
"allow-lan": allowLan,
|
const { ipv6, "allow-lan": allowLan, "log-level": logLevel } = clash ?? {};
|
||||||
"log-level": logLevel,
|
|
||||||
"mixed-port": mixedPort,
|
const { enable_random_port = false, verge_mixed_port } = verge ?? {};
|
||||||
} = clash ?? {};
|
|
||||||
|
|
||||||
const webRef = useRef<DialogRef>(null);
|
const webRef = useRef<DialogRef>(null);
|
||||||
const fieldRef = useRef<DialogRef>(null);
|
const fieldRef = useRef<DialogRef>(null);
|
||||||
@ -49,7 +50,9 @@ const SettingClash = ({ onError }: Props) => {
|
|||||||
const onChangeData = (patch: Partial<IConfigData>) => {
|
const onChangeData = (patch: Partial<IConfigData>) => {
|
||||||
mutateClash((old) => ({ ...(old! || {}), ...patch }), false);
|
mutateClash((old) => ({ ...(old! || {}), ...patch }), false);
|
||||||
};
|
};
|
||||||
|
const onChangeVerge = (patch: Partial<IVergeConfig>) => {
|
||||||
|
mutateVerge({ ...verge, ...patch }, false);
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<SettingList title={t("Clash Setting")}>
|
<SettingList title={t("Clash Setting")}>
|
||||||
<WebUIViewer ref={webRef} />
|
<WebUIViewer ref={webRef} />
|
||||||
@ -103,11 +106,32 @@ const SettingClash = ({ onError }: Props) => {
|
|||||||
</GuardState>
|
</GuardState>
|
||||||
</SettingItem>
|
</SettingItem>
|
||||||
|
|
||||||
<SettingItem label={t("Mixed Port")}>
|
<SettingItem
|
||||||
|
label={t("Mixed Port")}
|
||||||
|
extra={
|
||||||
|
<Tooltip title={t("Random Port")}>
|
||||||
|
<IconButton
|
||||||
|
color={enable_random_port ? "success" : "inherit"}
|
||||||
|
size="medium"
|
||||||
|
onClick={() => {
|
||||||
|
Notice.success(t("After restart to take effect"), 1000);
|
||||||
|
onChangeVerge({ enable_random_port: !enable_random_port });
|
||||||
|
patchVerge({ enable_random_port: !enable_random_port });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Shuffle
|
||||||
|
fontSize="inherit"
|
||||||
|
style={{ cursor: "pointer", opacity: 0.75 }}
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
>
|
||||||
<TextField
|
<TextField
|
||||||
|
disabled={enable_random_port}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
size="small"
|
size="small"
|
||||||
value={mixedPort ?? 0}
|
value={verge_mixed_port ?? 7890}
|
||||||
sx={{ width: 100, input: { py: "7.5px", cursor: "pointer" } }}
|
sx={{ width: 100, input: { py: "7.5px", cursor: "pointer" } }}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
portRef.current?.open();
|
portRef.current?.open();
|
||||||
|
@ -67,6 +67,8 @@
|
|||||||
"IPv6": "IPv6",
|
"IPv6": "IPv6",
|
||||||
"Log Level": "Log Level",
|
"Log Level": "Log Level",
|
||||||
"Mixed Port": "Mixed Port",
|
"Mixed Port": "Mixed Port",
|
||||||
|
"Random Port": "Random Port",
|
||||||
|
"After restart to take effect": "After restart to take effect",
|
||||||
"External": "External",
|
"External": "External",
|
||||||
"Clash Core": "Clash Core",
|
"Clash Core": "Clash Core",
|
||||||
"Grant": "Grant",
|
"Grant": "Grant",
|
||||||
|
@ -64,6 +64,8 @@
|
|||||||
"IPv6": "IPv6",
|
"IPv6": "IPv6",
|
||||||
"Log Level": "Уровень логов",
|
"Log Level": "Уровень логов",
|
||||||
"Mixed Port": "Смешанный порт",
|
"Mixed Port": "Смешанный порт",
|
||||||
|
"Random Port": "Случайный порт",
|
||||||
|
"After restart to take effect": "Чтобы изменения вступили в силу, необходимо перезапустить приложение",
|
||||||
"Clash Core": "Ядро Clash",
|
"Clash Core": "Ядро Clash",
|
||||||
"Tun Mode": "Режим туннеля",
|
"Tun Mode": "Режим туннеля",
|
||||||
"Service Mode": "Режим сервиса",
|
"Service Mode": "Режим сервиса",
|
||||||
|
@ -67,6 +67,8 @@
|
|||||||
"IPv6": "IPv6",
|
"IPv6": "IPv6",
|
||||||
"Log Level": "日志等级",
|
"Log Level": "日志等级",
|
||||||
"Mixed Port": "端口设置",
|
"Mixed Port": "端口设置",
|
||||||
|
"Random Port": "随机端口",
|
||||||
|
"After restart to take effect": "重启后生效",
|
||||||
"External": "外部控制",
|
"External": "外部控制",
|
||||||
"Clash Core": "Clash 内核",
|
"Clash Core": "Clash 内核",
|
||||||
"Grant": "授权",
|
"Grant": "授权",
|
||||||
|
2
src/services/types.d.ts
vendored
2
src/services/types.d.ts
vendored
@ -166,6 +166,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;
|
||||||
|
enable_random_port?: boolean;
|
||||||
|
verge_mixed_port?: number;
|
||||||
enable_proxy_guard?: boolean;
|
enable_proxy_guard?: boolean;
|
||||||
proxy_guard_duration?: number;
|
proxy_guard_duration?: number;
|
||||||
system_proxy_bypass?: string;
|
system_proxy_bypass?: string;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user