diff --git a/src-tauri/src/cmd/runtime.rs b/src-tauri/src/cmd/runtime.rs index 2b7e3e24..8e335b57 100644 --- a/src-tauri/src/cmd/runtime.rs +++ b/src-tauri/src/cmd/runtime.rs @@ -37,9 +37,8 @@ pub async fn get_runtime_logs() -> CmdResult CmdResult { +pub async fn get_runtime_proxy_chain_config(proxy_chain_exit_node: String) -> CmdResult { let runtime = Config::runtime().await; let runtime = runtime.latest_ref(); @@ -50,51 +49,36 @@ pub async fn get_runtime_proxy_chain_config() -> CmdResult { .ok_or(anyhow::anyhow!("failed to parse config to yaml file")) )?; - if let ( - Some(serde_yaml_ng::Value::Sequence(proxies)), - Some(serde_yaml_ng::Value::Sequence(proxy_groups)), - ) = (config.get("proxies"), config.get("proxy-groups")) - { - let mut proxy_name = None; + if let Some(serde_yaml_ng::Value::Sequence(proxies)) = config.get("proxies") { + let mut proxy_name = Some(Some(proxy_chain_exit_node.as_str())); let mut proxies_chain = Vec::new(); - let proxy_chain_groups = proxy_groups - .iter() - .filter_map( - |proxy_group| match proxy_group.get("name").and_then(|n| n.as_str()) { - Some("proxy_chain") => { - if let Some(serde_yaml_ng::Value::Sequence(ps)) = proxy_group.get("proxies") - && let Some(x) = ps.first() - { - proxy_name = Some(x); //插入出口节点名字 - } - Some(proxy_group.to_owned()) - } - _ => None, - }, - ) - .collect::>(); - while let Some(proxy) = proxies.iter().find(|proxy| { if let serde_yaml_ng::Value::Mapping(proxy_map) = proxy { - proxy_map.get("name") == proxy_name && proxy_map.get("dialer-proxy").is_some() + proxy_map.get("name").map(|x| x.as_str()) == proxy_name + && proxy_map.get("dialer-proxy").is_some() } else { false } }) { proxies_chain.push(proxy.to_owned()); - proxy_name = proxy.get("dialer-proxy"); + proxy_name = proxy.get("dialer-proxy").map(|x| x.as_str()); } - if let Some(entry_proxy) = proxies.iter().find(|proxy| proxy.get("name") == proxy_name) { + if let Some(entry_proxy) = proxies + .iter() + .find(|proxy| proxy.get("name").map(|x| x.as_str()) == proxy_name) + && !proxies_chain.is_empty() + { + // 添加第一个节点 proxies_chain.push(entry_proxy.to_owned()); } proxies_chain.reverse(); let mut config: HashMap> = HashMap::new(); + config.insert("proxies".to_string(), proxies_chain); - config.insert("proxy-groups".to_string(), proxy_chain_groups); wrap_err!(serde_yaml_ng::to_string(&config).context("YAML generation failed")) } else { diff --git a/src-tauri/src/config/runtime.rs b/src-tauri/src/config/runtime.rs index 3c4cd6f8..7113402b 100644 --- a/src-tauri/src/config/runtime.rs +++ b/src-tauri/src/config/runtime.rs @@ -92,22 +92,6 @@ impl IRuntime { /// 传入none 为删除 pub fn update_proxy_chain_config(&mut self, proxy_chain_config: Option) { if let Some(config) = self.config.as_mut() { - // 获取 默认第一的代理组的名字 - let proxy_group_name = - if let Some(Value::Sequence(proxy_groups)) = config.get("proxy-groups") { - if let Some(Value::Mapping(proxy_group)) = proxy_groups.first() { - if let Some(Value::String(proxy_group_name)) = proxy_group.get("name") { - proxy_group_name.to_string() - } else { - "".to_string() - } - } else { - "".to_string() - } - } else { - "".to_string() - }; - if let Some(Value::Sequence(proxies)) = config.get_mut("proxies") { proxies.iter_mut().for_each(|proxy| { if let Some(proxy) = proxy.as_mapping_mut() @@ -118,66 +102,19 @@ impl IRuntime { }); } - // 清除proxy_chain代理组 - if let Some(Value::Sequence(proxy_groups)) = config.get_mut("proxy-groups") { - proxy_groups.retain(|proxy_group| { - !matches!(proxy_group.get("name").and_then(|n| n.as_str()), Some(name) if name== "proxy_chain") - }); - } - - // 清除rules - if let Some(Value::Sequence(rules)) = config.get_mut("rules") { - rules.retain(|rule| rule.as_str() != Some("MATCH,proxy_chain")); - rules.push(Value::String(format!("MATCH,{}", proxy_group_name))); - } - - // some 则写入新配置 - // 给proxy添加dialer-proxy字段 - // 第一个proxy不添加dialer-proxy - // 然后第二个开始,dialer-proxy为上一个元素的name - if let Some(Value::Sequence(dialer_proxies)) = proxy_chain_config { - let mut proxy_chain_group = Mapping::new(); - - if let Some(Value::Sequence(proxies)) = config.get_mut("proxies") { - for (i, dialer_proxy) in dialer_proxies.iter().enumerate() { - if let Some(Value::Mapping(proxy)) = proxies - .iter_mut() - .find(|proxy| proxy.get("name") == Some(dialer_proxy)) - { - if i != 0 - && let Some(dialer_proxy) = dialer_proxies.get(i - 1) - { - proxy.insert("dialer-proxy".into(), dialer_proxy.to_owned()); - } - if i == dialer_proxies.len() - 1 { - // 添加proxy-groups - proxy_chain_group - .insert("name".into(), Value::String("proxy_chain".into())); - proxy_chain_group - .insert("type".into(), Value::String("select".into())); - proxy_chain_group.insert( - "proxies".into(), - Value::Sequence(vec![dialer_proxy.to_owned()]), - ); - } - } + if let Some(Value::Sequence(dialer_proxies)) = proxy_chain_config + && let Some(Value::Sequence(proxies)) = config.get_mut("proxies") + { + for (i, dialer_proxy) in dialer_proxies.iter().enumerate() { + if let Some(Value::Mapping(proxy)) = proxies + .iter_mut() + .find(|proxy| proxy.get("name") == Some(dialer_proxy)) + && i != 0 + && let Some(dialer_proxy) = dialer_proxies.get(i - 1) + { + proxy.insert("dialer-proxy".into(), dialer_proxy.to_owned()); } } - - if let Some(Value::Sequence(proxy_groups)) = config.get_mut("proxy-groups") { - proxy_groups.push(Value::Mapping(proxy_chain_group)); - } - - // 添加rules - if let Some(Value::Sequence(rules)) = config.get_mut("rules") - && let Ok(rule) = serde_yaml_ng::to_value("MATCH,proxy_chain") - { - rules.retain(|rule| { - rule.as_str() != Some(&format!("MATCH,{}", proxy_group_name)) - }); - rules.push(rule); - // *rules = vec![rule]; - } } } } diff --git a/src-tauri/src/core/tray/mod.rs b/src-tauri/src/core/tray/mod.rs index 78494bbd..059accb7 100644 --- a/src-tauri/src/core/tray/mod.rs +++ b/src-tauri/src/core/tray/mod.rs @@ -1034,9 +1034,9 @@ fn on_menu_event(_: &AppHandle, event: MenuEvent) { return; } if !is_in_lightweight_mode() { - lightweight::entry_lightweight_mode().await; + lightweight::entry_lightweight_mode().await; // Await async function } else { - lightweight::exit_lightweight_mode().await; + lightweight::exit_lightweight_mode().await; // Await async function } } "quit" => { diff --git a/src-tauri/src/ipc/general.rs b/src-tauri/src/ipc/general.rs index 1386ac1e..9e90ae90 100644 --- a/src-tauri/src/ipc/general.rs +++ b/src-tauri/src/ipc/general.rs @@ -276,9 +276,15 @@ impl IpcManager { let payload = serde_json::json!({ "name": proxy }); + + // println!("group: {}, proxy: {}", group, proxy); match self.send_request("PUT", &url, Some(&payload)).await { - Ok(_) => Ok(()), + Ok(_) => { + // println!("updateProxy response: {:?}", response); + Ok(()) + } Err(e) => { + // println!("updateProxy encountered error: {}", e); logging!( error, crate::utils::logging::Type::Ipc, diff --git a/src/components/proxy/proxy-chain.tsx b/src/components/proxy/proxy-chain.tsx index 2b0a0d8c..57e87243 100644 --- a/src/components/proxy/proxy-chain.tsx +++ b/src/components/proxy/proxy-chain.tsx @@ -63,6 +63,8 @@ interface ProxyChainProps { onUpdateChain: (chain: ProxyChainItem[]) => void; chainConfigData?: string | null; onMarkUnsavedChanges?: () => void; + mode?: string; + selectedGroup?: string | null; } interface SortableItemProps { @@ -189,6 +191,8 @@ export const ProxyChain = ({ onUpdateChain, chainConfigData, onMarkUnsavedChanges, + mode, + selectedGroup, }: ProxyChainProps) => { const theme = useTheme(); const { t } = useTranslation(); @@ -215,25 +219,46 @@ export const ProxyChain = ({ return; } - // 查找 proxy_chain 代理组 - const proxyChainGroup = currentProxies.groups.find( - (group) => group.name === "proxy_chain", - ); - if (!proxyChainGroup || !proxyChainGroup.now) { - setIsConnected(false); - return; - } - // 获取用户配置的最后一个节点 const lastNode = proxyChain[proxyChain.length - 1]; - // 检查当前选中的代理是否是配置的最后一个节点 - if (proxyChainGroup.now === lastNode.name) { - setIsConnected(true); + // 根据模式确定要检查的代理组和当前选中的代理 + if (mode === "global") { + // 全局模式:检查 global 对象 + if (!currentProxies.global || !currentProxies.global.now) { + setIsConnected(false); + return; + } + + // 检查当前选中的代理是否是配置的最后一个节点 + if (currentProxies.global.now === lastNode.name) { + setIsConnected(true); + } else { + setIsConnected(false); + } } else { - setIsConnected(false); + // 规则模式:检查指定的代理组 + if (!selectedGroup) { + setIsConnected(false); + return; + } + + const proxyChainGroup = currentProxies.groups.find( + (group) => group.name === selectedGroup, + ); + if (!proxyChainGroup || !proxyChainGroup.now) { + setIsConnected(false); + return; + } + + // 检查当前选中的代理是否是配置的最后一个节点 + if (proxyChainGroup.now === lastNode.name) { + setIsConnected(true); + } else { + setIsConnected(false); + } } - }, [currentProxies, proxyChain]); + }, [currentProxies, proxyChain, mode, selectedGroup]); // 监听链的变化,但排除从配置加载的情况 const chainLengthRef = useRef(proxyChain.length); @@ -334,14 +359,23 @@ export const ProxyChain = ({ // 第二步:连接到代理链的最后一个节点 const lastNode = proxyChain[proxyChain.length - 1]; console.log(`Connecting to proxy chain, last node: ${lastNode.name}`); - await updateProxyAndSync("proxy_chain", lastNode.name); + + // 根据模式确定使用的代理组名称 + if (mode !== "global" && !selectedGroup) { + throw new Error("规则模式下必须选择代理组"); + } + + const targetGroup = mode === "global" ? "GLOBAL" : selectedGroup; + + await updateProxyAndSync(targetGroup || "GLOBAL", lastNode.name); + localStorage.setItem("proxy-chain-group", targetGroup || "GLOBAL"); + localStorage.setItem("proxy-chain-exit-node", lastNode.name); // 刷新代理信息以更新连接状态 mutateProxies(); // 清除未保存标记 setHasUnsavedChanges(false); - console.log("Successfully connected to proxy chain"); } catch (error) { console.error("Failed to connect to proxy chain:", error); @@ -349,7 +383,7 @@ export const ProxyChain = ({ } finally { setIsConnecting(false); } - }, [proxyChain, isConnected, t, mutateProxies]); + }, [proxyChain, isConnected, t, mutateProxies, mode, selectedGroup]); const proxyChainRef = useRef(proxyChain); const onUpdateChainRef = useRef(onUpdateChain); @@ -504,7 +538,11 @@ export const ProxyChain = ({ variant="contained" startIcon={isConnected ? : } onClick={handleConnect} - disabled={isConnecting || proxyChain.length < 2} + disabled={ + isConnecting || + proxyChain.length < 2 || + (mode !== "global" && !selectedGroup) + } color={isConnected ? "error" : "success"} sx={{ minWidth: 90, diff --git a/src/components/proxy/proxy-groups.tsx b/src/components/proxy/proxy-groups.tsx index 21c62e22..889e66b0 100644 --- a/src/components/proxy/proxy-groups.tsx +++ b/src/components/proxy/proxy-groups.tsx @@ -1,12 +1,31 @@ -import { Box, Snackbar, Alert } from "@mui/material"; +import { + Box, + Snackbar, + Alert, + Chip, + Stack, + Typography, + IconButton, + Collapse, + Menu, + MenuItem, + Divider, +} from "@mui/material"; +import { ArchiveOutlined, ExpandMoreRounded } from "@mui/icons-material"; import { useLockFn } from "ahooks"; import { useRef, useState, useEffect, useCallback } from "react"; +import useSWR from "swr"; import { useTranslation } from "react-i18next"; import { Virtuoso, type VirtuosoHandle } from "react-virtuoso"; import { useProxySelection } from "@/hooks/use-proxy-selection"; import { useVerge } from "@/hooks/use-verge"; -import { providerHealthCheck, getGroupProxyDelays } from "@/services/cmds"; +import { useAppData } from "@/providers/app-data-provider"; +import { + providerHealthCheck, + getGroupProxyDelays, + updateProxyChainConfigInRuntime, +} from "@/services/cmds"; import delayManager from "@/services/delay"; import { BaseEmpty } from "../base"; @@ -33,18 +52,36 @@ export const ProxyGroups = (props: Props) => { const { t } = useTranslation(); const { mode, isChainMode = false, chainConfigData } = props; const [proxyChain, setProxyChain] = useState([]); + const [selectedGroup, setSelectedGroup] = useState(null); + const [ruleMenuAnchor, setRuleMenuAnchor] = useState( + null, + ); const [duplicateWarning, setDuplicateWarning] = useState<{ open: boolean; message: string; }>({ open: false, message: "" }); + const { verge } = useVerge(); + const { proxies: proxiesData } = useAppData(); + + // 当链式代理模式且规则模式下,如果没有选择代理组,默认选择第一个 + useEffect(() => { + if ( + isChainMode && + mode === "rule" && + !selectedGroup && + proxiesData?.groups?.length > 0 + ) { + setSelectedGroup(proxiesData.groups[0].name); + } + }, [isChainMode, mode, selectedGroup, proxiesData]); + const { renderList, onProxies, onHeadState } = useRenderList( mode, isChainMode, + selectedGroup, ); - const { verge } = useVerge(); - // 统代理选择 const { handleProxyGroupChange } = useProxySelection({ onSuccess: () => { @@ -142,6 +179,43 @@ export const ProxyGroups = (props: Props) => { setDuplicateWarning({ open: false, message: "" }); }, []); + // 获取当前选中的代理组信息 + const getCurrentGroup = useCallback(() => { + if (!selectedGroup || !proxiesData?.groups) return null; + return proxiesData.groups.find( + (group: any) => group.name === selectedGroup, + ); + }, [selectedGroup, proxiesData]); + + // 获取可用的代理组列表 + const getAvailableGroups = useCallback(() => { + return proxiesData?.groups || []; + }, [proxiesData]); + + // 处理代理组选择菜单 + const handleGroupMenuOpen = (event: React.MouseEvent) => { + setRuleMenuAnchor(event.currentTarget); + }; + + const handleGroupMenuClose = () => { + setRuleMenuAnchor(null); + }; + + const handleGroupSelect = (groupName: string) => { + setSelectedGroup(groupName); + handleGroupMenuClose(); + + // 在链式代理模式的规则模式下,切换代理组时清空链式代理配置 + if (isChainMode && mode === "rule") { + updateProxyChainConfigInRuntime(null); + // 同时清空右侧链式代理配置 + setProxyChain([]); + } + }; + + const currentGroup = getCurrentGroup(); + const availableGroups = getAvailableGroups(); + const handleChangeProxy = useCallback( (group: IProxyGroupItem, proxy: IProxyItem) => { if (isChainMode) { @@ -257,13 +331,89 @@ export const ProxyGroups = (props: Props) => { } if (isChainMode) { + // 获取所有代理组 + const proxyGroups = proxiesData?.groups || []; + return ( <> + {/* 代理规则标题和代理组按钮栏 */} + {mode === "rule" && proxyGroups.length > 0 && ( + + {/* 代理规则标题 */} + + + + {t("Proxy Rules")} + + {currentGroup && ( + + + + )} + + + {availableGroups.length > 0 && ( + + + {t("Select Rules")} + + + + )} + + + )} + 0 + ? "calc(100% - 80px)" // 只有标题的高度 + : "calc(100% - 14px)", + }} totalCount={renderList.length} increaseViewportBy={{ top: 200, bottom: 200 }} overscan={150} @@ -297,6 +447,8 @@ export const ProxyGroups = (props: Props) => { proxyChain={proxyChain} onUpdateChain={setProxyChain} chainConfigData={chainConfigData} + mode={mode} + selectedGroup={selectedGroup} /> @@ -315,6 +467,53 @@ export const ProxyGroups = (props: Props) => { {duplicateWarning.message} + + {/* 代理组选择菜单 */} + + {availableGroups.map((group: any, index: number) => ( + handleGroupSelect(group.name)} + selected={selectedGroup === group.name} + sx={{ + fontSize: "14px", + py: 1, + }} + > + + + {group.name} + + + {group.type} · {group.all.length} 节点 + + + + ))} + {availableGroups.length === 0 && ( + + + 暂无可用代理组 + + + )} + ); } diff --git a/src/components/proxy/use-render-list.ts b/src/components/proxy/use-render-list.ts index 0fb63fad..e5c17424 100644 --- a/src/components/proxy/use-render-list.ts +++ b/src/components/proxy/use-render-list.ts @@ -93,7 +93,11 @@ const groupProxies = (list: T[], size: number): T[][] => { }, [] as T[][]); }; -export const useRenderList = (mode: string, isChainMode?: boolean) => { +export const useRenderList = ( + mode: string, + isChainMode?: boolean, + selectedGroup?: string | null, +) => { // 使用全局数据提供者 const { proxies: proxiesData, refreshProxy } = useAppData(); const { verge } = useVerge(); @@ -180,7 +184,129 @@ export const useRenderList = (mode: string, isChainMode?: boolean) => { const renderList: IRenderItem[] = useMemo(() => { if (!proxiesData) return []; - // 链式代理模式下,从运行时配置读取所有 proxies + // 链式代理模式下,显示代理组和其节点 + if (isChainMode && runtimeConfig && mode === "rule") { + // 使用正常的规则模式代理组 + const allGroups = proxiesData.groups.length + ? proxiesData.groups + : [proxiesData.global!]; + + // 如果选择了特定代理组,只显示该组的节点 + if (selectedGroup) { + const targetGroup = allGroups.find( + (g: any) => g.name === selectedGroup, + ); + if (targetGroup) { + const proxies = filterSort(targetGroup.all, targetGroup.name, "", 0); + + if (col > 1) { + return groupProxies(proxies, col).map((proxyCol, colIndex) => ({ + type: 4, + key: `chain-col-${selectedGroup}-${colIndex}`, + group: targetGroup, + headState: DEFAULT_STATE, + col, + proxyCol, + provider: proxyCol[0]?.provider, + })); + } else { + return proxies.map((proxy) => ({ + type: 2, + key: `chain-${selectedGroup}-${proxy!.name}`, + group: targetGroup, + proxy, + headState: DEFAULT_STATE, + provider: proxy.provider, + })); + } + } + return []; + } + + // 如果没有选择特定组,显示第一个组的节点(如果有组的话) + if (allGroups.length > 0) { + const firstGroup = allGroups[0]; + const proxies = filterSort(firstGroup.all, firstGroup.name, "", 0); + + if (col > 1) { + return groupProxies(proxies, col).map((proxyCol, colIndex) => ({ + type: 4, + key: `chain-col-first-${colIndex}`, + group: firstGroup, + headState: DEFAULT_STATE, + col, + proxyCol, + provider: proxyCol[0]?.provider, + })); + } else { + return proxies.map((proxy) => ({ + type: 2, + key: `chain-first-${proxy!.name}`, + group: firstGroup, + proxy, + headState: DEFAULT_STATE, + provider: proxy.provider, + })); + } + } + + // 如果没有组,显示所有节点 + const allProxies: IProxyItem[] = allGroups.flatMap( + (group: any) => group.all, + ); + + // 为每个节点获取延迟信息 + const proxiesWithDelay = allProxies.map((proxy) => { + const delay = delayManager.getDelay(proxy.name, "chain-mode"); + return { + ...proxy, + // 如果delayManager有延迟数据,更新history + history: + delay >= 0 + ? [{ time: new Date().toISOString(), delay }] + : proxy.history || [], + }; + }); + + // 创建一个虚拟的组来容纳所有节点 + const virtualGroup: ProxyGroup = { + name: "All Proxies", + type: "Selector", + udp: false, + xudp: false, + tfo: false, + mptcp: false, + smux: false, + history: [], + now: "", + all: proxiesWithDelay, + }; + + if (col > 1) { + return groupProxies(proxiesWithDelay, col).map( + (proxyCol, colIndex) => ({ + type: 4, + key: `chain-col-all-${colIndex}`, + group: virtualGroup, + headState: DEFAULT_STATE, + col, + proxyCol, + provider: proxyCol[0]?.provider, + }), + ); + } else { + return proxiesWithDelay.map((proxy) => ({ + type: 2, + key: `chain-all-${proxy.name}`, + group: virtualGroup, + proxy, + headState: DEFAULT_STATE, + provider: proxy.provider, + })); + } + } + + // 链式代理模式下的其他模式(如global)仍显示所有节点 if (isChainMode && runtimeConfig) { // 从运行时配置直接获取 proxies 列表 (需要类型断言) const allProxies: IProxyItem[] = Object.values( @@ -311,7 +437,15 @@ export const useRenderList = (mode: string, isChainMode?: boolean) => { if (!useRule) return retList.slice(1); return retList.filter((item: IRenderItem) => !item.group.hidden); - }, [headStates, proxiesData, mode, col, isChainMode, runtimeConfig]); + }, [ + headStates, + proxiesData, + mode, + col, + isChainMode, + runtimeConfig, + selectedGroup, + ]); return { renderList, diff --git a/src/locales/en.json b/src/locales/en.json index d614c85c..6a3897ff 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -26,7 +26,7 @@ "Label-Settings": "Settings", "Proxies": "Proxies", "Proxy Groups": "Proxy Groups", - "Node Pool": "Node Pool", + "Proxy Chain Mode": "Proxy Chain Mode", "Connect": "Connect", "Connecting...": "Connecting...", "Disconnect": "Disconnect", @@ -40,6 +40,8 @@ "direct": "direct", "Chain Proxy": "🔗 Chain Proxy", "Chain Proxy Config": "Chain Proxy Config", + "Proxy Rules": "Proxy Rules", + "Select Rules": "Select Rules", "Click nodes in order to add to proxy chain": "Click nodes in order to add to proxy chain", "No proxy chain configured": "No proxy chain configured", "Proxy Order": "Proxy Order", diff --git a/src/locales/zh.json b/src/locales/zh.json index af70b0d8..9a3d1748 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -26,7 +26,7 @@ "Label-Settings": "设 置", "Proxies": "代理", "Proxy Groups": "代理组", - "Node Pool": "节点池", + "Proxy Chain Mode": "链式代理模式", "Connect": "连接", "Connecting...": "连接中...", "Disconnect": "断开", @@ -40,6 +40,8 @@ "direct": "直连", "Chain Proxy": "🔗 链式代理", "Chain Proxy Config": "代理链配置", + "Proxy Rules": "代理规则", + "Select Rules": "选择规则", "Click nodes in order to add to proxy chain": "顺序点击节点添加到代理链中", "No proxy chain configured": "暂无代理链配置", "Proxy Order": "代理顺序", diff --git a/src/locales/zhtw.json b/src/locales/zhtw.json index 67d8e181..6521d865 100644 --- a/src/locales/zhtw.json +++ b/src/locales/zhtw.json @@ -25,7 +25,7 @@ "Label-Unlock": "測 試", "Label-Settings": "設 置", "Proxy Groups": "代理組", - "Node Pool": "節點池", + "Proxy Chain Mode": "鏈式代理模式", "Connect": "連接", "Connecting...": "連接中...", "Disconnect": "斷開", diff --git a/src/pages/proxies.tsx b/src/pages/proxies.tsx index b115eb53..60663ce5 100644 --- a/src/pages/proxies.tsx +++ b/src/pages/proxies.tsx @@ -82,7 +82,15 @@ const ProxyPage = () => { if (isChainMode) { const fetchChainConfig = async () => { try { - const configData = await getRuntimeProxyChainConfig(); + const exitNode = localStorage.getItem("proxy-chain-exit-node"); + + if (!exitNode) { + console.error("No proxy chain exit node found in localStorage"); + setChainConfigData(""); + return; + } + + const configData = await getRuntimeProxyChainConfig(exitNode); setChainConfigData(configData || ""); } catch (error) { console.error("Failed to get runtime proxy chain config:", error); @@ -106,7 +114,7 @@ const ProxyPage = () => { diff --git a/src/services/cmds.ts b/src/services/cmds.ts index 3ea4570b..0d689770 100644 --- a/src/services/cmds.ts +++ b/src/services/cmds.ts @@ -87,8 +87,10 @@ export async function getRuntimeLogs() { return invoke>("get_runtime_logs"); } -export async function getRuntimeProxyChainConfig() { - return invoke("get_runtime_proxy_chain_config"); +export async function getRuntimeProxyChainConfig(proxyChainExitNode: String) { + return invoke("get_runtime_proxy_chain_config", { + proxyChainExitNode, + }); } export async function updateProxyChainConfigInRuntime(proxyChainConfig: any) {