feat: support random mixed port

This commit is contained in:
WhizPanda 2023-12-01 12:56:18 +08:00
parent 2d8da45bda
commit e9f14de05d
11 changed files with 135 additions and 23 deletions

View File

@ -194,7 +194,10 @@ impl PrfItem {
// 使用软件自己的代理
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}");

View File

@ -93,6 +93,12 @@ pub struct IVerge {
/// window size and position
#[serde(skip_serializing_if = "Option::is_none")]
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)]
@ -139,6 +145,8 @@ impl IVerge {
enable_auto_launch: Some(false),
enable_silent_start: Some(false),
enable_system_proxy: Some(false),
enable_random_port: Some(false),
verge_mixed_port: Some(7890),
enable_proxy_guard: Some(false),
proxy_guard_duration: Some(30),
auto_close_connection: Some(true),
@ -177,6 +185,8 @@ impl IVerge {
patch!(enable_service_mode);
patch!(enable_auto_launch);
patch!(enable_silent_start);
patch!(enable_random_port);
patch!(verge_mixed_port);
patch!(enable_system_proxy);
patch!(enable_proxy_guard);
patch!(system_proxy_bypass);

View File

@ -27,7 +27,8 @@ static DEFAULT_BYPASS: &str = "localhost;127.*;192.168.*;10.*;172.16.*;<local>";
#[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";
#[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 {
pub fn global() -> &'static Sysopt {
@ -43,7 +44,10 @@ impl Sysopt {
/// init the sysproxy
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 verge = Config::verge();
@ -284,7 +288,12 @@ impl Sysopt {
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 {
enable: true,

View File

@ -162,8 +162,13 @@ pub async fn patch_clash(patch: Mapping) -> Result<()> {
match {
let mixed_port = patch.get("mixed-port");
if mixed_port.is_some() {
let changed = mixed_port != Config::clash().data().0.get("mixed-port");
let enable_random_port = Config::verge().latest().enable_random_port.unwrap_or(false);
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 let Some(port) = mixed_port.clone().unwrap().as_u64() {
@ -333,11 +338,12 @@ async fn update_core_config() -> Result<()> {
/// copy env variable
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 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 ps: String = format!("$env:HTTP_PROXY=\"{http_proxy}\"; $env:HTTPS_PROXY=\"{http_proxy}\"");

View File

@ -1,8 +1,28 @@
use crate::config::IVerge;
use crate::{config::Config, core::*, utils::init, utils::server};
use crate::{log_err, trace_err};
use anyhow::Result;
use serde_yaml::Mapping;
use std::net::TcpListener;
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
pub fn resolve_setup(app: &mut App) {
#[cfg(target_os = "macos")]
@ -12,6 +32,33 @@ pub fn resolve_setup(app: &mut App) {
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_err!(Config::init_config());

View File

@ -4,30 +4,35 @@ import { useLockFn } from "ahooks";
import { List, ListItem, ListItemText, TextField } from "@mui/material";
import { useClashInfo } from "@/hooks/use-clash";
import { BaseDialog, DialogRef, Notice } from "@/components/base";
import { useVerge } from "@/hooks/use-verge";
export const ClashPortViewer = forwardRef<DialogRef>((props, ref) => {
const { t } = useTranslation();
const { clashInfo, patchInfo } = useClashInfo();
const { verge, patchVerge } = useVerge();
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, () => ({
open: () => {
if (clashInfo?.port) setPort(clashInfo?.port);
if (verge?.verge_mixed_port) setPort(verge?.verge_mixed_port);
setOpen(true);
},
close: () => setOpen(false),
}));
const onSave = useLockFn(async () => {
if (port === clashInfo?.port) {
if (port === verge?.verge_mixed_port) {
setOpen(false);
return;
}
try {
await patchInfo({ "mixed-port": port });
await patchVerge({ verge_mixed_port: port });
setOpen(false);
Notice.success("Change Clash port successfully!", 1000);
} catch (err: any) {

View File

@ -7,9 +7,10 @@ import {
MenuItem,
Typography,
IconButton,
Tooltip,
} from "@mui/material";
import { ArrowForward, Settings } from "@mui/icons-material";
import { DialogRef } from "@/components/base";
import { ArrowForward, Settings, Shuffle } from "@mui/icons-material";
import { DialogRef, Notice } from "@/components/base";
import { useClash } from "@/hooks/use-clash";
import { GuardState } from "./mods/guard-state";
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 { invoke_uwp_tool } from "@/services/cmds";
import getSystem from "@/utils/get-system";
import { useVerge } from "@/hooks/use-verge";
const isWIN = getSystem() === "windows";
@ -32,12 +34,11 @@ const SettingClash = ({ onError }: Props) => {
const { clash, version, mutateClash, patchClash } = useClash();
const {
ipv6,
"allow-lan": allowLan,
"log-level": logLevel,
"mixed-port": mixedPort,
} = clash ?? {};
const { verge, mutateVerge, patchVerge } = useVerge();
const { ipv6, "allow-lan": allowLan, "log-level": logLevel } = clash ?? {};
const { enable_random_port = false, verge_mixed_port } = verge ?? {};
const webRef = useRef<DialogRef>(null);
const fieldRef = useRef<DialogRef>(null);
@ -49,7 +50,9 @@ const SettingClash = ({ onError }: Props) => {
const onChangeData = (patch: Partial<IConfigData>) => {
mutateClash((old) => ({ ...(old! || {}), ...patch }), false);
};
const onChangeVerge = (patch: Partial<IVergeConfig>) => {
mutateVerge({ ...verge, ...patch }, false);
};
return (
<SettingList title={t("Clash Setting")}>
<WebUIViewer ref={webRef} />
@ -103,11 +106,32 @@ const SettingClash = ({ onError }: Props) => {
</GuardState>
</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
disabled={enable_random_port}
autoComplete="off"
size="small"
value={mixedPort ?? 0}
value={verge_mixed_port ?? 7890}
sx={{ width: 100, input: { py: "7.5px", cursor: "pointer" } }}
onClick={(e) => {
portRef.current?.open();

View File

@ -67,6 +67,8 @@
"IPv6": "IPv6",
"Log Level": "Log Level",
"Mixed Port": "Mixed Port",
"Random Port": "Random Port",
"After restart to take effect": "After restart to take effect",
"External": "External",
"Clash Core": "Clash Core",
"Grant": "Grant",

View File

@ -64,6 +64,8 @@
"IPv6": "IPv6",
"Log Level": "Уровень логов",
"Mixed Port": "Смешанный порт",
"Random Port": "Случайный порт",
"After restart to take effect": "Чтобы изменения вступили в силу, необходимо перезапустить приложение",
"Clash Core": "Ядро Clash",
"Tun Mode": "Режим туннеля",
"Service Mode": "Режим сервиса",

View File

@ -67,6 +67,8 @@
"IPv6": "IPv6",
"Log Level": "日志等级",
"Mixed Port": "端口设置",
"Random Port": "随机端口",
"After restart to take effect": "重启后生效",
"External": "外部控制",
"Clash Core": "Clash 内核",
"Grant": "授权",

View File

@ -166,6 +166,8 @@ interface IVergeConfig {
enable_service_mode?: boolean;
enable_silent_start?: boolean;
enable_system_proxy?: boolean;
enable_random_port?: boolean;
verge_mixed_port?: number;
enable_proxy_guard?: boolean;
proxy_guard_duration?: number;
system_proxy_bypass?: string;