memory and mihomo setting

This commit is contained in:
pompurin404 2024-08-03 20:08:28 +08:00
parent e456259fcb
commit 5ece0adcd6
No known key found for this signature in database
8 changed files with 185 additions and 73 deletions

View File

@ -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))
} }

View File

@ -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()
} }

View File

@ -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()
}) })

View File

@ -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'
} }

View File

@ -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>
) )

View File

@ -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

View File

@ -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(

View File

@ -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