Add Func 链式代理 (#4624)

* 添加链式代理gui和语言支持
在Iruntime中添跟新链式代理配置方法
同时添加了cmd

* 修复读取运行时代理链配置文件bug

* t

* 完成链式代理配置构造

* 修复获取链式代理运行时配置的bug

* 完整的链式代理功能
This commit is contained in:
Junkai W.
2025-09-15 07:44:54 +08:00
committed by GitHub
parent a1f468202f
commit f2073a2f83
25 changed files with 1246 additions and 316 deletions

View File

@@ -1,9 +1,14 @@
import useSWR from "swr";
import { useEffect } from "react";
import { useEffect, useState } from "react";
import { useLockFn } from "ahooks";
import { useTranslation } from "react-i18next";
import { Box, Button, ButtonGroup } from "@mui/material";
import { closeAllConnections, getClashConfig } from "@/services/cmds";
import {
closeAllConnections,
getClashConfig,
getRuntimeProxyChainConfig,
updateProxyChainConfigInRuntime,
} from "@/services/cmds";
import { patchClashMode } from "@/services/cmds";
import { useVerge } from "@/hooks/use-verge";
import { BasePage } from "@/components/base";
@@ -13,6 +18,18 @@ import { ProviderButton } from "@/components/proxy/provider-button";
const ProxyPage = () => {
const { t } = useTranslation();
// 从 localStorage 恢复链式代理按钮状态
const [isChainMode, setIsChainMode] = useState(() => {
try {
const saved = localStorage.getItem("proxy-chain-mode-enabled");
return saved === "true";
} catch {
return false;
}
});
const [chainConfigData, setChainConfigData] = useState<string | null>(null);
const { data: clashConfig, mutate: mutateClash } = useSWR(
"getClashConfig",
getClashConfig,
@@ -39,6 +56,45 @@ const ProxyPage = () => {
mutateClash();
});
const onToggleChainMode = useLockFn(async () => {
const newChainMode = !isChainMode;
if (!newChainMode) {
// 退出链式代理模式时,清除链式代理配置
try {
console.log("Exiting chain mode, clearing chain configuration");
await updateProxyChainConfigInRuntime(null);
console.log("Chain configuration cleared successfully");
} catch (error) {
console.error("Failed to clear chain configuration:", error);
}
}
setIsChainMode(newChainMode);
// 保存链式代理按钮状态到 localStorage
localStorage.setItem("proxy-chain-mode-enabled", newChainMode.toString());
});
// 当开启链式代理模式时,获取配置数据
useEffect(() => {
if (isChainMode) {
const fetchChainConfig = async () => {
try {
const configData = await getRuntimeProxyChainConfig();
setChainConfigData(configData || "");
} catch (error) {
console.error("Failed to get runtime proxy chain config:", error);
setChainConfigData("");
}
};
fetchChainConfig();
} else {
setChainConfigData(null);
}
}, [isChainMode]);
useEffect(() => {
if (curMode && !modeList.includes(curMode)) {
onChangeMode("rule");
@@ -49,7 +105,7 @@ const ProxyPage = () => {
<BasePage
full
contentStyle={{ height: "101.5%" }}
title={t("Proxy Groups")}
title={isChainMode ? t("Node Pool") : t("Proxy Groups")}
header={
<Box display="flex" alignItems="center" gap={1}>
<ProviderButton />
@@ -66,10 +122,23 @@ const ProxyPage = () => {
</Button>
))}
</ButtonGroup>
<Button
size="small"
variant={isChainMode ? "contained" : "outlined"}
onClick={onToggleChainMode}
sx={{ ml: 1 }}
>
{t("Chain Proxy")}
</Button>
</Box>
}
>
<ProxyGroups mode={curMode!} />
<ProxyGroups
mode={curMode!}
isChainMode={isChainMode}
chainConfigData={chainConfigData}
/>
</BasePage>
);
};