mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2025-12-27 21:20:29 +08:00
optimized rule page performance
This commit is contained in:
parent
704a322c25
commit
449597f941
@ -2,10 +2,6 @@
|
|||||||
|
|
||||||
- 1.2.x YAML覆写语法有所变动,请更新后参考文档进行修改
|
- 1.2.x YAML覆写语法有所变动,请更新后参考文档进行修改
|
||||||
|
|
||||||
### New Features
|
### Performance Improvements
|
||||||
|
|
||||||
- 支持使用外部编辑器打开文件
|
- 优化规则/代理页面性能
|
||||||
- 支持新建订阅/覆写
|
|
||||||
- 添加窗口置顶按钮
|
|
||||||
- 允许禁用系统标题栏
|
|
||||||
- 重写连接页面
|
|
||||||
|
|||||||
@ -8,17 +8,22 @@ import {
|
|||||||
} from '../config'
|
} from '../config'
|
||||||
import { mihomoWorkConfigPath, overridePath } from '../utils/dirs'
|
import { mihomoWorkConfigPath, overridePath } from '../utils/dirs'
|
||||||
import yaml from 'yaml'
|
import yaml from 'yaml'
|
||||||
import { readFile, writeFile } from 'fs/promises'
|
import { writeFile } from 'fs/promises'
|
||||||
import { deepMerge } from '../utils/merge'
|
import { deepMerge } from '../utils/merge'
|
||||||
import vm from 'vm'
|
import vm from 'vm'
|
||||||
import { writeFileSync } from 'fs'
|
import { writeFileSync } from 'fs'
|
||||||
|
|
||||||
|
let runtimeConfigStr: string
|
||||||
|
let runtimeConfig: IMihomoConfig
|
||||||
|
|
||||||
export async function generateProfile(): Promise<void> {
|
export async function generateProfile(): Promise<void> {
|
||||||
const { current } = await getProfileConfig()
|
const { current } = await getProfileConfig()
|
||||||
const currentProfile = await overrideProfile(current, await getProfile(current))
|
const currentProfile = await overrideProfile(current, await getProfile(current))
|
||||||
const controledMihomoConfig = await getControledMihomoConfig()
|
const controledMihomoConfig = await getControledMihomoConfig()
|
||||||
const profile = deepMerge(currentProfile, controledMihomoConfig)
|
const profile = deepMerge(currentProfile, controledMihomoConfig)
|
||||||
await writeFile(mihomoWorkConfigPath(), yaml.stringify(profile))
|
runtimeConfig = profile
|
||||||
|
runtimeConfigStr = yaml.stringify(profile)
|
||||||
|
await writeFile(mihomoWorkConfigPath(), runtimeConfigStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function overrideProfile(
|
async function overrideProfile(
|
||||||
@ -87,9 +92,9 @@ function runOverrideScript(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getRuntimeConfigStr(): Promise<string> {
|
export async function getRuntimeConfigStr(): Promise<string> {
|
||||||
return await readFile(mihomoWorkConfigPath(), 'utf8')
|
return runtimeConfigStr
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getRuntimeConfig(): Promise<IMihomoConfig> {
|
export async function getRuntimeConfig(): Promise<IMihomoConfig> {
|
||||||
return yaml.parse(await getRuntimeConfigStr())
|
return runtimeConfig
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,6 +60,7 @@ export async function startCore(): Promise<void> {
|
|||||||
}
|
}
|
||||||
if (data.toString().includes('RESTful API listening at')) {
|
if (data.toString().includes('RESTful API listening at')) {
|
||||||
await startMihomoTraffic()
|
await startMihomoTraffic()
|
||||||
|
mainWindow?.webContents.send('coreRestart')
|
||||||
retry = 10
|
retry = 10
|
||||||
resolve()
|
resolve()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -71,8 +71,11 @@ export const mihomoRules = async (): Promise<IMihomoRulesInfo> => {
|
|||||||
|
|
||||||
export const mihomoProxies = async (): Promise<IMihomoProxies> => {
|
export const mihomoProxies = async (): Promise<IMihomoProxies> => {
|
||||||
const instance = await getAxios()
|
const instance = await getAxios()
|
||||||
|
const proxies = (await instance.get('/proxies')) as IMihomoProxies
|
||||||
return await instance.get('/proxies')
|
if (!proxies.proxies['GLOBAL']) {
|
||||||
|
throw new Error('GLOBAL proxy not found')
|
||||||
|
}
|
||||||
|
return proxies
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mihomoGroups = async (): Promise<IMihomoMixedGroup[]> => {
|
export const mihomoGroups = async (): Promise<IMihomoMixedGroup[]> => {
|
||||||
|
|||||||
@ -3,14 +3,13 @@ import { useSortable } from '@dnd-kit/sortable'
|
|||||||
import { CSS } from '@dnd-kit/utilities'
|
import { CSS } from '@dnd-kit/utilities'
|
||||||
import { LuGroup } from 'react-icons/lu'
|
import { LuGroup } from 'react-icons/lu'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import useSWR from 'swr'
|
import { useGroups } from '@renderer/hooks/use-groups'
|
||||||
import { mihomoGroups } from '@renderer/utils/ipc'
|
|
||||||
|
|
||||||
const ProxyCard: React.FC = () => {
|
const ProxyCard: React.FC = () => {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const match = location.pathname.includes('/proxies')
|
const match = location.pathname.includes('/proxies')
|
||||||
const { data: groups = [] } = useSWR('mihomoGroups', mihomoGroups)
|
const { groups = [] } = useGroups()
|
||||||
const {
|
const {
|
||||||
attributes,
|
attributes,
|
||||||
listeners,
|
listeners,
|
||||||
|
|||||||
@ -1,16 +1,15 @@
|
|||||||
import { Button, Card, CardBody, CardFooter, Chip } from '@nextui-org/react'
|
import { Button, Card, CardBody, CardFooter, Chip } from '@nextui-org/react'
|
||||||
import { mihomoRules } from '@renderer/utils/ipc'
|
|
||||||
import { MdOutlineAltRoute } from 'react-icons/md'
|
import { MdOutlineAltRoute } from 'react-icons/md'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import { useSortable } from '@dnd-kit/sortable'
|
import { useSortable } from '@dnd-kit/sortable'
|
||||||
import { CSS } from '@dnd-kit/utilities'
|
import { CSS } from '@dnd-kit/utilities'
|
||||||
import useSWR from 'swr'
|
import { useRules } from '@renderer/hooks/use-rules'
|
||||||
|
|
||||||
const RuleCard: React.FC = () => {
|
const RuleCard: React.FC = () => {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const match = location.pathname.includes('/rules')
|
const match = location.pathname.includes('/rules')
|
||||||
const { data: rules } = useSWR<IMihomoRulesInfo>('mihomoRules', mihomoRules)
|
const { rules } = useRules()
|
||||||
const {
|
const {
|
||||||
attributes,
|
attributes,
|
||||||
listeners,
|
listeners,
|
||||||
|
|||||||
36
src/renderer/src/hooks/use-groups.tsx
Normal file
36
src/renderer/src/hooks/use-groups.tsx
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import React, { createContext, useContext, ReactNode } from 'react'
|
||||||
|
import useSWR from 'swr'
|
||||||
|
import { mihomoGroups } from '@renderer/utils/ipc'
|
||||||
|
|
||||||
|
interface GroupsContextType {
|
||||||
|
groups: IMihomoMixedGroup[] | undefined
|
||||||
|
mutate: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const GroupsContext = createContext<GroupsContextType | undefined>(undefined)
|
||||||
|
|
||||||
|
export const GroupsProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
|
||||||
|
const { data: groups, mutate } = useSWR<IMihomoMixedGroup[]>('mihomoGroups', mihomoGroups, {
|
||||||
|
errorRetryInterval: 200,
|
||||||
|
errorRetryCount: 10
|
||||||
|
})
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
window.electron.ipcRenderer.on('coreRestart', () => {
|
||||||
|
mutate()
|
||||||
|
})
|
||||||
|
return (): void => {
|
||||||
|
window.electron.ipcRenderer.removeAllListeners('coreRestart')
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return <GroupsContext.Provider value={{ groups, mutate }}>{children}</GroupsContext.Provider>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useGroups = (): GroupsContextType => {
|
||||||
|
const context = useContext(GroupsContext)
|
||||||
|
if (context === undefined) {
|
||||||
|
throw new Error('useGroups must be used within an GroupsProvider')
|
||||||
|
}
|
||||||
|
return context
|
||||||
|
}
|
||||||
47
src/renderer/src/hooks/use-rules.tsx
Normal file
47
src/renderer/src/hooks/use-rules.tsx
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import React, { createContext, useContext, ReactNode } from 'react'
|
||||||
|
import useSWR from 'swr'
|
||||||
|
import { mihomoRules } from '@renderer/utils/ipc'
|
||||||
|
|
||||||
|
interface RulesContextType {
|
||||||
|
rules: IMihomoRulesInfo | undefined
|
||||||
|
mutate: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const RulesContext = createContext<RulesContextType | undefined>(undefined)
|
||||||
|
let emptyRetry = 10
|
||||||
|
|
||||||
|
export const RulesProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
|
||||||
|
const { data: rules, mutate } = useSWR<IMihomoRulesInfo>('mihomoRules', mihomoRules, {
|
||||||
|
errorRetryInterval: 200,
|
||||||
|
errorRetryCount: 10,
|
||||||
|
onSuccess: (data) => {
|
||||||
|
if (data.rules.length === 0 && emptyRetry) {
|
||||||
|
emptyRetry--
|
||||||
|
setTimeout(() => {
|
||||||
|
mutate()
|
||||||
|
}, 200)
|
||||||
|
} else {
|
||||||
|
emptyRetry = 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
window.electron.ipcRenderer.on('coreRestart', () => {
|
||||||
|
mutate()
|
||||||
|
})
|
||||||
|
return (): void => {
|
||||||
|
window.electron.ipcRenderer.removeAllListeners('coreRestart')
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return <RulesContext.Provider value={{ rules, mutate }}>{children}</RulesContext.Provider>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useRules = (): RulesContextType => {
|
||||||
|
const context = useContext(RulesContext)
|
||||||
|
if (context === undefined) {
|
||||||
|
throw new Error('useRules must be used within an RulesProvider')
|
||||||
|
}
|
||||||
|
return context
|
||||||
|
}
|
||||||
@ -12,6 +12,8 @@ import { AppConfigProvider } from './hooks/use-app-config'
|
|||||||
import { ControledMihomoConfigProvider } from './hooks/use-controled-mihomo-config'
|
import { ControledMihomoConfigProvider } from './hooks/use-controled-mihomo-config'
|
||||||
import { OverrideConfigProvider } from './hooks/use-override-config'
|
import { OverrideConfigProvider } from './hooks/use-override-config'
|
||||||
import { ProfileConfigProvider } from './hooks/use-profile-config'
|
import { ProfileConfigProvider } from './hooks/use-profile-config'
|
||||||
|
import { RulesProvider } from './hooks/use-rules'
|
||||||
|
import { GroupsProvider } from './hooks/use-groups'
|
||||||
|
|
||||||
init().then(() => {
|
init().then(() => {
|
||||||
document.addEventListener('keydown', (e) => {
|
document.addEventListener('keydown', (e) => {
|
||||||
@ -53,7 +55,11 @@ init().then(() => {
|
|||||||
<ControledMihomoConfigProvider>
|
<ControledMihomoConfigProvider>
|
||||||
<ProfileConfigProvider>
|
<ProfileConfigProvider>
|
||||||
<OverrideConfigProvider>
|
<OverrideConfigProvider>
|
||||||
|
<GroupsProvider>
|
||||||
|
<RulesProvider>
|
||||||
<App />
|
<App />
|
||||||
|
</RulesProvider>
|
||||||
|
</GroupsProvider>
|
||||||
</OverrideConfigProvider>
|
</OverrideConfigProvider>
|
||||||
</ProfileConfigProvider>
|
</ProfileConfigProvider>
|
||||||
</ControledMihomoConfigProvider>
|
</ControledMihomoConfigProvider>
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import {
|
|||||||
mihomoChangeProxy,
|
mihomoChangeProxy,
|
||||||
mihomoCloseAllConnections,
|
mihomoCloseAllConnections,
|
||||||
mihomoGroupDelay,
|
mihomoGroupDelay,
|
||||||
mihomoGroups,
|
|
||||||
mihomoProxyDelay
|
mihomoProxyDelay
|
||||||
} from '@renderer/utils/ipc'
|
} from '@renderer/utils/ipc'
|
||||||
import { CgDetailsLess, CgDetailsMore } from 'react-icons/cg'
|
import { CgDetailsLess, CgDetailsMore } from 'react-icons/cg'
|
||||||
@ -14,14 +13,14 @@ import { TbCircleLetterD } from 'react-icons/tb'
|
|||||||
import { FaLocationCrosshairs } from 'react-icons/fa6'
|
import { FaLocationCrosshairs } from 'react-icons/fa6'
|
||||||
import { RxLetterCaseCapitalize } from 'react-icons/rx'
|
import { RxLetterCaseCapitalize } from 'react-icons/rx'
|
||||||
import { useEffect, useMemo, useRef, useState } from 'react'
|
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||||
import useSWR from 'swr'
|
|
||||||
import { GroupedVirtuoso, GroupedVirtuosoHandle } from 'react-virtuoso'
|
import { GroupedVirtuoso, GroupedVirtuosoHandle } from 'react-virtuoso'
|
||||||
import ProxyItem from '@renderer/components/proxies/proxy-item'
|
import ProxyItem from '@renderer/components/proxies/proxy-item'
|
||||||
import { IoIosArrowBack } from 'react-icons/io'
|
import { IoIosArrowBack } from 'react-icons/io'
|
||||||
import { MdOutlineSpeed } from 'react-icons/md'
|
import { MdOutlineSpeed } from 'react-icons/md'
|
||||||
|
import { useGroups } from '@renderer/hooks/use-groups'
|
||||||
|
|
||||||
const Proxies: React.FC = () => {
|
const Proxies: React.FC = () => {
|
||||||
const { data: groups = [], mutate } = useSWR('mihomoGroups', mihomoGroups)
|
const { groups = [], mutate } = useGroups()
|
||||||
const { appConfig, patchAppConfig } = useAppConfig()
|
const { appConfig, patchAppConfig } = useAppConfig()
|
||||||
const {
|
const {
|
||||||
proxyDisplayMode = 'simple',
|
proxyDisplayMode = 'simple',
|
||||||
@ -190,7 +189,6 @@ const Proxies: React.FC = () => {
|
|||||||
canvas.height = img.height
|
canvas.height = img.height
|
||||||
ctx?.drawImage(img, 0, 0)
|
ctx?.drawImage(img, 0, 0)
|
||||||
const data = canvas.toDataURL('image/png')
|
const data = canvas.toDataURL('image/png')
|
||||||
console.log('set')
|
|
||||||
localStorage.setItem(groups[index].icon, data)
|
localStorage.setItem(groups[index].icon, data)
|
||||||
}
|
}
|
||||||
img.src = groups[index].icon
|
img.src = groups[index].icon
|
||||||
|
|||||||
@ -3,11 +3,10 @@ import RuleItem from '@renderer/components/rules/rule-item'
|
|||||||
import { Virtuoso } from 'react-virtuoso'
|
import { Virtuoso } from 'react-virtuoso'
|
||||||
import { useMemo, useState } from 'react'
|
import { useMemo, useState } from 'react'
|
||||||
import { Divider, Input } from '@nextui-org/react'
|
import { Divider, Input } from '@nextui-org/react'
|
||||||
import useSWR from 'swr'
|
import { useRules } from '@renderer/hooks/use-rules'
|
||||||
import { mihomoRules } from '@renderer/utils/ipc'
|
|
||||||
|
|
||||||
const Rules: React.FC = () => {
|
const Rules: React.FC = () => {
|
||||||
const { data: rules } = useSWR<IMihomoRulesInfo>('mihomoRules', mihomoRules)
|
const { rules } = useRules()
|
||||||
const [filter, setFilter] = useState('')
|
const [filter, setFilter] = useState('')
|
||||||
|
|
||||||
const filteredRules = useMemo(() => {
|
const filteredRules = useMemo(() => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user