mirror of
https://github.com/pompurin404/mihomo-party.git
synced 2024-11-16 11:42:19 +08:00
proxies page
This commit is contained in:
parent
deeaa5933d
commit
ba9c9ba84d
|
@ -30,6 +30,7 @@
|
||||||
"react-icons": "^5.2.1",
|
"react-icons": "^5.2.1",
|
||||||
"react-monaco-editor": "^0.55.0",
|
"react-monaco-editor": "^0.55.0",
|
||||||
"react-router-dom": "^6.25.1",
|
"react-router-dom": "^6.25.1",
|
||||||
|
"react-virtuoso": "^4.9.0",
|
||||||
"swr": "^2.2.5",
|
"swr": "^2.2.5",
|
||||||
"ws": "^8.18.0",
|
"ws": "^8.18.0",
|
||||||
"yaml": "^2.5.0"
|
"yaml": "^2.5.0"
|
||||||
|
|
|
@ -41,6 +41,9 @@ importers:
|
||||||
react-router-dom:
|
react-router-dom:
|
||||||
specifier: ^6.25.1
|
specifier: ^6.25.1
|
||||||
version: 6.25.1(react-dom@18.3.1(react@18.3.1))(react@18.3.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:
|
swr:
|
||||||
specifier: ^2.2.5
|
specifier: ^2.2.5
|
||||||
version: 2.2.5(react@18.3.1)
|
version: 2.2.5(react@18.3.1)
|
||||||
|
@ -3669,6 +3672,13 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
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:
|
react@18.3.1:
|
||||||
resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
|
resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
@ -9000,6 +9010,11 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@types/react'
|
- '@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:
|
react@18.3.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
loose-envify: 1.4.0
|
loose-envify: 1.4.0
|
||||||
|
|
|
@ -49,6 +49,16 @@ export const mihomoRules = async (): Promise<IMihomoRulesInfo> => {
|
||||||
return instance.get('/rules') as Promise<IMihomoRulesInfo>
|
return instance.get('/rules') as Promise<IMihomoRulesInfo>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const mihomoProxies = async (): Promise<IMihomoProxies> => {
|
||||||
|
const instance = await getAxios()
|
||||||
|
return instance.get('/proxies') as Promise<IMihomoProxies>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const mihomoChangeProxy = async (group: string, proxy: string): Promise<IMihomoProxy> => {
|
||||||
|
const instance = await getAxios()
|
||||||
|
return instance.put(`/proxies/${encodeURIComponent(group)}`, { name: proxy })
|
||||||
|
}
|
||||||
|
|
||||||
export const startMihomoTraffic = (): void => {
|
export const startMihomoTraffic = (): void => {
|
||||||
mihomoTraffic()
|
mihomoTraffic()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import { ipcMain } from 'electron'
|
import { ipcMain } from 'electron'
|
||||||
import {
|
import {
|
||||||
|
mihomoChangeProxy,
|
||||||
mihomoConfig,
|
mihomoConfig,
|
||||||
mihomoConnections,
|
mihomoConnections,
|
||||||
|
mihomoProxies,
|
||||||
mihomoRules,
|
mihomoRules,
|
||||||
mihomoVersion,
|
mihomoVersion,
|
||||||
patchMihomoConfig,
|
patchMihomoConfig,
|
||||||
|
@ -29,6 +31,8 @@ export function registerIpcMainHandlers(): void {
|
||||||
ipcMain.handle('mihomoConfig', mihomoConfig)
|
ipcMain.handle('mihomoConfig', mihomoConfig)
|
||||||
ipcMain.handle('mihomoConnections', mihomoConnections)
|
ipcMain.handle('mihomoConnections', mihomoConnections)
|
||||||
ipcMain.handle('mihomoRules', mihomoRules)
|
ipcMain.handle('mihomoRules', mihomoRules)
|
||||||
|
ipcMain.handle('mihomoProxies', () => mihomoProxies())
|
||||||
|
ipcMain.handle('mihomoChangeProxy', (_e, group, proxy) => mihomoChangeProxy(group, proxy))
|
||||||
ipcMain.handle('startMihomoLogs', startMihomoLogs)
|
ipcMain.handle('startMihomoLogs', startMihomoLogs)
|
||||||
ipcMain.handle('stopMihomoLogs', () => stopMihomoLogs())
|
ipcMain.handle('stopMihomoLogs', () => stopMihomoLogs())
|
||||||
ipcMain.handle('patchMihomoConfig', async (_e, patch) => await patchMihomoConfig(patch))
|
ipcMain.handle('patchMihomoConfig', async (_e, patch) => await patchMihomoConfig(patch))
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
|
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
|
||||||
<meta
|
<meta
|
||||||
http-equiv="Content-Security-Policy"
|
http-equiv="Content-Security-Policy"
|
||||||
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:"
|
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src *"
|
||||||
/>
|
/>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
33
src/renderer/src/components/proxies/proxy-item.tsx
Normal file
33
src/renderer/src/components/proxies/proxy-item.tsx
Normal file
|
@ -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> = (props) => {
|
||||||
|
const { proxy, selected, onSelect } = props
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Divider />
|
||||||
|
<Card
|
||||||
|
onPress={() => onSelect(proxy.name)}
|
||||||
|
isPressable
|
||||||
|
fullWidth
|
||||||
|
className={`my-1 ${selected ? 'bg-primary' : ''}`}
|
||||||
|
radius="sm"
|
||||||
|
>
|
||||||
|
<CardBody className="p-1">
|
||||||
|
<div className="flex justify-between items-center">
|
||||||
|
<div>{proxy.name}</div>
|
||||||
|
<div className="mx-2 text-sm">{proxy.history.length > 0 && proxy.history[0].delay}</div>
|
||||||
|
</div>
|
||||||
|
</CardBody>
|
||||||
|
</Card>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ProxyItem
|
30
src/renderer/src/components/proxies/proxy-list.tsx
Normal file
30
src/renderer/src/components/proxies/proxy-list.tsx
Normal file
|
@ -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> = (props) => {
|
||||||
|
const { onChangeProxy, proxies, now } = props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Virtuoso
|
||||||
|
style={{ height: `min(calc(100vh - 200px), ${proxies.length * 44}px)` }}
|
||||||
|
totalCount={proxies.length}
|
||||||
|
increaseViewportBy={100}
|
||||||
|
itemContent={(index) => (
|
||||||
|
<ProxyItem
|
||||||
|
onSelect={onChangeProxy}
|
||||||
|
proxy={proxies[index]}
|
||||||
|
selected={proxies[index].name === now}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ProxyList
|
|
@ -1,7 +1,80 @@
|
||||||
|
import { Accordion, AccordionItem, Avatar } from '@nextui-org/react'
|
||||||
import BasePage from '@renderer/components/base/base-page'
|
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 = () => {
|
const Proxies: React.FC = () => {
|
||||||
return <BasePage title="代理组"></BasePage>
|
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<string, (IMihomoProxy | IMihomoGroup)[]> = {}
|
||||||
|
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 (
|
||||||
|
<BasePage title="代理组">
|
||||||
|
<Accordion variant="splitted" className="p-2">
|
||||||
|
{groups.map((group) => {
|
||||||
|
return (
|
||||||
|
<AccordionItem
|
||||||
|
key={group.name}
|
||||||
|
title={group.name}
|
||||||
|
classNames={{ content: 'p-0' }}
|
||||||
|
startContent={
|
||||||
|
group.icon.length > 0 ? (
|
||||||
|
<Avatar className="bg-transparent" size="sm" radius="sm" src={group.icon} />
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ProxyList
|
||||||
|
onChangeProxy={(proxy) => onChangeProxy(group.name, proxy)}
|
||||||
|
proxies={groupProxies[group.name]}
|
||||||
|
now={group.now}
|
||||||
|
/>
|
||||||
|
</AccordionItem>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</Accordion>
|
||||||
|
</BasePage>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function isGroup(proxy: IMihomoProxy | IMihomoGroup): proxy is IMihomoGroup {
|
||||||
|
return 'all' in proxy
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Proxies
|
export default Proxies
|
||||||
|
|
|
@ -13,6 +13,15 @@ export async function mihomoConnections(): Promise<IMihomoConnectionsInfo> {
|
||||||
export async function mihomoRules(): Promise<IMihomoRulesInfo> {
|
export async function mihomoRules(): Promise<IMihomoRulesInfo> {
|
||||||
return await window.electron.ipcRenderer.invoke('mihomoRules')
|
return await window.electron.ipcRenderer.invoke('mihomoRules')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function mihomoProxies(): Promise<IMihomoProxies> {
|
||||||
|
return await window.electron.ipcRenderer.invoke('mihomoProxies')
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function mihomoChangeProxy(group: string, proxy: string): Promise<IMihomoProxy> {
|
||||||
|
return await window.electron.ipcRenderer.invoke('mihomoChangeProxy', group, proxy)
|
||||||
|
}
|
||||||
|
|
||||||
export async function startMihomoLogs(): Promise<void> {
|
export async function startMihomoLogs(): Promise<void> {
|
||||||
return await window.electron.ipcRenderer.invoke('startMihomoLogs')
|
return await window.electron.ipcRenderer.invoke('startMihomoLogs')
|
||||||
}
|
}
|
||||||
|
|
39
src/shared/types.d.ts
vendored
39
src/shared/types.d.ts
vendored
|
@ -1,6 +1,9 @@
|
||||||
type OutboundMode = 'rule' | 'global' | 'direct'
|
type OutboundMode = 'rule' | 'global' | 'direct'
|
||||||
type LogLevel = 'info' | 'debug' | 'warning' | 'error' | 'silent'
|
type LogLevel = 'info' | 'debug' | 'warning' | 'error' | 'silent'
|
||||||
type SysProxyMode = 'auto' | 'manual'
|
type SysProxyMode = 'auto' | 'manual'
|
||||||
|
type MihomoGroupType = 'Selector'
|
||||||
|
type MihomoProxyType = 'Shadowsocks'
|
||||||
|
|
||||||
interface IMihomoVersion {
|
interface IMihomoVersion {
|
||||||
version: string
|
version: string
|
||||||
meta: boolean
|
meta: boolean
|
||||||
|
@ -69,6 +72,42 @@ interface IMihomoConnectionDetail {
|
||||||
rulePayload: string
|
rulePayload: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IMihomoHistory {
|
||||||
|
time: string
|
||||||
|
delay: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IMihomoProxy {
|
||||||
|
alive: boolean
|
||||||
|
extra: Record<string, { alive: boolean; history: IMihomoHistory[] }>
|
||||||
|
history: IMihomoHistory[]
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
tfo: boolean
|
||||||
|
type: MihomoProxyType
|
||||||
|
udp: boolean
|
||||||
|
xudp: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IMihomoGroup {
|
||||||
|
alive: boolean
|
||||||
|
all: string[]
|
||||||
|
extra: Record<string, { alive: boolean; history: IMihomoHistory[] }>
|
||||||
|
hidden: boolean
|
||||||
|
history: IMihomoHistory[]
|
||||||
|
icon: string
|
||||||
|
name: string
|
||||||
|
now: string
|
||||||
|
tfo: boolean
|
||||||
|
type: MihomoGroupType
|
||||||
|
udp: boolean
|
||||||
|
xudp: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IMihomoProxies {
|
||||||
|
proxies: Record<string, IMihomoProxy | IMihomoGroup>
|
||||||
|
}
|
||||||
|
|
||||||
interface ISysProxyConfig {
|
interface ISysProxyConfig {
|
||||||
enable: boolean
|
enable: boolean
|
||||||
host?: string
|
host?: string
|
||||||
|
|
Loading…
Reference in New Issue
Block a user