From ba9c9ba84d548b0934600de1c008285ab90bc0f7 Mon Sep 17 00:00:00 2001 From: pompurin404 Date: Sat, 3 Aug 2024 12:20:47 +0800 Subject: [PATCH] proxies page --- package.json | 1 + pnpm-lock.yaml | 15 ++++ src/main/core/mihomoApi.ts | 10 +++ src/main/utils/cmds.ts | 4 + src/renderer/index.html | 2 +- .../src/components/proxies/proxy-item.tsx | 33 ++++++++ .../src/components/proxies/proxy-list.tsx | 30 ++++++++ src/renderer/src/pages/proxies.tsx | 75 ++++++++++++++++++- src/renderer/src/utils/ipc.ts | 9 +++ src/shared/types.d.ts | 39 ++++++++++ 10 files changed, 216 insertions(+), 2 deletions(-) create mode 100644 src/renderer/src/components/proxies/proxy-item.tsx create mode 100644 src/renderer/src/components/proxies/proxy-list.tsx diff --git a/package.json b/package.json index c50436d..81394a1 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "react-icons": "^5.2.1", "react-monaco-editor": "^0.55.0", "react-router-dom": "^6.25.1", + "react-virtuoso": "^4.9.0", "swr": "^2.2.5", "ws": "^8.18.0", "yaml": "^2.5.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index aabe947..82828eb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,6 +41,9 @@ importers: react-router-dom: specifier: ^6.25.1 version: 6.25.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react-virtuoso: + specifier: ^4.9.0 + version: 4.9.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) swr: specifier: ^2.2.5 version: 2.2.5(react@18.3.1) @@ -3669,6 +3672,13 @@ packages: peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-virtuoso@4.9.0: + resolution: {integrity: sha512-MiiSGKqvYPfAK3FUe852n2L3M5IXMKP0pUgYQ/UTk90A/l2UNQOvaEUvAZp+0ytL0kOCNk8i8/J8FMKvIq7kqg==} + engines: {node: '>=10'} + peerDependencies: + react: '>=16 || >=17 || >= 18' + react-dom: '>=16 || >=17 || >= 18' + react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -9000,6 +9010,11 @@ snapshots: transitivePeerDependencies: - '@types/react' + react-virtuoso@4.9.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react@18.3.1: dependencies: loose-envify: 1.4.0 diff --git a/src/main/core/mihomoApi.ts b/src/main/core/mihomoApi.ts index cc12a3a..65d3641 100644 --- a/src/main/core/mihomoApi.ts +++ b/src/main/core/mihomoApi.ts @@ -49,6 +49,16 @@ export const mihomoRules = async (): Promise => { return instance.get('/rules') as Promise } +export const mihomoProxies = async (): Promise => { + const instance = await getAxios() + return instance.get('/proxies') as Promise +} + +export const mihomoChangeProxy = async (group: string, proxy: string): Promise => { + const instance = await getAxios() + return instance.put(`/proxies/${encodeURIComponent(group)}`, { name: proxy }) +} + export const startMihomoTraffic = (): void => { mihomoTraffic() } diff --git a/src/main/utils/cmds.ts b/src/main/utils/cmds.ts index bf03acf..dfdd9b3 100644 --- a/src/main/utils/cmds.ts +++ b/src/main/utils/cmds.ts @@ -1,7 +1,9 @@ import { ipcMain } from 'electron' import { + mihomoChangeProxy, mihomoConfig, mihomoConnections, + mihomoProxies, mihomoRules, mihomoVersion, patchMihomoConfig, @@ -29,6 +31,8 @@ export function registerIpcMainHandlers(): void { ipcMain.handle('mihomoConfig', mihomoConfig) ipcMain.handle('mihomoConnections', mihomoConnections) ipcMain.handle('mihomoRules', mihomoRules) + ipcMain.handle('mihomoProxies', () => mihomoProxies()) + ipcMain.handle('mihomoChangeProxy', (_e, group, proxy) => mihomoChangeProxy(group, proxy)) ipcMain.handle('startMihomoLogs', startMihomoLogs) ipcMain.handle('stopMihomoLogs', () => stopMihomoLogs()) ipcMain.handle('patchMihomoConfig', async (_e, patch) => await patchMihomoConfig(patch)) diff --git a/src/renderer/index.html b/src/renderer/index.html index 27d4b4e..a48de92 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -6,7 +6,7 @@ diff --git a/src/renderer/src/components/proxies/proxy-item.tsx b/src/renderer/src/components/proxies/proxy-item.tsx new file mode 100644 index 0000000..902466c --- /dev/null +++ b/src/renderer/src/components/proxies/proxy-item.tsx @@ -0,0 +1,33 @@ +import { Card, CardBody, Divider } from '@nextui-org/react' +import React from 'react' + +interface Props { + proxy: IMihomoProxy | IMihomoGroup + onSelect: (proxy: string) => void + selected: boolean +} + +const ProxyItem: React.FC = (props) => { + const { proxy, selected, onSelect } = props + return ( + <> + + onSelect(proxy.name)} + isPressable + fullWidth + className={`my-1 ${selected ? 'bg-primary' : ''}`} + radius="sm" + > + +
+
{proxy.name}
+
{proxy.history.length > 0 && proxy.history[0].delay}
+
+
+
+ + ) +} + +export default ProxyItem diff --git a/src/renderer/src/components/proxies/proxy-list.tsx b/src/renderer/src/components/proxies/proxy-list.tsx new file mode 100644 index 0000000..4469c6f --- /dev/null +++ b/src/renderer/src/components/proxies/proxy-list.tsx @@ -0,0 +1,30 @@ +import React from 'react' +import { Virtuoso } from 'react-virtuoso' +import ProxyItem from './proxy-item' + +interface Props { + onChangeProxy: (proxy: string) => void + proxies: (IMihomoProxy | IMihomoGroup)[] + now: string +} + +const ProxyList: React.FC = (props) => { + const { onChangeProxy, proxies, now } = props + + return ( + ( + + )} + /> + ) +} + +export default ProxyList diff --git a/src/renderer/src/pages/proxies.tsx b/src/renderer/src/pages/proxies.tsx index a0be9e0..5215db5 100644 --- a/src/renderer/src/pages/proxies.tsx +++ b/src/renderer/src/pages/proxies.tsx @@ -1,7 +1,80 @@ +import { Accordion, AccordionItem, Avatar } from '@nextui-org/react' import BasePage from '@renderer/components/base/base-page' +import ProxyList from '@renderer/components/proxies/proxy-list' +import { mihomoChangeProxy, mihomoProxies } from '@renderer/utils/ipc' +import { useEffect, useMemo } from 'react' +import useSWR from 'swr' const Proxies: React.FC = () => { - return + const { data: proxies, mutate } = useSWR('mihomoProxies', mihomoProxies) + + const groups = useMemo(() => { + const groups: IMihomoGroup[] = [] + if (proxies) { + const globalGroup = proxies.proxies['GLOBAL'] as IMihomoGroup + for (const global of globalGroup.all) { + if (isGroup(proxies.proxies[global])) { + groups.push(proxies.proxies[global] as IMihomoGroup) + } + } + Object.keys(proxies.proxies).forEach((key) => { + if (isGroup(proxies.proxies[key])) { + if (!groups.find((group) => group.name === key)) { + groups.push(proxies.proxies[key] as IMihomoGroup) + } + } + }) + } + return groups + }, [proxies]) + + const groupProxies = useMemo(() => { + const groupProxies: Record = {} + if (proxies) { + for (const group of groups) { + groupProxies[group.name] = group.all.map((name) => proxies.proxies[name]) + } + } + return groupProxies + }, [proxies]) + + const onChangeProxy = (group: string, proxy: string): void => { + mihomoChangeProxy(group, proxy).then(() => { + mutate() + }) + } + + useEffect(() => {}, []) + return ( + + + {groups.map((group) => { + return ( + 0 ? ( + + ) : null + } + > + onChangeProxy(group.name, proxy)} + proxies={groupProxies[group.name]} + now={group.now} + /> + + ) + })} + + + ) +} + +function isGroup(proxy: IMihomoProxy | IMihomoGroup): proxy is IMihomoGroup { + return 'all' in proxy } export default Proxies diff --git a/src/renderer/src/utils/ipc.ts b/src/renderer/src/utils/ipc.ts index d4235f4..08e0a76 100644 --- a/src/renderer/src/utils/ipc.ts +++ b/src/renderer/src/utils/ipc.ts @@ -13,6 +13,15 @@ export async function mihomoConnections(): Promise { export async function mihomoRules(): Promise { return await window.electron.ipcRenderer.invoke('mihomoRules') } + +export async function mihomoProxies(): Promise { + return await window.electron.ipcRenderer.invoke('mihomoProxies') +} + +export async function mihomoChangeProxy(group: string, proxy: string): Promise { + return await window.electron.ipcRenderer.invoke('mihomoChangeProxy', group, proxy) +} + export async function startMihomoLogs(): Promise { return await window.electron.ipcRenderer.invoke('startMihomoLogs') } diff --git a/src/shared/types.d.ts b/src/shared/types.d.ts index ae71570..d193991 100644 --- a/src/shared/types.d.ts +++ b/src/shared/types.d.ts @@ -1,6 +1,9 @@ type OutboundMode = 'rule' | 'global' | 'direct' type LogLevel = 'info' | 'debug' | 'warning' | 'error' | 'silent' type SysProxyMode = 'auto' | 'manual' +type MihomoGroupType = 'Selector' +type MihomoProxyType = 'Shadowsocks' + interface IMihomoVersion { version: string meta: boolean @@ -69,6 +72,42 @@ interface IMihomoConnectionDetail { rulePayload: string } +interface IMihomoHistory { + time: string + delay: number +} + +interface IMihomoProxy { + alive: boolean + extra: Record + history: IMihomoHistory[] + id: string + name: string + tfo: boolean + type: MihomoProxyType + udp: boolean + xudp: boolean +} + +interface IMihomoGroup { + alive: boolean + all: string[] + extra: Record + hidden: boolean + history: IMihomoHistory[] + icon: string + name: string + now: string + tfo: boolean + type: MihomoGroupType + udp: boolean + xudp: boolean +} + +interface IMihomoProxies { + proxies: Record +} + interface ISysProxyConfig { enable: boolean host?: string