mirror of
https://github.com/pompurin404/mihomo-party.git
synced 2024-11-15 19:22:31 +08:00
setup core manager
This commit is contained in:
parent
f30d1228f1
commit
574bdb05be
Binary file not shown.
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 28 KiB |
Binary file not shown.
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 51 KiB |
|
@ -4,9 +4,11 @@ import { checkAutoRun, disableAutoRun, enableAutoRun } from './autoRun'
|
|||
import {
|
||||
getAppConfig,
|
||||
setAppConfig,
|
||||
getProfileConfig,
|
||||
getControledMihomoConfig,
|
||||
setControledMihomoConfig
|
||||
} from './config'
|
||||
import { restartCore } from './manager'
|
||||
|
||||
export function registerIpcMainHandlers(): void {
|
||||
ipcMain.handle('mihomoVersion', mihomoVersion)
|
||||
|
@ -21,4 +23,6 @@ export function registerIpcMainHandlers(): void {
|
|||
ipcMain.handle('setControledMihomoConfig', (_e, config) => {
|
||||
setControledMihomoConfig(config)
|
||||
})
|
||||
ipcMain.handle('getProfileConfig', (_e, force) => getProfileConfig(force))
|
||||
ipcMain.handle('restartCore', () => restartCore())
|
||||
}
|
||||
|
|
|
@ -1,50 +1,80 @@
|
|||
import yaml from 'yaml'
|
||||
import fs from 'fs'
|
||||
import { app } from 'electron'
|
||||
import path from 'path'
|
||||
import { defaultConfig } from './template'
|
||||
|
||||
const dataDir = app.getPath('userData')
|
||||
const appConfigPath = path.join(dataDir, 'config.yaml')
|
||||
const controledMihomoConfigPath = path.join(dataDir, 'mihomo.yaml')
|
||||
import {
|
||||
defaultConfig,
|
||||
defaultControledMihomoConfig,
|
||||
defaultProfile,
|
||||
defaultProfileConfig
|
||||
} from './template'
|
||||
import { appConfigPath, controledMihomoConfigPath, profileConfigPath, profilePath } from './dirs'
|
||||
|
||||
export let appConfig: IAppConfig
|
||||
export let profileConfig: IProfileConfig
|
||||
export let currentProfile: Partial<IMihomoConfig>
|
||||
export let controledMihomoConfig: Partial<IMihomoConfig>
|
||||
|
||||
export function initConfig(): void {
|
||||
if (!fs.existsSync(dataDir)) {
|
||||
fs.mkdirSync(dataDir)
|
||||
if (!fs.existsSync(appConfigPath())) {
|
||||
fs.writeFileSync(appConfigPath(), yaml.stringify(defaultConfig))
|
||||
}
|
||||
if (!fs.existsSync(appConfigPath)) {
|
||||
fs.writeFileSync(appConfigPath, yaml.stringify(defaultConfig))
|
||||
if (!fs.existsSync(profileConfigPath())) {
|
||||
fs.writeFileSync(profileConfigPath(), yaml.stringify(defaultProfileConfig))
|
||||
}
|
||||
if (!fs.existsSync(controledMihomoConfigPath)) {
|
||||
fs.writeFileSync(controledMihomoConfigPath, yaml.stringify({}))
|
||||
if (!fs.existsSync(profilePath('default'))) {
|
||||
fs.writeFileSync(profilePath('default'), yaml.stringify(defaultProfile))
|
||||
}
|
||||
if (!fs.existsSync(controledMihomoConfigPath())) {
|
||||
fs.writeFileSync(controledMihomoConfigPath(), yaml.stringify(defaultControledMihomoConfig))
|
||||
}
|
||||
getAppConfig(true)
|
||||
getControledMihomoConfig(true)
|
||||
getProfileConfig(true)
|
||||
getCurrentProfile(true)
|
||||
}
|
||||
|
||||
export function getAppConfig(force = false): IAppConfig {
|
||||
if (force || !appConfig) {
|
||||
appConfig = yaml.parse(fs.readFileSync(appConfigPath, 'utf-8'))
|
||||
appConfig = yaml.parse(fs.readFileSync(appConfigPath(), 'utf-8'))
|
||||
}
|
||||
return appConfig
|
||||
}
|
||||
|
||||
export function setAppConfig(patch: Partial<IAppConfig>): void {
|
||||
appConfig = Object.assign(appConfig, patch)
|
||||
fs.writeFileSync(appConfigPath, yaml.stringify(appConfig))
|
||||
fs.writeFileSync(appConfigPath(), yaml.stringify(appConfig))
|
||||
}
|
||||
|
||||
export function getControledMihomoConfig(force = false): Partial<IMihomoConfig> {
|
||||
if (force || !controledMihomoConfig) {
|
||||
controledMihomoConfig = yaml.parse(fs.readFileSync(controledMihomoConfigPath, 'utf-8'))
|
||||
controledMihomoConfig = yaml.parse(fs.readFileSync(controledMihomoConfigPath(), 'utf-8'))
|
||||
}
|
||||
return controledMihomoConfig
|
||||
}
|
||||
|
||||
export function setControledMihomoConfig(patch: Partial<IMihomoConfig>): void {
|
||||
controledMihomoConfig = Object.assign(controledMihomoConfig, patch)
|
||||
fs.writeFileSync(controledMihomoConfigPath, yaml.stringify(controledMihomoConfig))
|
||||
fs.writeFileSync(controledMihomoConfigPath(), yaml.stringify(controledMihomoConfig))
|
||||
}
|
||||
|
||||
export function getProfileConfig(force = false): IProfileConfig {
|
||||
if (force || !profileConfig) {
|
||||
profileConfig = yaml.parse(fs.readFileSync(profileConfigPath(), 'utf-8'))
|
||||
}
|
||||
return profileConfig
|
||||
}
|
||||
|
||||
export function setProfileConfig(patch: Partial<IProfileConfig>): void {
|
||||
profileConfig = Object.assign(profileConfig, patch)
|
||||
fs.writeFileSync(profileConfigPath(), yaml.stringify(profileConfig))
|
||||
}
|
||||
|
||||
export function getCurrentProfile(force = false): Partial<IMihomoConfig> {
|
||||
if (force || !currentProfile) {
|
||||
if (profileConfig.current) {
|
||||
currentProfile = yaml.parse(fs.readFileSync(profilePath(profileConfig.current), 'utf-8'))
|
||||
} else {
|
||||
currentProfile = yaml.parse(fs.readFileSync(profilePath('default'), 'utf-8'))
|
||||
}
|
||||
}
|
||||
return currentProfile
|
||||
}
|
||||
|
|
59
src/main/dirs.ts
Normal file
59
src/main/dirs.ts
Normal file
|
@ -0,0 +1,59 @@
|
|||
import { is } from '@electron-toolkit/utils'
|
||||
import { app } from 'electron'
|
||||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
|
||||
export const dataDir = app.getPath('userData')
|
||||
|
||||
export function initDirs(): void {
|
||||
if (!fs.existsSync(dataDir)) {
|
||||
fs.mkdirSync(dataDir)
|
||||
}
|
||||
if (!fs.existsSync(profilesDir())) {
|
||||
fs.mkdirSync(profilesDir())
|
||||
}
|
||||
if (!fs.existsSync(mihomoWorkDir())) {
|
||||
fs.mkdirSync(mihomoWorkDir())
|
||||
}
|
||||
}
|
||||
|
||||
export function mihomoCoreDir(): string {
|
||||
if (is.dev) {
|
||||
return path.join(__dirname, '../../resources/sidecar')
|
||||
} else {
|
||||
return path.join(process.resourcesPath, 'sidecar')
|
||||
}
|
||||
}
|
||||
|
||||
export function mihomoCorePath(core: string): string {
|
||||
const isWin = process.platform === 'win32'
|
||||
return path.join(mihomoCoreDir(), `${core}${isWin ? '.exe' : ''}`)
|
||||
}
|
||||
|
||||
export function appConfigPath(): string {
|
||||
return path.join(dataDir, 'config.yaml')
|
||||
}
|
||||
|
||||
export function controledMihomoConfigPath(): string {
|
||||
return path.join(dataDir, 'mihomo.yaml')
|
||||
}
|
||||
|
||||
export function profileConfigPath(): string {
|
||||
return path.join(dataDir, 'profile.yaml')
|
||||
}
|
||||
|
||||
export function profilesDir(): string {
|
||||
return path.join(dataDir, 'profiles')
|
||||
}
|
||||
|
||||
export function profilePath(id: string): string {
|
||||
return path.join(profilesDir(), `${id}.yaml`)
|
||||
}
|
||||
|
||||
export function mihomoWorkDir(): string {
|
||||
return path.join(dataDir, 'work')
|
||||
}
|
||||
|
||||
export function mihomoWorkConfigPath(): string {
|
||||
return path.join(mihomoWorkDir(), 'config.yaml')
|
||||
}
|
9
src/main/factory.ts
Normal file
9
src/main/factory.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { controledMihomoConfig, currentProfile } from './config'
|
||||
import { mihomoWorkConfigPath } from './dirs'
|
||||
import yaml from 'yaml'
|
||||
import fs from 'fs'
|
||||
|
||||
export function generateProfile(): void {
|
||||
const profile = Object.assign(currentProfile, controledMihomoConfig)
|
||||
fs.writeFileSync(mihomoWorkConfigPath(), yaml.stringify(profile))
|
||||
}
|
|
@ -5,13 +5,16 @@ import pngIcon from '../../resources/icon.png?asset'
|
|||
import icoIcon from '../../resources/icon.ico?asset'
|
||||
import { registerIpcMainHandlers } from './cmds'
|
||||
import { initConfig, appConfig } from './config'
|
||||
import { stopCore, startCore } from './manager'
|
||||
import { initDirs } from './dirs'
|
||||
|
||||
let window: BrowserWindow | null = null
|
||||
let tray: Tray | null = null
|
||||
let trayContextMenu: Menu | null = null
|
||||
|
||||
initDirs()
|
||||
initConfig()
|
||||
|
||||
startCore()
|
||||
function createWindow(): void {
|
||||
// Create the browser window.
|
||||
window = new BrowserWindow({
|
||||
|
@ -124,5 +127,6 @@ app.on('window-all-closed', () => {
|
|||
})
|
||||
|
||||
app.on('before-quit', () => {
|
||||
stopCore()
|
||||
app.exit()
|
||||
})
|
||||
|
|
25
src/main/manager.ts
Normal file
25
src/main/manager.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import { execFile, ChildProcess } from 'child_process'
|
||||
import { mihomoCorePath, mihomoWorkDir } from './dirs'
|
||||
import { generateProfile } from './factory'
|
||||
import { appConfig } from './config'
|
||||
|
||||
let child: ChildProcess
|
||||
|
||||
export function startCore(): void {
|
||||
const corePath = mihomoCorePath(appConfig.core ?? 'mihomo')
|
||||
generateProfile()
|
||||
stopCore()
|
||||
child = execFile(corePath, ['-d', mihomoWorkDir()], (error, stdout) => {
|
||||
console.log(stdout)
|
||||
})
|
||||
}
|
||||
|
||||
export function stopCore(): void {
|
||||
if (child) {
|
||||
child.kill('SIGINT')
|
||||
}
|
||||
}
|
||||
|
||||
export function restartCore(): void {
|
||||
startCore()
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import axios, { AxiosInstance } from 'axios'
|
||||
import { controledMihomoConfig } from './config'
|
||||
|
||||
let axiosIns: AxiosInstance = null!
|
||||
|
||||
|
@ -7,8 +8,9 @@ let axiosIns: AxiosInstance = null!
|
|||
export const getAxios = async (force: boolean = false): Promise<AxiosInstance> => {
|
||||
if (axiosIns && !force) return axiosIns
|
||||
|
||||
const server = '127.0.0.1:9097'
|
||||
const secret = ''
|
||||
let server = controledMihomoConfig['external-controller']
|
||||
const secret = controledMihomoConfig.secret ?? ''
|
||||
if (server?.startsWith(':')) server = `127.0.0.1${server}`
|
||||
|
||||
axiosIns = axios.create({
|
||||
baseURL: `http://${server}`,
|
||||
|
|
|
@ -1,3 +1,30 @@
|
|||
export const defaultConfig: IAppConfig = {
|
||||
core: 'mihomo',
|
||||
silentStart: false
|
||||
}
|
||||
|
||||
export const defaultControledMihomoConfig: Partial<IMihomoConfig> = {
|
||||
'external-controller': '127.0.0.1:9090',
|
||||
ipv6: false,
|
||||
mode: 'rule',
|
||||
'mixed-port': 7890,
|
||||
'allow-lan': false,
|
||||
'log-level': 'info'
|
||||
}
|
||||
|
||||
export const defaultProfileConfig: IProfileConfig = {
|
||||
current: 'default',
|
||||
profiles: [
|
||||
{
|
||||
id: 'default',
|
||||
type: 'local',
|
||||
name: '默认'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
export const defaultProfile: Partial<IMihomoConfig> = {
|
||||
proxies: [],
|
||||
'proxy-groups': [],
|
||||
rules: []
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import RuleCard from '@renderer/components/sider/rule-card'
|
|||
import OverrideCard from '@renderer/components/sider/override-card'
|
||||
import ConnCard from '@renderer/components/sider/conn-card'
|
||||
import LogCard from '@renderer/components/sider/log-card'
|
||||
import MihomoCoreCard from './components/sider/mihomo-core-card.tsx'
|
||||
|
||||
const App: React.FC = () => {
|
||||
const { setTheme } = useTheme()
|
||||
|
@ -67,6 +68,7 @@ const App: React.FC = () => {
|
|||
<h3 className="select-none text-lg font-bold m-2">配置</h3>
|
||||
<div className="w-full h-[calc(100%-260px)] overflow-y-auto no-scrollbar">
|
||||
<div className="mx-2">
|
||||
<MihomoCoreCard />
|
||||
<ProfileCard />
|
||||
<ProxyCard />
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Button, Card, CardBody, CardFooter, Chip } from '@nextui-org/react'
|
||||
import { Button, Card, CardBody, CardFooter } from '@nextui-org/react'
|
||||
import { IoLink } from 'react-icons/io5'
|
||||
import { useLocation, useNavigate } from 'react-router-dom'
|
||||
|
||||
|
@ -22,9 +22,6 @@ const ConnCard: React.FC = () => {
|
|||
>
|
||||
<IoLink color="default" className="text-[20px]" />
|
||||
</Button>
|
||||
<Chip size="sm" color="secondary" variant="bordered" className="mr-3 mt-2">
|
||||
1103
|
||||
</Chip>
|
||||
</div>
|
||||
</CardBody>
|
||||
<CardFooter className="pt-1">
|
||||
|
|
72
src/renderer/src/components/sider/mihomo-core-card.tsx.tsx
Normal file
72
src/renderer/src/components/sider/mihomo-core-card.tsx.tsx
Normal file
|
@ -0,0 +1,72 @@
|
|||
import {
|
||||
Button,
|
||||
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 { IoMdRefresh } from 'react-icons/io'
|
||||
import useSWR from 'swr'
|
||||
|
||||
const CoreMap = {
|
||||
mihomo: 'Mihomo',
|
||||
'mihomo-alpha': 'Mihomo Alpha'
|
||||
}
|
||||
|
||||
const MihomoCoreCard: React.FC = () => {
|
||||
const { data: version, mutate } = useSWR('mihomoVersion', mihomoVersion)
|
||||
const { appConfig, patchAppConfig } = useAppConfig()
|
||||
const { core } = appConfig || {}
|
||||
|
||||
return (
|
||||
<Card
|
||||
fullWidth
|
||||
className={`mb-2 ${location.pathname.includes('/profiles') ? 'bg-primary' : ''}`}
|
||||
>
|
||||
<CardBody>
|
||||
<div className="flex justify-between h-[32px]">
|
||||
<h3 className="select-none text-md font-bold leading-[32px]">
|
||||
{version?.version ?? '-'}
|
||||
</h3>
|
||||
<Button
|
||||
isIconOnly
|
||||
size="sm"
|
||||
variant="light"
|
||||
color="default"
|
||||
onPress={() => {
|
||||
restartCore()
|
||||
}}
|
||||
>
|
||||
<IoMdRefresh color="default" className="text-[24px]" />
|
||||
</Button>
|
||||
</div>
|
||||
</CardBody>
|
||||
<CardFooter className="pt-1">
|
||||
<Dropdown>
|
||||
<DropdownTrigger>
|
||||
<Button variant="faded" fullWidth>
|
||||
{core ? CoreMap[core] : ''}
|
||||
</Button>
|
||||
</DropdownTrigger>
|
||||
<DropdownMenu
|
||||
onAction={async (key) => {
|
||||
await patchAppConfig({ core: key as 'mihomo' | 'mihomo-alpha' })
|
||||
await restartCore()
|
||||
await mutate()
|
||||
}}
|
||||
>
|
||||
<DropdownItem key="mihomo">Mihomo </DropdownItem>
|
||||
<DropdownItem key="mihomo-alpha">Mihomo Alpha</DropdownItem>
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
|
||||
export default MihomoCoreCard
|
|
@ -4,7 +4,7 @@ import { getAppConfig, setAppConfig } from '@renderer/utils/ipc'
|
|||
interface RetuenType {
|
||||
appConfig: IAppConfig | undefined
|
||||
mutateAppConfig: () => void
|
||||
patchAppConfig: (value: Partial<IAppConfig>) => void
|
||||
patchAppConfig: (value: Partial<IAppConfig>) => Promise<void>
|
||||
}
|
||||
|
||||
export const useAppConfig = (): RetuenType => {
|
||||
|
|
|
@ -29,3 +29,7 @@ export async function getControledMihomoConfig(force = false): Promise<Partial<I
|
|||
export async function setControledMihomoConfig(patch: Partial<IMihomoConfig>): Promise<void> {
|
||||
await window.electron.ipcRenderer.invoke('setControledMihomoConfig', patch)
|
||||
}
|
||||
|
||||
export async function restartCore(): Promise<void> {
|
||||
await window.electron.ipcRenderer.invoke('restartCore')
|
||||
}
|
||||
|
|
21
src/shared/types.d.ts
vendored
21
src/shared/types.d.ts
vendored
|
@ -1,4 +1,5 @@
|
|||
type OutboundMode = 'rule' | 'global' | 'direct'
|
||||
type LogLevel = 'info' | 'debug' | 'warn' | 'error' | 'silent'
|
||||
|
||||
interface IMihomoVersion {
|
||||
version: string
|
||||
|
@ -6,12 +7,32 @@ interface IMihomoVersion {
|
|||
}
|
||||
|
||||
interface IAppConfig {
|
||||
core: 'mihomo' | 'mihomo-alpha'
|
||||
silentStart: boolean
|
||||
}
|
||||
|
||||
interface IMihomoConfig {
|
||||
'external-controller': string
|
||||
secret?: string
|
||||
ipv6: boolean
|
||||
mode: OutboundMode
|
||||
'mixed-port': number
|
||||
'allow-lan': boolean
|
||||
'log-level': LogLevel
|
||||
'socks-port'?: number
|
||||
port?: number
|
||||
proxies?: []
|
||||
'proxy-groups'?: []
|
||||
rules?: []
|
||||
}
|
||||
|
||||
interface IProfileConfig {
|
||||
current?: string
|
||||
profiles?: IProfileItem[]
|
||||
}
|
||||
|
||||
interface IProfileItem {
|
||||
id: string
|
||||
type: 'remote' | 'local'
|
||||
name: string
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user