mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2025-12-27 05:00:30 +08:00
memory and mihomo setting
This commit is contained in:
parent
e456259fcb
commit
5ece0adcd6
@ -1,6 +1,7 @@
|
|||||||
import { controledMihomoConfigPath } from '../utils/dirs'
|
import { controledMihomoConfigPath } from '../utils/dirs'
|
||||||
import yaml from 'yaml'
|
import yaml from 'yaml'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
|
import { getAxios } from '../core/mihomoApi'
|
||||||
|
|
||||||
export let controledMihomoConfig: Partial<IMihomoConfig> // mihomo.yaml
|
export let controledMihomoConfig: Partial<IMihomoConfig> // mihomo.yaml
|
||||||
|
|
||||||
@ -13,5 +14,8 @@ export function getControledMihomoConfig(force = false): Partial<IMihomoConfig>
|
|||||||
|
|
||||||
export function setControledMihomoConfig(patch: Partial<IMihomoConfig>): void {
|
export function setControledMihomoConfig(patch: Partial<IMihomoConfig>): void {
|
||||||
controledMihomoConfig = Object.assign(controledMihomoConfig, patch)
|
controledMihomoConfig = Object.assign(controledMihomoConfig, patch)
|
||||||
|
if (patch['external-controller'] || patch.secret) {
|
||||||
|
getAxios(true)
|
||||||
|
}
|
||||||
fs.writeFileSync(controledMihomoConfigPath(), yaml.stringify(controledMihomoConfig))
|
fs.writeFileSync(controledMihomoConfigPath(), yaml.stringify(controledMihomoConfig))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import { window } from '..'
|
|||||||
|
|
||||||
let axiosIns: AxiosInstance = null!
|
let axiosIns: AxiosInstance = null!
|
||||||
let mihomoTrafficWs: WebSocket | null = null
|
let mihomoTrafficWs: WebSocket | null = null
|
||||||
|
let mihomoMemoryWs: WebSocket | null = null
|
||||||
let mihomoLogsWs: WebSocket | null = null
|
let mihomoLogsWs: WebSocket | null = null
|
||||||
|
|
||||||
export const getAxios = async (force: boolean = false): Promise<AxiosInstance> => {
|
export const getAxios = async (force: boolean = false): Promise<AxiosInstance> => {
|
||||||
@ -111,6 +112,45 @@ const mihomoTraffic = (): void => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const startMihomoMemory = (): void => {
|
||||||
|
mihomoMemory()
|
||||||
|
}
|
||||||
|
|
||||||
|
export const stopMihomoMemory = (): void => {
|
||||||
|
if (mihomoMemoryWs) {
|
||||||
|
mihomoMemoryWs.removeAllListeners()
|
||||||
|
if (mihomoMemoryWs.readyState === WebSocket.OPEN) {
|
||||||
|
mihomoMemoryWs.close()
|
||||||
|
}
|
||||||
|
mihomoMemoryWs = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mihomoMemory = (): void => {
|
||||||
|
let server = getControledMihomoConfig()['external-controller']
|
||||||
|
const secret = getControledMihomoConfig().secret ?? ''
|
||||||
|
if (server?.startsWith(':')) server = `127.0.0.1${server}`
|
||||||
|
stopMihomoMemory()
|
||||||
|
|
||||||
|
mihomoMemoryWs = new WebSocket(`ws://${server}/memory?secret=${secret}`)
|
||||||
|
|
||||||
|
mihomoMemoryWs.onmessage = (e): void => {
|
||||||
|
const data = e.data as string
|
||||||
|
window?.webContents.send('mihomoMemory', JSON.parse(data) as IMihomoMemoryInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
mihomoMemoryWs.onclose = (): void => {
|
||||||
|
mihomoMemory()
|
||||||
|
}
|
||||||
|
|
||||||
|
mihomoMemoryWs.onerror = (): void => {
|
||||||
|
if (mihomoMemoryWs) {
|
||||||
|
mihomoMemoryWs.close()
|
||||||
|
mihomoMemoryWs = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const startMihomoLogs = (): void => {
|
export const startMihomoLogs = (): void => {
|
||||||
mihomoLogs()
|
mihomoLogs()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,12 @@ import { createTray } from './core/tray'
|
|||||||
import { init } from './resolve/init'
|
import { init } from './resolve/init'
|
||||||
import { getAppConfig } from './config'
|
import { getAppConfig } from './config'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import { startMihomoTraffic, stopMihomoTraffic } from './core/mihomoApi'
|
import {
|
||||||
|
startMihomoMemory,
|
||||||
|
startMihomoTraffic,
|
||||||
|
stopMihomoMemory,
|
||||||
|
stopMihomoTraffic
|
||||||
|
} from './core/mihomoApi'
|
||||||
|
|
||||||
export let window: BrowserWindow | null = null
|
export let window: BrowserWindow | null = null
|
||||||
|
|
||||||
@ -93,10 +98,12 @@ function createWindow(): void {
|
|||||||
|
|
||||||
window.on('show', () => {
|
window.on('show', () => {
|
||||||
startMihomoTraffic()
|
startMihomoTraffic()
|
||||||
|
startMihomoMemory()
|
||||||
})
|
})
|
||||||
|
|
||||||
window.on('close', (event) => {
|
window.on('close', (event) => {
|
||||||
stopMihomoTraffic()
|
stopMihomoTraffic()
|
||||||
|
stopMihomoMemory()
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
window?.hide()
|
window?.hide()
|
||||||
})
|
})
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import React from 'react'
|
|||||||
|
|
||||||
const colorMap = {
|
const colorMap = {
|
||||||
error: 'danger',
|
error: 'danger',
|
||||||
warn: 'warning',
|
warning: 'warning',
|
||||||
info: 'primary',
|
info: 'primary',
|
||||||
debug: 'default'
|
debug: 'default'
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,31 +1,28 @@
|
|||||||
import {
|
import { Button, Card, CardBody, CardFooter } from '@nextui-org/react'
|
||||||
Button,
|
import { calcTraffic } from '@renderer/utils/calc'
|
||||||
Card,
|
|
||||||
CardBody,
|
|
||||||
CardFooter,
|
|
||||||
Dropdown,
|
|
||||||
DropdownItem,
|
|
||||||
DropdownMenu,
|
|
||||||
DropdownTrigger
|
|
||||||
} from '@nextui-org/react'
|
|
||||||
import { useAppConfig } from '@renderer/hooks/use-config'
|
|
||||||
import { mihomoVersion, restartCore } from '@renderer/utils/ipc'
|
import { mihomoVersion, restartCore } from '@renderer/utils/ipc'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
import { IoMdRefresh } from 'react-icons/io'
|
import { IoMdRefresh } from 'react-icons/io'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import useSWR from 'swr'
|
import useSWR from 'swr'
|
||||||
|
|
||||||
const CoreMap = {
|
|
||||||
mihomo: '稳定版',
|
|
||||||
'mihomo-alpha': '预览版'
|
|
||||||
}
|
|
||||||
|
|
||||||
const MihomoCoreCard: React.FC = () => {
|
const MihomoCoreCard: React.FC = () => {
|
||||||
const { data: version, mutate } = useSWR('mihomoVersion', mihomoVersion)
|
const { data: version } = useSWR('mihomoVersion', mihomoVersion)
|
||||||
const { appConfig, patchAppConfig } = useAppConfig()
|
|
||||||
const { core } = appConfig || {}
|
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const match = location.pathname.includes('/mihomo')
|
const match = location.pathname.includes('/mihomo')
|
||||||
|
|
||||||
|
const [mem, setMem] = useState(0)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.electron.ipcRenderer.on('mihomoMemory', (_e, info: IMihomoMemoryInfo) => {
|
||||||
|
setMem(info.inuse)
|
||||||
|
})
|
||||||
|
return (): void => {
|
||||||
|
window.electron.ipcRenderer.removeAllListeners('mihomoMemory')
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
fullWidth
|
fullWidth
|
||||||
@ -38,6 +35,7 @@ const MihomoCoreCard: React.FC = () => {
|
|||||||
<h3 className="select-none text-md font-bold leading-[32px]">
|
<h3 className="select-none text-md font-bold leading-[32px]">
|
||||||
{version?.version ?? '-'}
|
{version?.version ?? '-'}
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
isIconOnly
|
isIconOnly
|
||||||
size="sm"
|
size="sm"
|
||||||
@ -52,26 +50,10 @@ const MihomoCoreCard: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</CardBody>
|
</CardBody>
|
||||||
<CardFooter className="pt-1">
|
<CardFooter className="pt-1">
|
||||||
<Dropdown>
|
<div className="flex justify-between w-full">
|
||||||
<DropdownTrigger>
|
<h4 className="select-none text-md font-bold">内核设置</h4>
|
||||||
<Button fullWidth size="sm" variant="solid">
|
<h4 className="select-none text-md">{calcTraffic(mem)}</h4>
|
||||||
{core ? CoreMap[core] : ''}
|
</div>
|
||||||
</Button>
|
|
||||||
</DropdownTrigger>
|
|
||||||
<DropdownMenu
|
|
||||||
onAction={async (key) => {
|
|
||||||
await patchAppConfig({ core: key as 'mihomo' | 'mihomo-alpha' })
|
|
||||||
await restartCore()
|
|
||||||
mutate()
|
|
||||||
setTimeout(() => {
|
|
||||||
mutate()
|
|
||||||
}, 200)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<DropdownItem key="mihomo">{CoreMap['mihomo']}</DropdownItem>
|
|
||||||
<DropdownItem key="mihomo-alpha">{CoreMap['mihomo-alpha']}</DropdownItem>
|
|
||||||
</DropdownMenu>
|
|
||||||
</Dropdown>
|
|
||||||
</CardFooter>
|
</CardFooter>
|
||||||
</Card>
|
</Card>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,40 +1,114 @@
|
|||||||
import { Input, Select, SelectItem, Switch } from '@nextui-org/react'
|
import { Button, Input, Select, SelectItem, Switch } from '@nextui-org/react'
|
||||||
import BasePage from '@renderer/components/base/base-page'
|
import BasePage from '@renderer/components/base/base-page'
|
||||||
import SettingCard from '@renderer/components/base/base-setting-card'
|
import SettingCard from '@renderer/components/base/base-setting-card'
|
||||||
import SettingItem from '@renderer/components/base/base-setting-item'
|
import SettingItem from '@renderer/components/base/base-setting-item'
|
||||||
import { useControledMihomoConfig } from '@renderer/hooks/use-controled-mihomo-config'
|
import { useControledMihomoConfig } from '@renderer/hooks/use-controled-mihomo-config'
|
||||||
import { patchMihomoConfig } from '@renderer/utils/ipc'
|
import { patchMihomoConfig, restartCore } from '@renderer/utils/ipc'
|
||||||
import React from 'react'
|
import React, { useState } from 'react'
|
||||||
|
|
||||||
const Mihomo: React.FC = () => {
|
const Mihomo: React.FC = () => {
|
||||||
const { controledMihomoConfig, patchControledMihomoConfig } = useControledMihomoConfig()
|
const { controledMihomoConfig, patchControledMihomoConfig } = useControledMihomoConfig()
|
||||||
const {
|
const {
|
||||||
ipv6,
|
ipv6,
|
||||||
|
'external-controller': externalController,
|
||||||
|
secret,
|
||||||
'log-level': level = 'info',
|
'log-level': level = 'info',
|
||||||
'allow-lan': lan,
|
'allow-lan': lan,
|
||||||
'mixed-port': mixedPort = 7890
|
'mixed-port': mixedPort = 7890
|
||||||
} = controledMihomoConfig || {}
|
} = controledMihomoConfig || {}
|
||||||
|
|
||||||
|
const [mixedPortInput, setMixedPortInput] = useState(mixedPort)
|
||||||
|
const [externalControllerInput, setExternalControllerInput] = useState(externalController)
|
||||||
|
const [secretInput, setSecretInput] = useState(secret)
|
||||||
|
|
||||||
const onChange = async (patch: Partial<IMihomoConfig>): Promise<void> => {
|
const onChange = async (patch: Partial<IMihomoConfig>): Promise<void> => {
|
||||||
await patchControledMihomoConfig(patch)
|
await patchControledMihomoConfig(patch)
|
||||||
await patchMihomoConfig(patch)
|
await patchMihomoConfig(patch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onChangeNeedRestart = async (patch: Partial<IMihomoConfig>): Promise<void> => {
|
||||||
|
await patchControledMihomoConfig(patch)
|
||||||
|
await restartCore()
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BasePage title="内核设置">
|
<BasePage title="内核设置">
|
||||||
<SettingCard>
|
<SettingCard>
|
||||||
<SettingItem title="混合端口" divider>
|
<SettingItem title="混合端口" divider>
|
||||||
|
<div className="flex">
|
||||||
|
{mixedPortInput !== mixedPort && (
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
color="primary"
|
||||||
|
className="mr-2"
|
||||||
|
onPress={() => {
|
||||||
|
onChangeNeedRestart({ 'mixed-port': mixedPortInput })
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
确认
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
size="sm"
|
size="sm"
|
||||||
type="number"
|
type="number"
|
||||||
className="w-[100px]"
|
className="w-[100px]"
|
||||||
value={mixedPort.toString()}
|
value={mixedPortInput.toString()}
|
||||||
max={65535}
|
max={65535}
|
||||||
min={0}
|
min={0}
|
||||||
onValueChange={(v) => {
|
onValueChange={(v) => {
|
||||||
onChange({ 'mixed-port': parseInt(v) })
|
setMixedPortInput(parseInt(v))
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
</SettingItem>
|
||||||
|
<SettingItem title="外部控制" divider>
|
||||||
|
<div className="flex">
|
||||||
|
{externalControllerInput !== externalController && (
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
color="primary"
|
||||||
|
className="mr-2"
|
||||||
|
onPress={() => {
|
||||||
|
onChangeNeedRestart({ 'external-controller': externalControllerInput })
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
确认
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Input
|
||||||
|
size="sm"
|
||||||
|
value={externalControllerInput}
|
||||||
|
onValueChange={(v) => {
|
||||||
|
setExternalControllerInput(v)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</SettingItem>
|
||||||
|
<SettingItem title="外部控制访问密钥" divider>
|
||||||
|
<div className="flex">
|
||||||
|
{secretInput !== secret && (
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
color="primary"
|
||||||
|
className="mr-2"
|
||||||
|
onPress={() => {
|
||||||
|
onChangeNeedRestart({ secret: secretInput })
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
确认
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Input
|
||||||
|
size="sm"
|
||||||
|
value={secretInput}
|
||||||
|
onValueChange={(v) => {
|
||||||
|
setSecretInput(v)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</SettingItem>
|
</SettingItem>
|
||||||
<SettingItem title="IPv6" divider>
|
<SettingItem title="IPv6" divider>
|
||||||
<Switch
|
<Switch
|
||||||
|
|||||||
@ -1,21 +1,21 @@
|
|||||||
export function calcTraffic(bit: number): string {
|
export function calcTraffic(byte: number): string {
|
||||||
if (bit < 1024) return `${bit} B`
|
if (byte < 1024) return `${byte} B`
|
||||||
bit /= 1024
|
byte /= 1024
|
||||||
if (bit < 1024) return `${bit.toFixed(2)} KB`
|
if (byte < 1024) return `${byte.toFixed(2)} KB`
|
||||||
bit /= 1024
|
byte /= 1024
|
||||||
if (bit < 1024) return `${bit.toFixed(2)} MB`
|
if (byte < 1024) return `${byte.toFixed(2)} MB`
|
||||||
bit /= 1024
|
byte /= 1024
|
||||||
if (bit < 1024) return `${bit.toFixed(2)} GB`
|
if (byte < 1024) return `${byte.toFixed(2)} GB`
|
||||||
bit /= 1024
|
byte /= 1024
|
||||||
if (bit < 1024) return `${bit.toFixed(2)} TB`
|
if (byte < 1024) return `${byte.toFixed(2)} TB`
|
||||||
bit /= 1024
|
byte /= 1024
|
||||||
if (bit < 1024) return `${bit.toFixed(2)} PB`
|
if (byte < 1024) return `${byte.toFixed(2)} PB`
|
||||||
bit /= 1024
|
byte /= 1024
|
||||||
if (bit < 1024) return `${bit.toFixed(2)} EB`
|
if (byte < 1024) return `${byte.toFixed(2)} EB`
|
||||||
bit /= 1024
|
byte /= 1024
|
||||||
if (bit < 1024) return `${bit.toFixed(2)} ZB`
|
if (byte < 1024) return `${byte.toFixed(2)} ZB`
|
||||||
bit /= 1024
|
byte /= 1024
|
||||||
return `${bit.toFixed(2)} YB`
|
return `${byte.toFixed(2)} YB`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calcPercent(
|
export function calcPercent(
|
||||||
|
|||||||
5
src/shared/types.d.ts
vendored
5
src/shared/types.d.ts
vendored
@ -14,6 +14,11 @@ interface IMihomoTrafficInfo {
|
|||||||
down: number
|
down: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IMihomoMemoryInfo {
|
||||||
|
inuse: number
|
||||||
|
oslimit: number
|
||||||
|
}
|
||||||
|
|
||||||
interface IMihomoLogInfo {
|
interface IMihomoLogInfo {
|
||||||
type: LogLevel
|
type: LogLevel
|
||||||
payload: string
|
payload: string
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user