From 4aeac0ebb3b1bcad0ebd73fc022a4981afaea91d Mon Sep 17 00:00:00 2001 From: pompurin404 Date: Mon, 19 Aug 2024 10:10:22 +0800 Subject: [PATCH] support interfaces info --- changelog.md | 1 + src/main/sys/interface.ts | 5 + src/main/utils/ipc.ts | 2 + .../src/components/mihomo/interface-modal.tsx | 67 +++ src/renderer/src/pages/mihomo.tsx | 497 +++++++++--------- src/renderer/src/utils/ipc.ts | 4 + src/shared/types.d.ts | 1 + 7 files changed, 340 insertions(+), 237 deletions(-) create mode 100644 src/main/sys/interface.ts create mode 100644 src/renderer/src/components/mihomo/interface-modal.tsx diff --git a/changelog.md b/changelog.md index 4db6d2f..aaff616 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,4 @@ ### New Features - 添加覆写脚本执行日志功能 +- 支持查看局域网网络信息 diff --git a/src/main/sys/interface.ts b/src/main/sys/interface.ts new file mode 100644 index 0000000..36744e4 --- /dev/null +++ b/src/main/sys/interface.ts @@ -0,0 +1,5 @@ +import os from 'os' + +export function getInterfaces(): NodeJS.Dict { + return os.networkInterfaces() +} diff --git a/src/main/utils/ipc.ts b/src/main/utils/ipc.ts index 40d9807..9721497 100644 --- a/src/main/utils/ipc.ts +++ b/src/main/utils/ipc.ts @@ -51,6 +51,7 @@ import { getFilePath, openUWPTool, readTextFile, setupFirewall } from '../sys/mi import { getRuntimeConfig, getRuntimeConfigStr } from '../core/factory' import { isPortable, setPortable } from './dirs' import { listWebdavBackups, webdavBackup, webdavRestore } from '../resolve/backup' +import { getInterfaces } from '../sys/interface' function ipcErrorWrapper( // eslint-disable-next-line @typescript-eslint/no-explicit-any fn: (...args: any[]) => Promise // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -139,6 +140,7 @@ export function registerIpcMainHandlers(): void { ipcMain.handle('platform', () => process.platform) ipcMain.handle('openUWPTool', ipcErrorWrapper(openUWPTool)) ipcMain.handle('setupFirewall', ipcErrorWrapper(setupFirewall)) + ipcMain.handle('getInterfaces', getInterfaces) ipcMain.handle('setPortable', (_e, portable) => ipcErrorWrapper(setPortable)(portable)) ipcMain.handle('isPortable', isPortable) ipcMain.handle('webdavBackup', ipcErrorWrapper(webdavBackup)) diff --git a/src/renderer/src/components/mihomo/interface-modal.tsx b/src/renderer/src/components/mihomo/interface-modal.tsx new file mode 100644 index 0000000..6bae34b --- /dev/null +++ b/src/renderer/src/components/mihomo/interface-modal.tsx @@ -0,0 +1,67 @@ +import { + Modal, + ModalContent, + ModalHeader, + ModalBody, + ModalFooter, + Button, + Snippet +} from '@nextui-org/react' +import React, { useEffect, useState } from 'react' +import { getInterfaces } from '@renderer/utils/ipc' +interface Props { + onClose: () => void +} +const InterfaceModal: React.FC = (props) => { + const { onClose } = props + const [info, setInfo] = useState>({}) + const getInfo = async (): Promise => { + setInfo(await getInterfaces()) + } + + useEffect(() => { + getInfo() + }, []) + + return ( + + + 网络信息 + + {Object.entries(info).map(([key, value]) => { + return ( +
+

{key}

+ {value.map((v) => { + return ( +
+
+ {v.family} + + {v.address} + +
+
+ ) + })} +
+ ) + })} +
+ + + +
+
+ ) +} + +export default InterfaceModal diff --git a/src/renderer/src/pages/mihomo.tsx b/src/renderer/src/pages/mihomo.tsx index 6a83825..c39f4eb 100644 --- a/src/renderer/src/pages/mihomo.tsx +++ b/src/renderer/src/pages/mihomo.tsx @@ -5,8 +5,10 @@ import SettingItem from '@renderer/components/base/base-setting-item' import { useAppConfig } from '@renderer/hooks/use-app-config' import { useControledMihomoConfig } from '@renderer/hooks/use-controled-mihomo-config' import { platform } from '@renderer/utils/init' +import { FaNetworkWired } from 'react-icons/fa' import { restartCore } from '@renderer/utils/ipc' import React, { useState } from 'react' +import InterfaceModal from '@renderer/components/mihomo/interface-modal' const CoreMap = { mihomo: '稳定版', @@ -43,128 +45,47 @@ const Mihomo: React.FC = () => { const [externalControllerInput, setExternalControllerInput] = useState(externalController) const [secretInput, setSecretInput] = useState(secret) + const [lanOpen, setLanOpen] = useState(false) + const onChangeNeedRestart = async (patch: Partial): Promise => { await patchControledMihomoConfig(patch) await restartCore() } return ( - - - - - - -
- {mixedPortInput !== mixedPort && ( - - )} - - + {lanOpen && setLanOpen(false)} />} + + + + { - setSocksPortInput(parseInt(v)) + selectedKeys={new Set([core])} + onSelectionChange={async (v) => { + try { + await patchAppConfig({ core: v.currentKey as 'mihomo' | 'mihomo-alpha' }) + await restartCore() + } catch (e) { + alert(e) + } finally { + PubSub.publish('mihomo-core-changed') + } }} - /> -
-
- -
- {httpPortInput !== httpPort && ( - - )} - - { - setHttpPortInput(parseInt(v)) - }} - /> -
-
- {platform !== 'win32' && ( - + > + {CoreMap['mihomo']} + {CoreMap['mihomo-alpha']} + + +
- {redirPortInput !== redirPort && ( + {mixedPortInput !== mixedPort && (
- )} - {platform === 'linux' && ( - +
- {tproxyPortInput !== tproxyPort && ( + {socksPortInput !== socksPort && (
- )} - -
- {externalControllerInput !== externalController && ( - - )} + +
+ {httpPortInput !== httpPort && ( + + )} - { + setHttpPortInput(parseInt(v)) + }} + /> +
+
+ {platform !== 'win32' && ( + +
+ {redirPortInput !== redirPort && ( + + )} + + { + setRedirPortInput(parseInt(v)) + }} + /> +
+
+ )} + {platform === 'linux' && ( + +
+ {tproxyPortInput !== tproxyPort && ( + + )} + + { + setTproxyPortInput(parseInt(v)) + }} + /> +
+
+ )} + +
+ {externalControllerInput !== externalController && ( + + )} + + { + setExternalControllerInput(v) + }} + /> +
+
+ +
+ {secretInput !== secret && ( + + )} + + { + setSecretInput(v) + }} + /> +
+
+ + { - setExternalControllerInput(v) + onChangeNeedRestart({ ipv6: v }) }} /> -
-
- -
- {secretInput !== secret && ( + + { - onChangeNeedRestart({ secret: secretInput }) + setLanOpen(true) }} > - 确认 + - )} - - + { - setSecretInput(v) + onChangeNeedRestart({ 'allow-lan': v }) }} /> -
-
- - { - onChangeNeedRestart({ ipv6: v }) - }} - /> - - - { - onChangeNeedRestart({ 'allow-lan': v }) - }} - /> - - - { - onChangeNeedRestart({ 'unified-delay': v }) - }} - /> - - - { - onChangeNeedRestart({ 'tcp-concurrent': v }) - }} - /> - - - { - onChangeNeedRestart({ profile: { 'store-selected': v } }) - }} - /> - - - { - onChangeNeedRestart({ profile: { 'store-fake-ip': v } }) - }} - /> - - - - - - - -
-
+ + + { + onChangeNeedRestart({ 'unified-delay': v }) + }} + /> + + + { + onChangeNeedRestart({ 'tcp-concurrent': v }) + }} + /> + + + { + onChangeNeedRestart({ profile: { 'store-selected': v } }) + }} + /> + + + { + onChangeNeedRestart({ profile: { 'store-fake-ip': v } }) + }} + /> + + + + + + + + + + ) } diff --git a/src/renderer/src/utils/ipc.ts b/src/renderer/src/utils/ipc.ts index 61bcc73..0803ce9 100644 --- a/src/renderer/src/utils/ipc.ts +++ b/src/renderer/src/utils/ipc.ts @@ -251,6 +251,10 @@ export async function setupFirewall(): Promise { return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('setupFirewall')) } +export async function getInterfaces(): Promise> { + return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('getInterfaces')) +} + export async function setPortable(portable: boolean): Promise { return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('setPortable', portable)) } diff --git a/src/shared/types.d.ts b/src/shared/types.d.ts index 663a6f8..0417dcd 100644 --- a/src/shared/types.d.ts +++ b/src/shared/types.d.ts @@ -36,6 +36,7 @@ type MihomoProxyType = type TunStack = 'gvisor' | 'mixed' | 'system' type FindProcessMode = 'off' | 'strict' | 'always' type DnsMode = 'normal' | 'fake-ip' | 'redir-host' +type NetworkInterfaceInfo = os.NetworkInterfaceInfo interface IAppVersion { version: string