mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2026-02-11 04:00:32 +08:00
connections page
This commit is contained in:
parent
15dd29c0f8
commit
e4d4b54874
@ -7,6 +7,7 @@ let axiosIns: AxiosInstance = null!
|
|||||||
let mihomoTrafficWs: WebSocket | null = null
|
let mihomoTrafficWs: WebSocket | null = null
|
||||||
let mihomoMemoryWs: WebSocket | null = null
|
let mihomoMemoryWs: WebSocket | null = null
|
||||||
let mihomoLogsWs: WebSocket | null = null
|
let mihomoLogsWs: WebSocket | null = null
|
||||||
|
let mihomoConnectionsWs: WebSocket | null = null
|
||||||
|
|
||||||
export const getAxios = async (force: boolean = false): Promise<AxiosInstance> => {
|
export const getAxios = async (force: boolean = false): Promise<AxiosInstance> => {
|
||||||
if (axiosIns && !force) return axiosIns
|
if (axiosIns && !force) return axiosIns
|
||||||
@ -46,13 +47,6 @@ export const patchMihomoConfig = async (patch: Partial<IMihomoConfig>): Promise<
|
|||||||
})) as Promise<void>
|
})) as Promise<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mihomoConnections = async (): Promise<IMihomoConnectionsInfo> => {
|
|
||||||
const instance = await getAxios()
|
|
||||||
return (await instance.get('/connections').catch(() => {
|
|
||||||
return { downloadTotal: 0, uploadTotal: 0, connections: [], memory: 0 }
|
|
||||||
})) as IMihomoConnectionsInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
export const mihomoCloseConnection = async (id: string): Promise<void> => {
|
export const mihomoCloseConnection = async (id: string): Promise<void> => {
|
||||||
const instance = await getAxios()
|
const instance = await getAxios()
|
||||||
return (await instance.delete(`/connections/${encodeURIComponent(id)}`).catch((e) => {
|
return (await instance.delete(`/connections/${encodeURIComponent(id)}`).catch((e) => {
|
||||||
@ -230,3 +224,44 @@ const mihomoLogs = (): void => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const startMihomoConnections = (): void => {
|
||||||
|
mihomoConnections()
|
||||||
|
}
|
||||||
|
|
||||||
|
export const stopMihomoConnections = (): void => {
|
||||||
|
if (mihomoConnectionsWs) {
|
||||||
|
mihomoConnectionsWs.removeAllListeners()
|
||||||
|
if (mihomoConnectionsWs.readyState === WebSocket.OPEN) {
|
||||||
|
mihomoConnectionsWs.close()
|
||||||
|
}
|
||||||
|
mihomoConnectionsWs = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mihomoConnections = (): void => {
|
||||||
|
let server = getControledMihomoConfig()['external-controller']
|
||||||
|
const secret = getControledMihomoConfig().secret ?? ''
|
||||||
|
if (server?.startsWith(':')) server = `127.0.0.1${server}`
|
||||||
|
stopMihomoConnections()
|
||||||
|
|
||||||
|
mihomoConnectionsWs = new WebSocket(
|
||||||
|
`ws://${server}/connections?token=${encodeURIComponent(secret)}`
|
||||||
|
)
|
||||||
|
|
||||||
|
mihomoConnectionsWs.onmessage = (e): void => {
|
||||||
|
const data = e.data as string
|
||||||
|
window?.webContents.send('mihomoConnections', JSON.parse(data) as IMihomoConnectionsInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
mihomoConnectionsWs.onclose = (): void => {
|
||||||
|
mihomoConnections()
|
||||||
|
}
|
||||||
|
|
||||||
|
mihomoConnectionsWs.onerror = (): void => {
|
||||||
|
if (mihomoConnectionsWs) {
|
||||||
|
mihomoConnectionsWs.close()
|
||||||
|
mihomoConnectionsWs = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -4,13 +4,14 @@ import {
|
|||||||
mihomoCloseAllConnections,
|
mihomoCloseAllConnections,
|
||||||
mihomoCloseConnection,
|
mihomoCloseConnection,
|
||||||
mihomoConfig,
|
mihomoConfig,
|
||||||
mihomoConnections,
|
|
||||||
mihomoProxies,
|
mihomoProxies,
|
||||||
mihomoProxyDelay,
|
mihomoProxyDelay,
|
||||||
mihomoRules,
|
mihomoRules,
|
||||||
mihomoVersion,
|
mihomoVersion,
|
||||||
patchMihomoConfig,
|
patchMihomoConfig,
|
||||||
|
startMihomoConnections,
|
||||||
startMihomoLogs,
|
startMihomoLogs,
|
||||||
|
stopMihomoConnections,
|
||||||
stopMihomoLogs
|
stopMihomoLogs
|
||||||
} from '../core/mihomoApi'
|
} from '../core/mihomoApi'
|
||||||
import { checkAutoRun, disableAutoRun, enableAutoRun } from '../resolve/autoRun'
|
import { checkAutoRun, disableAutoRun, enableAutoRun } from '../resolve/autoRun'
|
||||||
@ -36,7 +37,6 @@ import { checkUpdate } from '../resolve/autoUpdater'
|
|||||||
export function registerIpcMainHandlers(): void {
|
export function registerIpcMainHandlers(): void {
|
||||||
ipcMain.handle('mihomoVersion', mihomoVersion)
|
ipcMain.handle('mihomoVersion', mihomoVersion)
|
||||||
ipcMain.handle('mihomoConfig', mihomoConfig)
|
ipcMain.handle('mihomoConfig', mihomoConfig)
|
||||||
ipcMain.handle('mihomoConnections', mihomoConnections)
|
|
||||||
ipcMain.handle('mihomoCloseConnection', (_e, id) => mihomoCloseConnection(id))
|
ipcMain.handle('mihomoCloseConnection', (_e, id) => mihomoCloseConnection(id))
|
||||||
ipcMain.handle('mihomoCloseAllConnections', mihomoCloseAllConnections)
|
ipcMain.handle('mihomoCloseAllConnections', mihomoCloseAllConnections)
|
||||||
ipcMain.handle('mihomoRules', mihomoRules)
|
ipcMain.handle('mihomoRules', mihomoRules)
|
||||||
@ -45,6 +45,8 @@ export function registerIpcMainHandlers(): void {
|
|||||||
ipcMain.handle('mihomoProxyDelay', (_e, proxy, url) => mihomoProxyDelay(proxy, url))
|
ipcMain.handle('mihomoProxyDelay', (_e, proxy, url) => mihomoProxyDelay(proxy, url))
|
||||||
ipcMain.handle('startMihomoLogs', startMihomoLogs)
|
ipcMain.handle('startMihomoLogs', startMihomoLogs)
|
||||||
ipcMain.handle('stopMihomoLogs', stopMihomoLogs)
|
ipcMain.handle('stopMihomoLogs', stopMihomoLogs)
|
||||||
|
ipcMain.handle('startMihomoConnections', () => startMihomoConnections())
|
||||||
|
ipcMain.handle('stopMihomoConnections', () => stopMihomoConnections())
|
||||||
ipcMain.handle('patchMihomoConfig', (_e, patch) => patchMihomoConfig(patch))
|
ipcMain.handle('patchMihomoConfig', (_e, patch) => patchMihomoConfig(patch))
|
||||||
ipcMain.handle('checkAutoRun', checkAutoRun)
|
ipcMain.handle('checkAutoRun', checkAutoRun)
|
||||||
ipcMain.handle('enableAutoRun', enableAutoRun)
|
ipcMain.handle('enableAutoRun', enableAutoRun)
|
||||||
|
|||||||
@ -8,7 +8,11 @@
|
|||||||
|
|
||||||
*::-webkit-scrollbar {
|
*::-webkit-scrollbar {
|
||||||
width: 8px;
|
width: 8px;
|
||||||
height: 6px;
|
height: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
*::-webkit-scrollbar-corner {
|
||||||
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Light mode */
|
/* Light mode */
|
||||||
|
|||||||
@ -0,0 +1,29 @@
|
|||||||
|
import { Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Button } from '@nextui-org/react'
|
||||||
|
import React from 'react'
|
||||||
|
interface Props {
|
||||||
|
connection: IMihomoConnectionDetail
|
||||||
|
onClose: () => void
|
||||||
|
}
|
||||||
|
const ConnectionDetailModal: React.FC<Props> = (props) => {
|
||||||
|
const { connection, onClose } = props
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal size="xl" hideCloseButton isOpen={true} scrollBehavior="inside">
|
||||||
|
<ModalContent>
|
||||||
|
<ModalHeader className="flex">连接详情</ModalHeader>
|
||||||
|
<ModalBody>
|
||||||
|
<pre>
|
||||||
|
<code>{JSON.stringify(connection, null, 2)}</code>
|
||||||
|
</pre>
|
||||||
|
</ModalBody>
|
||||||
|
<ModalFooter>
|
||||||
|
<Button variant="light" onPress={onClose}>
|
||||||
|
关闭
|
||||||
|
</Button>
|
||||||
|
</ModalFooter>
|
||||||
|
</ModalContent>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ConnectionDetailModal
|
||||||
@ -1,40 +0,0 @@
|
|||||||
import { Button, Card, CardBody } from '@nextui-org/react'
|
|
||||||
import { mihomoCloseConnection } from '@renderer/utils/ipc'
|
|
||||||
import { IoClose } from 'react-icons/io5'
|
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
interface Props extends IMihomoConnectionDetail {
|
|
||||||
mutate: () => void
|
|
||||||
}
|
|
||||||
const ConnectionItem: React.FC<Props> = (props) => {
|
|
||||||
const { id, metadata, mutate } = props
|
|
||||||
return (
|
|
||||||
<Card className="m-2">
|
|
||||||
<CardBody className="">
|
|
||||||
<div className="flex justify-between">
|
|
||||||
<div className="select-none h-[32px] leading-[32px]">
|
|
||||||
{metadata.type}({metadata.network})
|
|
||||||
</div>
|
|
||||||
<div className="select-none h-[32px] leading-[32px]">{metadata.inboundIP}</div>
|
|
||||||
<div className="select-none h-[32px] leading-[32px]">{'-->'}</div>
|
|
||||||
<div className="select-none h-[32px] leading-[32px]">{metadata.remoteDestination}</div>
|
|
||||||
<Button
|
|
||||||
isIconOnly
|
|
||||||
size="sm"
|
|
||||||
color="danger"
|
|
||||||
variant="light"
|
|
||||||
onPress={() => {
|
|
||||||
mihomoCloseConnection(id).then(() => {
|
|
||||||
mutate()
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<IoClose className="text-[24px]" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</CardBody>
|
|
||||||
</Card>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ConnectionItem
|
|
||||||
@ -1,25 +1,80 @@
|
|||||||
import ConnectionItem from '@renderer/components/connections/connection-item'
|
|
||||||
import BasePage from '@renderer/components/base/base-page'
|
import BasePage from '@renderer/components/base/base-page'
|
||||||
import { mihomoCloseAllConnections, mihomoConnections } from '@renderer/utils/ipc'
|
import {
|
||||||
import { useMemo, useState } from 'react'
|
mihomoCloseAllConnections,
|
||||||
|
mihomoCloseConnection,
|
||||||
|
startMihomoConnections,
|
||||||
|
stopMihomoConnections
|
||||||
|
} from '@renderer/utils/ipc'
|
||||||
|
import { Key, useEffect, useMemo, useState } from 'react'
|
||||||
import { Button, Input } from '@nextui-org/react'
|
import { Button, Input } from '@nextui-org/react'
|
||||||
import useSWR from 'swr'
|
import { IoCloseCircle } from 'react-icons/io5'
|
||||||
import { calcTraffic } from '@renderer/utils/calc'
|
import { calcTraffic } from '@renderer/utils/calc'
|
||||||
|
import { Table, TableHeader, TableColumn, TableBody, TableRow, TableCell } from '@nextui-org/react'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import ConnectionDetailModal from '@renderer/components/connections/connection-detail-modal'
|
||||||
|
|
||||||
|
let preData: IMihomoConnectionDetail[] = []
|
||||||
|
|
||||||
const Connections: React.FC = () => {
|
const Connections: React.FC = () => {
|
||||||
const { data: connections = { downloadTotal: 0, uploadTotal: 0, connections: [] }, mutate } =
|
|
||||||
useSWR<IMihomoConnectionsInfo>('mihomoConnections', mihomoConnections, {
|
|
||||||
refreshInterval: 1000
|
|
||||||
})
|
|
||||||
const [filter, setFilter] = useState('')
|
const [filter, setFilter] = useState('')
|
||||||
|
const [connectionsInfo, setConnectionsInfo] = useState<IMihomoConnectionsInfo>()
|
||||||
|
const [connections, setConnections] = useState<IMihomoConnectionDetail[]>([])
|
||||||
|
const [selectedConnection, setSelectedConnection] = useState<IMihomoConnectionDetail>()
|
||||||
|
const [isDetailModalOpen, setIsDetailModalOpen] = useState(false)
|
||||||
|
const [sortKey, setSortKey] = useState('')
|
||||||
|
const [descend, setDescend] = useState(false)
|
||||||
|
|
||||||
const filteredConnections = useMemo(() => {
|
const filteredConnections = useMemo(() => {
|
||||||
if (filter === '') return connections.connections
|
if (filter === '') return connections
|
||||||
return connections.connections?.filter((connection) => {
|
return connections?.filter((connection) => {
|
||||||
return connection.metadata.remoteDestination.includes(filter)
|
const raw = JSON.stringify(connection)
|
||||||
|
return raw.includes(filter)
|
||||||
})
|
})
|
||||||
}, [connections, filter])
|
}, [connections, filter])
|
||||||
|
|
||||||
|
const sortedConnections = useMemo(() => {
|
||||||
|
if (sortKey === '') return filteredConnections
|
||||||
|
return filteredConnections.sort((a, b) => {
|
||||||
|
const localA = a[sortKey] ? a[sortKey] : a.metadata[sortKey]
|
||||||
|
const localB = b[sortKey] ? b[sortKey] : b.metadata[sortKey]
|
||||||
|
if (descend) {
|
||||||
|
if (typeof localA === 'string') {
|
||||||
|
return localB.localeCompare(localA)
|
||||||
|
}
|
||||||
|
return localB - localA
|
||||||
|
} else {
|
||||||
|
if (typeof localA === 'string') {
|
||||||
|
return localA.localeCompare(localB)
|
||||||
|
}
|
||||||
|
return localA - localB
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, [filteredConnections, sortKey, descend])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
startMihomoConnections()
|
||||||
|
window.electron.ipcRenderer.on('mihomoConnections', (_e, info: IMihomoConnectionsInfo) => {
|
||||||
|
setConnectionsInfo(info)
|
||||||
|
const newConns: IMihomoConnectionDetail[] = []
|
||||||
|
for (const conn of info.connections ?? []) {
|
||||||
|
const preConn = preData?.find((c) => c.id === conn.id)
|
||||||
|
|
||||||
|
if (preConn) {
|
||||||
|
conn.downloadSpeed = conn.download - preConn.download
|
||||||
|
conn.uploadSpeed = conn.upload - preConn.upload
|
||||||
|
}
|
||||||
|
newConns.push(conn)
|
||||||
|
}
|
||||||
|
setConnections(newConns)
|
||||||
|
preData = newConns
|
||||||
|
})
|
||||||
|
|
||||||
|
return (): void => {
|
||||||
|
stopMihomoConnections()
|
||||||
|
window.electron.ipcRenderer.removeAllListeners('mihomoConnections')
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BasePage
|
<BasePage
|
||||||
title="连接"
|
title="连接"
|
||||||
@ -27,28 +82,30 @@ const Connections: React.FC = () => {
|
|||||||
<div className="flex">
|
<div className="flex">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<span className="mx-1 text-gray-400">
|
<span className="mx-1 text-gray-400">
|
||||||
下载: {calcTraffic(connections.downloadTotal)}{' '}
|
下载: {calcTraffic(connectionsInfo?.downloadTotal ?? 0)}{' '}
|
||||||
</span>
|
</span>
|
||||||
<span className="mx-1 text-gray-400">
|
<span className="mx-1 text-gray-400">
|
||||||
上传: {calcTraffic(connections.uploadTotal)}{' '}
|
上传: {calcTraffic(connectionsInfo?.uploadTotal ?? 0)}{' '}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
className="ml-1"
|
className="ml-1"
|
||||||
size="sm"
|
size="sm"
|
||||||
color="primary"
|
color="primary"
|
||||||
onPress={() =>
|
onPress={() => mihomoCloseAllConnections()}
|
||||||
mihomoCloseAllConnections().then(() => {
|
|
||||||
mutate()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
关闭所有连接
|
关闭所有连接
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="sticky top-[48px] z-40 backdrop-blur bg-background/40 flex p-2">
|
{isDetailModalOpen && selectedConnection && (
|
||||||
|
<ConnectionDetailModal
|
||||||
|
onClose={() => setIsDetailModalOpen(false)}
|
||||||
|
connection={selectedConnection}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<div className="overflow-x-auto sticky top-[49px] z-40 backdrop-blur bg-background/40 flex p-2">
|
||||||
<Input
|
<Input
|
||||||
variant="bordered"
|
variant="bordered"
|
||||||
size="sm"
|
size="sm"
|
||||||
@ -57,7 +114,106 @@ const Connections: React.FC = () => {
|
|||||||
onValueChange={setFilter}
|
onValueChange={setFilter}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{filteredConnections?.map((connection) => {
|
<Table
|
||||||
|
onRowAction={(id: Key) => {
|
||||||
|
setSelectedConnection(connections.find((c) => c.id === (id as string)))
|
||||||
|
setIsDetailModalOpen(true)
|
||||||
|
}}
|
||||||
|
sortDescriptor={{ column: sortKey, direction: descend ? 'descending' : 'ascending' }}
|
||||||
|
onSortChange={(desc) => {
|
||||||
|
setSortKey(desc.column as string)
|
||||||
|
setDescend(desc.direction !== 'ascending')
|
||||||
|
}}
|
||||||
|
isHeaderSticky
|
||||||
|
isStriped
|
||||||
|
className="h-[calc(100vh-100px)] p-2"
|
||||||
|
>
|
||||||
|
<TableHeader>
|
||||||
|
<TableColumn key="type" allowsSorting>
|
||||||
|
类型
|
||||||
|
</TableColumn>
|
||||||
|
<TableColumn key="process" allowsSorting>
|
||||||
|
进程
|
||||||
|
</TableColumn>
|
||||||
|
<TableColumn key="host" allowsSorting>
|
||||||
|
主机
|
||||||
|
</TableColumn>
|
||||||
|
<TableColumn key="sniffer" allowsSorting>
|
||||||
|
嗅探域名
|
||||||
|
</TableColumn>
|
||||||
|
<TableColumn key="rule" allowsSorting>
|
||||||
|
规则
|
||||||
|
</TableColumn>
|
||||||
|
<TableColumn key="chains" width={500}>
|
||||||
|
链路
|
||||||
|
</TableColumn>
|
||||||
|
<TableColumn key="download" allowsSorting>
|
||||||
|
下载量
|
||||||
|
</TableColumn>
|
||||||
|
<TableColumn key="upload" allowsSorting>
|
||||||
|
上传量
|
||||||
|
</TableColumn>
|
||||||
|
<TableColumn key="downloadSpeed" allowsSorting>
|
||||||
|
下载速度
|
||||||
|
</TableColumn>
|
||||||
|
<TableColumn key="uploadSpeed" allowsSorting>
|
||||||
|
上传速度
|
||||||
|
</TableColumn>
|
||||||
|
<TableColumn key="start" allowsSorting>
|
||||||
|
连接时间
|
||||||
|
</TableColumn>
|
||||||
|
<TableColumn key="sourceIp">源地址</TableColumn>
|
||||||
|
<TableColumn key="sourcePort">源端口</TableColumn>
|
||||||
|
<TableColumn key="inboundUser">入站用户</TableColumn>
|
||||||
|
<TableColumn key="close">关闭连接</TableColumn>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody items={sortedConnections ?? []}>
|
||||||
|
{(item) => (
|
||||||
|
<TableRow key={item.id}>
|
||||||
|
<TableCell className="max-w-[10px]">
|
||||||
|
{item.metadata.type}({item.metadata.network})
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>{item.metadata.process}</TableCell>
|
||||||
|
<TableCell className="max-w-[200px] text-ellipsis whitespace-nowrap overflow-hidden">
|
||||||
|
{item.metadata.host}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="max-w-[200px] text-ellipsis whitespace-nowrap overflow-hidden">
|
||||||
|
{item.metadata.sniffHost ?? '-'}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="max-w-[200px] text-ellipsis whitespace-nowrap overflow-hidden">
|
||||||
|
{item.rule}:{item.rulePayload}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="max-w-[200px] text-ellipsis whitespace-nowrap overflow-hidden">
|
||||||
|
{item.chains.reverse().join('::')}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="whitespace-nowrap">{calcTraffic(item.download)}</TableCell>
|
||||||
|
<TableCell className="whitespace-nowrap">{calcTraffic(item.upload)}</TableCell>
|
||||||
|
<TableCell className="whitespace-nowrap">
|
||||||
|
{calcTraffic(item.downloadSpeed ?? 0)}/s
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="whitespace-nowrap">
|
||||||
|
{calcTraffic(item.uploadSpeed ?? 0)}/s
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="whitespace-nowrap">{dayjs(item.start).fromNow()}</TableCell>
|
||||||
|
<TableCell className="whitespace-nowrap">{item.metadata.sourceIP}</TableCell>
|
||||||
|
<TableCell className="whitespace-nowrap">{item.metadata.sourcePort}</TableCell>
|
||||||
|
<TableCell className="whitespace-nowrap">{item.metadata.inboundUser}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Button
|
||||||
|
isIconOnly
|
||||||
|
size="sm"
|
||||||
|
color="danger"
|
||||||
|
variant="light"
|
||||||
|
onPress={() => mihomoCloseConnection(item.id)}
|
||||||
|
>
|
||||||
|
<IoCloseCircle className="text-lg" />
|
||||||
|
</Button>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
{/* {filteredConnections?.map((connection) => {
|
||||||
return (
|
return (
|
||||||
<ConnectionItem
|
<ConnectionItem
|
||||||
mutate={mutate}
|
mutate={mutate}
|
||||||
@ -72,7 +228,7 @@ const Connections: React.FC = () => {
|
|||||||
start={connection.start}
|
start={connection.start}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
})}
|
})} */}
|
||||||
</BasePage>
|
</BasePage>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,10 +6,6 @@ export async function mihomoConfig(): Promise<IMihomoConfig> {
|
|||||||
return await window.electron.ipcRenderer.invoke('mihomoConfig')
|
return await window.electron.ipcRenderer.invoke('mihomoConfig')
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function mihomoConnections(): Promise<IMihomoConnectionsInfo> {
|
|
||||||
return await window.electron.ipcRenderer.invoke('mihomoConnections')
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function mihomoCloseConnection(id: string): Promise<void> {
|
export async function mihomoCloseConnection(id: string): Promise<void> {
|
||||||
return await window.electron.ipcRenderer.invoke('mihomoCloseConnection', id)
|
return await window.electron.ipcRenderer.invoke('mihomoCloseConnection', id)
|
||||||
}
|
}
|
||||||
@ -43,6 +39,14 @@ export async function stopMihomoLogs(): Promise<void> {
|
|||||||
return await window.electron.ipcRenderer.invoke('stopMihomoLogs')
|
return await window.electron.ipcRenderer.invoke('stopMihomoLogs')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function startMihomoConnections(): Promise<void> {
|
||||||
|
return await window.electron.ipcRenderer.invoke('startMihomoConnections')
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function stopMihomoConnections(): Promise<void> {
|
||||||
|
return await window.electron.ipcRenderer.invoke('stopMihomoConnections')
|
||||||
|
}
|
||||||
|
|
||||||
export async function patchMihomoConfig(patch: Partial<IMihomoConfig>): Promise<void> {
|
export async function patchMihomoConfig(patch: Partial<IMihomoConfig>): Promise<void> {
|
||||||
return await window.electron.ipcRenderer.invoke('patchMihomoConfig', patch)
|
return await window.electron.ipcRenderer.invoke('patchMihomoConfig', patch)
|
||||||
}
|
}
|
||||||
|
|||||||
2
src/shared/types.d.ts
vendored
2
src/shared/types.d.ts
vendored
@ -71,6 +71,8 @@ interface IMihomoConnectionDetail {
|
|||||||
dscp: number
|
dscp: number
|
||||||
sniffHost: string
|
sniffHost: string
|
||||||
}
|
}
|
||||||
|
uploadSpeed?: number
|
||||||
|
downloadSpeed?: number
|
||||||
upload: number
|
upload: number
|
||||||
download: number
|
download: number
|
||||||
start: string
|
start: string
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user