mirror of
https://github.com/pompurin404/mihomo-party.git
synced 2024-11-16 03:32:17 +08:00
view runtime config
This commit is contained in:
parent
1ecaea5667
commit
7f8e1ac386
|
@ -2,6 +2,7 @@ import { controledMihomoConfigPath } from '../utils/dirs'
|
||||||
import yaml from 'yaml'
|
import yaml from 'yaml'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import { getAxios, startMihomoMemory, startMihomoTraffic } from '../core/mihomoApi'
|
import { getAxios, startMihomoMemory, startMihomoTraffic } from '../core/mihomoApi'
|
||||||
|
import { generateProfile } from '../resolve/factory'
|
||||||
|
|
||||||
export let controledMihomoConfig: Partial<IMihomoConfig> // mihomo.yaml
|
export let controledMihomoConfig: Partial<IMihomoConfig> // mihomo.yaml
|
||||||
|
|
||||||
|
@ -34,5 +35,6 @@ export function setControledMihomoConfig(patch: Partial<IMihomoConfig>): void {
|
||||||
startMihomoMemory()
|
startMihomoMemory()
|
||||||
startMihomoTraffic()
|
startMihomoTraffic()
|
||||||
}
|
}
|
||||||
|
generateProfile()
|
||||||
fs.writeFileSync(controledMihomoConfigPath(), yaml.stringify(controledMihomoConfig))
|
fs.writeFileSync(controledMihomoConfigPath(), yaml.stringify(controledMihomoConfig))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
export { getAppConfig, setAppConfig } from './app'
|
export { getAppConfig, setAppConfig } from './app'
|
||||||
export { getControledMihomoConfig, setControledMihomoConfig } from './controledMihomo'
|
export { getControledMihomoConfig, setControledMihomoConfig } from './controledMihomo'
|
||||||
export {
|
export {
|
||||||
getCurrentProfile,
|
getProfile,
|
||||||
getCurrentProfileItem,
|
getCurrentProfileItem,
|
||||||
getProfileItem,
|
getProfileItem,
|
||||||
getProfileConfig,
|
getProfileConfig,
|
||||||
|
|
|
@ -10,7 +10,6 @@ import { dialog } from 'electron'
|
||||||
import { addProfileUpdater } from '../core/profileUpdater'
|
import { addProfileUpdater } from '../core/profileUpdater'
|
||||||
|
|
||||||
let profileConfig: IProfileConfig // profile.yaml
|
let profileConfig: IProfileConfig // profile.yaml
|
||||||
let currentProfile: Partial<IMihomoConfig> // profiles/xxx.yaml
|
|
||||||
|
|
||||||
export function getProfileConfig(force = false): IProfileConfig {
|
export function getProfileConfig(force = false): IProfileConfig {
|
||||||
if (force || !profileConfig) {
|
if (force || !profileConfig) {
|
||||||
|
@ -27,12 +26,10 @@ export function getProfileItem(id: string | undefined): IProfileItem {
|
||||||
export async function changeCurrentProfile(id: string): Promise<void> {
|
export async function changeCurrentProfile(id: string): Promise<void> {
|
||||||
const oldId = getProfileConfig().current
|
const oldId = getProfileConfig().current
|
||||||
profileConfig.current = id
|
profileConfig.current = id
|
||||||
getCurrentProfile(true)
|
|
||||||
try {
|
try {
|
||||||
await startCore()
|
await startCore()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
profileConfig.current = oldId
|
profileConfig.current = oldId
|
||||||
getCurrentProfile(true)
|
|
||||||
} finally {
|
} finally {
|
||||||
window?.webContents.send('profileConfigUpdated')
|
window?.webContents.send('profileConfigUpdated')
|
||||||
fs.writeFileSync(profileConfigPath(), yaml.stringify(profileConfig))
|
fs.writeFileSync(profileConfigPath(), yaml.stringify(profileConfig))
|
||||||
|
@ -180,19 +177,10 @@ export function getProfileStr(id: string): string {
|
||||||
export async function setProfileStr(id: string, content: string): Promise<void> {
|
export async function setProfileStr(id: string, content: string): Promise<void> {
|
||||||
fs.writeFileSync(profilePath(id), content, 'utf-8')
|
fs.writeFileSync(profilePath(id), content, 'utf-8')
|
||||||
if (id === getProfileConfig().current) {
|
if (id === getProfileConfig().current) {
|
||||||
getCurrentProfile(true)
|
|
||||||
await startCore()
|
await startCore()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getCurrentProfile(force = false): Partial<IMihomoConfig> {
|
export function getProfile(id: string): IMihomoConfig {
|
||||||
if (force || !currentProfile) {
|
return yaml.parse(getProfileStr(id))
|
||||||
const current = getProfileConfig().current
|
|
||||||
if (current) {
|
|
||||||
currentProfile = yaml.parse(getProfileStr(current))
|
|
||||||
} else {
|
|
||||||
currentProfile = yaml.parse(getProfileStr('default'))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return currentProfile
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,13 +33,6 @@ export async function mihomoVersion(): Promise<IMihomoVersion> {
|
||||||
})) as IMihomoVersion
|
})) as IMihomoVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mihomoConfig = async (): Promise<IMihomoConfig> => {
|
|
||||||
const instance = await getAxios()
|
|
||||||
return (await instance.get('/configs').catch(() => {
|
|
||||||
return {}
|
|
||||||
})) as IMihomoConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
export const patchMihomoConfig = async (patch: Partial<IMihomoConfig>): Promise<void> => {
|
export const patchMihomoConfig = async (patch: Partial<IMihomoConfig>): Promise<void> => {
|
||||||
const instance = await getAxios()
|
const instance = await getAxios()
|
||||||
return (await instance.patch('/configs', patch).catch((e) => {
|
return (await instance.patch('/configs', patch).catch((e) => {
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import { getControledMihomoConfig, getCurrentProfile } from '../config'
|
import { getControledMihomoConfig, getProfileConfig, getProfile } from '../config'
|
||||||
import { mihomoWorkConfigPath } from '../utils/dirs'
|
import { mihomoWorkConfigPath } from '../utils/dirs'
|
||||||
import yaml from 'yaml'
|
import yaml from 'yaml'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
|
|
||||||
export function generateProfile(): void {
|
export function generateProfile(): void {
|
||||||
const currentProfile = getCurrentProfile()
|
const current = getProfileConfig().current
|
||||||
|
if (!current) return
|
||||||
|
const currentProfile = getProfile(current)
|
||||||
const controledMihomoConfig = getControledMihomoConfig()
|
const controledMihomoConfig = getControledMihomoConfig()
|
||||||
const { tun: profileTun = {} } = currentProfile
|
const { tun: profileTun = {} } = currentProfile
|
||||||
const { tun: controledTun } = controledMihomoConfig
|
const { tun: controledTun } = controledMihomoConfig
|
||||||
|
|
|
@ -3,7 +3,6 @@ import {
|
||||||
mihomoChangeProxy,
|
mihomoChangeProxy,
|
||||||
mihomoCloseAllConnections,
|
mihomoCloseAllConnections,
|
||||||
mihomoCloseConnection,
|
mihomoCloseConnection,
|
||||||
mihomoConfig,
|
|
||||||
mihomoProxies,
|
mihomoProxies,
|
||||||
mihomoProxyDelay,
|
mihomoProxyDelay,
|
||||||
mihomoRules,
|
mihomoRules,
|
||||||
|
@ -33,13 +32,12 @@ import {
|
||||||
import { isEncryptionAvailable, startCore } from '../core/manager'
|
import { isEncryptionAvailable, startCore } from '../core/manager'
|
||||||
import { triggerSysProxy } from '../resolve/sysproxy'
|
import { triggerSysProxy } from '../resolve/sysproxy'
|
||||||
import { checkUpdate } from '../resolve/autoUpdater'
|
import { checkUpdate } from '../resolve/autoUpdater'
|
||||||
import { exePath, mihomoCorePath } from './dirs'
|
import { exePath, mihomoCorePath, mihomoWorkConfigPath } from './dirs'
|
||||||
import { execSync } from 'child_process'
|
import { execSync } from 'child_process'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
|
|
||||||
export function registerIpcMainHandlers(): void {
|
export function registerIpcMainHandlers(): void {
|
||||||
ipcMain.handle('mihomoVersion', mihomoVersion)
|
ipcMain.handle('mihomoVersion', mihomoVersion)
|
||||||
ipcMain.handle('mihomoConfig', mihomoConfig)
|
|
||||||
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)
|
||||||
|
@ -73,6 +71,7 @@ export function registerIpcMainHandlers(): void {
|
||||||
ipcMain.handle('encryptString', (_e, str) => safeStorage.encryptString(str))
|
ipcMain.handle('encryptString', (_e, str) => safeStorage.encryptString(str))
|
||||||
ipcMain.handle('getFilePath', getFilePath)
|
ipcMain.handle('getFilePath', getFilePath)
|
||||||
ipcMain.handle('readTextFile', (_e, filePath) => readTextFile(filePath))
|
ipcMain.handle('readTextFile', (_e, filePath) => readTextFile(filePath))
|
||||||
|
ipcMain.handle('getRuntimeConfig', getRuntimeConfig)
|
||||||
ipcMain.handle('checkUpdate', () => checkUpdate())
|
ipcMain.handle('checkUpdate', () => checkUpdate())
|
||||||
ipcMain.handle('getVersion', () => app.getVersion())
|
ipcMain.handle('getVersion', () => app.getVersion())
|
||||||
ipcMain.handle('platform', () => process.platform)
|
ipcMain.handle('platform', () => process.platform)
|
||||||
|
@ -92,6 +91,10 @@ function readTextFile(filePath: string): string {
|
||||||
return fs.readFileSync(filePath, 'utf8')
|
return fs.readFileSync(filePath, 'utf8')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRuntimeConfig(): string {
|
||||||
|
return fs.readFileSync(mihomoWorkConfigPath(), 'utf8')
|
||||||
|
}
|
||||||
|
|
||||||
async function setupFirewall(): Promise<void> {
|
async function setupFirewall(): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const removeCommand = `
|
const removeCommand = `
|
||||||
|
|
67
src/renderer/src/components/sider/config-viewer.tsx
Normal file
67
src/renderer/src/components/sider/config-viewer.tsx
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
import { Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Button } from '@nextui-org/react'
|
||||||
|
import React, { useEffect, useState } from 'react'
|
||||||
|
import MonacoEditor, { monaco } from 'react-monaco-editor'
|
||||||
|
import { useTheme } from 'next-themes'
|
||||||
|
import { getRuntimeConfig } from '@renderer/utils/ipc'
|
||||||
|
interface Props {
|
||||||
|
onClose: () => void
|
||||||
|
}
|
||||||
|
const ConfigViewer: React.FC<Props> = (props) => {
|
||||||
|
const { onClose } = props
|
||||||
|
const [currData, setCurrData] = useState('')
|
||||||
|
const { theme } = useTheme()
|
||||||
|
|
||||||
|
const editorDidMount = (editor: monaco.editor.IStandaloneCodeEditor): void => {
|
||||||
|
window.electron.ipcRenderer.on('resize', () => {
|
||||||
|
editor.layout()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const editorWillUnmount = (editor: monaco.editor.IStandaloneCodeEditor): void => {
|
||||||
|
window.electron.ipcRenderer.removeAllListeners('resize')
|
||||||
|
editor.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
const getContent = async (): Promise<void> => {
|
||||||
|
setCurrData(await getRuntimeConfig())
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getContent()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal size="5xl" hideCloseButton isOpen={true} scrollBehavior="inside">
|
||||||
|
<ModalContent className="h-full w-[calc(100%-100px)]">
|
||||||
|
<ModalHeader className="flex">当前运行时配置</ModalHeader>
|
||||||
|
<ModalBody className="h-full">
|
||||||
|
<MonacoEditor
|
||||||
|
height="100%"
|
||||||
|
language="yaml"
|
||||||
|
value={currData}
|
||||||
|
theme={theme === 'dark' ? 'vs-dark' : 'vs'}
|
||||||
|
options={{
|
||||||
|
readOnly: true,
|
||||||
|
minimap: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
mouseWheelZoom: true,
|
||||||
|
fontFamily: `Fira Code, JetBrains Mono, Roboto Mono, "Source Code Pro", Consolas, Menlo, Monaco, monospace, "Courier New", "Apple Color Emoji"`,
|
||||||
|
fontLigatures: true, // 连字符
|
||||||
|
smoothScrolling: true // 平滑滚动
|
||||||
|
}}
|
||||||
|
editorDidMount={editorDidMount}
|
||||||
|
editorWillUnmount={editorWillUnmount}
|
||||||
|
/>
|
||||||
|
</ModalBody>
|
||||||
|
<ModalFooter>
|
||||||
|
<Button variant="light" onPress={onClose}>
|
||||||
|
关闭
|
||||||
|
</Button>
|
||||||
|
</ModalFooter>
|
||||||
|
</ModalContent>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ConfigViewer
|
|
@ -2,11 +2,13 @@ import { Button, Card, CardBody, CardFooter, Chip, Progress } from '@nextui-org/
|
||||||
import { useProfileConfig } from '@renderer/hooks/use-profile-config'
|
import { useProfileConfig } from '@renderer/hooks/use-profile-config'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import { calcTraffic, calcPercent } from '@renderer/utils/calc'
|
import { calcTraffic, calcPercent } from '@renderer/utils/calc'
|
||||||
|
import { LiaGripfire } from 'react-icons/lia'
|
||||||
import { IoMdRefresh } from 'react-icons/io'
|
import { IoMdRefresh } from 'react-icons/io'
|
||||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||||
import 'dayjs/locale/zh-cn'
|
import 'dayjs/locale/zh-cn'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
import ConfigViewer from './config-viewer'
|
||||||
|
|
||||||
dayjs.extend(relativeTime)
|
dayjs.extend(relativeTime)
|
||||||
dayjs.locale('zh-cn')
|
dayjs.locale('zh-cn')
|
||||||
|
@ -16,6 +18,7 @@ const ProfileCard: React.FC = () => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const match = location.pathname.includes('/profiles')
|
const match = location.pathname.includes('/profiles')
|
||||||
const [updating, setUpdating] = useState(false)
|
const [updating, setUpdating] = useState(false)
|
||||||
|
const [showRuntimeConfig, setShowRuntimeConfig] = useState(false)
|
||||||
const { profileConfig, addProfileItem } = useProfileConfig()
|
const { profileConfig, addProfileItem } = useProfileConfig()
|
||||||
const { current, items } = profileConfig ?? {}
|
const { current, items } = profileConfig ?? {}
|
||||||
const info = items?.find((item) => item.id === current) ?? {
|
const info = items?.find((item) => item.id === current) ?? {
|
||||||
|
@ -35,6 +38,7 @@ const ProfileCard: React.FC = () => {
|
||||||
isPressable
|
isPressable
|
||||||
onPress={() => navigate('/profiles')}
|
onPress={() => navigate('/profiles')}
|
||||||
>
|
>
|
||||||
|
{showRuntimeConfig && <ConfigViewer onClose={() => setShowRuntimeConfig(false)} />}
|
||||||
<CardBody className="pb-1">
|
<CardBody className="pb-1">
|
||||||
<div className="flex justify-between h-[32px]">
|
<div className="flex justify-between h-[32px]">
|
||||||
<h3
|
<h3
|
||||||
|
@ -42,25 +46,39 @@ const ProfileCard: React.FC = () => {
|
||||||
>
|
>
|
||||||
{info?.name}
|
{info?.name}
|
||||||
</h3>
|
</h3>
|
||||||
{info.type === 'remote' && (
|
<div>
|
||||||
<Button
|
<Button
|
||||||
isIconOnly
|
isIconOnly
|
||||||
size="sm"
|
size="sm"
|
||||||
disabled={updating}
|
title="查看当前运行时配置"
|
||||||
variant="light"
|
variant="light"
|
||||||
color="default"
|
color="default"
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
setUpdating(true)
|
setShowRuntimeConfig(true)
|
||||||
addProfileItem(info).finally(() => {
|
|
||||||
setUpdating(false)
|
|
||||||
})
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<IoMdRefresh
|
<LiaGripfire className={`text-[24px] ${match ? 'text-white' : 'text-foreground'}`} />
|
||||||
className={`text-[24px] ${match ? 'text-white' : 'text-foreground'} ${updating ? 'animate-spin' : ''}`}
|
|
||||||
/>
|
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
{info.type === 'remote' && (
|
||||||
|
<Button
|
||||||
|
isIconOnly
|
||||||
|
size="sm"
|
||||||
|
disabled={updating}
|
||||||
|
variant="light"
|
||||||
|
color="default"
|
||||||
|
onPress={() => {
|
||||||
|
setUpdating(true)
|
||||||
|
addProfileItem(info).finally(() => {
|
||||||
|
setUpdating(false)
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IoMdRefresh
|
||||||
|
className={`text-[24px] ${match ? 'text-white' : 'text-foreground'} ${updating ? 'animate-spin' : ''}`}
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{info.type === 'remote' && (
|
{info.type === 'remote' && (
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -2,10 +2,6 @@ export async function mihomoVersion(): Promise<IMihomoVersion> {
|
||||||
return await window.electron.ipcRenderer.invoke('mihomoVersion')
|
return await window.electron.ipcRenderer.invoke('mihomoVersion')
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function mihomoConfig(): Promise<IMihomoConfig> {
|
|
||||||
return await window.electron.ipcRenderer.invoke('mihomoConfig')
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -139,6 +135,10 @@ export async function readTextFile(filePath: string): Promise<string> {
|
||||||
return await window.electron.ipcRenderer.invoke('readTextFile', filePath)
|
return await window.electron.ipcRenderer.invoke('readTextFile', filePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getRuntimeConfig(): Promise<string> {
|
||||||
|
return await window.electron.ipcRenderer.invoke('getRuntimeConfig')
|
||||||
|
}
|
||||||
|
|
||||||
export async function checkUpdate(): Promise<string | undefined> {
|
export async function checkUpdate(): Promise<string | undefined> {
|
||||||
return await window.electron.ipcRenderer.invoke('checkUpdate')
|
return await window.electron.ipcRenderer.invoke('checkUpdate')
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user