mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2025-12-27 05:00:30 +08:00
sysproxy and tun controller
This commit is contained in:
parent
536ae67e29
commit
bfcd195b4d
@ -19,6 +19,7 @@ import {
|
|||||||
removeProfileItem
|
removeProfileItem
|
||||||
} from './config'
|
} from './config'
|
||||||
import { restartCore } from './manager'
|
import { restartCore } from './manager'
|
||||||
|
import { triggerSysProxy } from './sysproxy'
|
||||||
|
|
||||||
export function registerIpcMainHandlers(): void {
|
export function registerIpcMainHandlers(): void {
|
||||||
ipcMain.handle('mihomoVersion', mihomoVersion)
|
ipcMain.handle('mihomoVersion', mihomoVersion)
|
||||||
@ -39,4 +40,5 @@ export function registerIpcMainHandlers(): void {
|
|||||||
ipcMain.handle('addProfileItem', (_e, item) => addProfileItem(item))
|
ipcMain.handle('addProfileItem', (_e, item) => addProfileItem(item))
|
||||||
ipcMain.handle('removeProfileItem', (_e, id) => removeProfileItem(id))
|
ipcMain.handle('removeProfileItem', (_e, id) => removeProfileItem(id))
|
||||||
ipcMain.handle('restartCore', () => restartCore())
|
ipcMain.handle('restartCore', () => restartCore())
|
||||||
|
ipcMain.handle('triggerSysProxy', (_e, enable) => triggerSysProxy(enable))
|
||||||
}
|
}
|
||||||
|
|||||||
17
src/main/sysproxy.ts
Normal file
17
src/main/sysproxy.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { controledMihomoConfig } from './config'
|
||||||
|
|
||||||
|
export function triggerSysProxy(enable: boolean): void {
|
||||||
|
if (enable) {
|
||||||
|
enableSysProxy()
|
||||||
|
} else {
|
||||||
|
disableSysProxy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function enableSysProxy(): void {
|
||||||
|
console.log('enableSysProxy', controledMihomoConfig['mixed-port'])
|
||||||
|
}
|
||||||
|
|
||||||
|
export function disableSysProxy(): void {
|
||||||
|
console.log('disableSysProxy')
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
export const defaultConfig: IAppConfig = {
|
export const defaultConfig: IAppConfig = {
|
||||||
core: 'mihomo',
|
core: 'mihomo',
|
||||||
silentStart: false
|
silentStart: false,
|
||||||
|
sysProxy: { enable: false, mode: 'manual' }
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultControledMihomoConfig: Partial<IMihomoConfig> = {
|
export const defaultControledMihomoConfig: Partial<IMihomoConfig> = {
|
||||||
@ -9,7 +10,8 @@ export const defaultControledMihomoConfig: Partial<IMihomoConfig> = {
|
|||||||
mode: 'rule',
|
mode: 'rule',
|
||||||
'mixed-port': 7890,
|
'mixed-port': 7890,
|
||||||
'allow-lan': false,
|
'allow-lan': false,
|
||||||
'log-level': 'info'
|
'log-level': 'info',
|
||||||
|
tun: { enable: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultProfileConfig: IProfileConfig = {
|
export const defaultProfileConfig: IProfileConfig = {
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
import { controledMihomoConfig, setControledMihomoConfig } from './config'
|
import { appConfig, controledMihomoConfig, setAppConfig, setControledMihomoConfig } from './config'
|
||||||
import icoIcon from '../../resources/icon.ico?asset'
|
import icoIcon from '../../resources/icon.ico?asset'
|
||||||
import pngIcon from '../../resources/icon.png?asset'
|
import pngIcon from '../../resources/icon.png?asset'
|
||||||
import { patchMihomoConfig } from './mihomoApi'
|
import { patchMihomoConfig } from './mihomoApi'
|
||||||
import { window } from '.'
|
import { window } from '.'
|
||||||
import { app, ipcMain, Menu, Tray } from 'electron'
|
import { app, ipcMain, Menu, shell, Tray } from 'electron'
|
||||||
|
import { dataDir, logDir, mihomoCoreDir, mihomoWorkDir } from './dirs'
|
||||||
|
import { triggerSysProxy } from './sysproxy'
|
||||||
|
|
||||||
let tray: Tray | null = null
|
let tray: Tray | null = null
|
||||||
|
|
||||||
@ -55,6 +57,58 @@ const buildContextMenu = (): Menu => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ type: 'separator' },
|
{ type: 'separator' },
|
||||||
|
{
|
||||||
|
type: 'checkbox',
|
||||||
|
label: '系统代理',
|
||||||
|
checked: appConfig.sysProxy.enable,
|
||||||
|
click: (item): void => {
|
||||||
|
const enable = item.checked
|
||||||
|
setAppConfig({ sysProxy: { enable } })
|
||||||
|
triggerSysProxy(enable)
|
||||||
|
window?.webContents.send('appConfigUpdated')
|
||||||
|
updateTrayMenu()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'checkbox',
|
||||||
|
label: '虚拟网卡',
|
||||||
|
checked: controledMihomoConfig.tun?.enable ?? false,
|
||||||
|
click: (item): void => {
|
||||||
|
const enable = item.checked
|
||||||
|
setControledMihomoConfig({ tun: { enable } })
|
||||||
|
patchMihomoConfig({ tun: { enable } })
|
||||||
|
window?.webContents.send('controledMihomoConfigUpdated')
|
||||||
|
updateTrayMenu()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ type: 'separator' },
|
||||||
|
{
|
||||||
|
type: 'submenu',
|
||||||
|
label: '打开目录',
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
type: 'normal',
|
||||||
|
label: '应用目录',
|
||||||
|
click: (): Promise<string> => shell.openPath(dataDir)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'normal',
|
||||||
|
label: '工作目录',
|
||||||
|
click: (): Promise<string> => shell.openPath(mihomoWorkDir())
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'normal',
|
||||||
|
label: '内核目录',
|
||||||
|
click: (): Promise<string> => shell.openPath(mihomoCoreDir())
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'normal',
|
||||||
|
label: '日志目录',
|
||||||
|
click: (): Promise<string> => shell.openPath(logDir())
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{ type: 'separator' },
|
||||||
{
|
{
|
||||||
id: 'restart',
|
id: 'restart',
|
||||||
label: '重启应用',
|
label: '重启应用',
|
||||||
@ -80,6 +134,9 @@ export function createTray(): void {
|
|||||||
ipcMain.on('controledMihomoConfigUpdated', () => {
|
ipcMain.on('controledMihomoConfigUpdated', () => {
|
||||||
updateTrayMenu()
|
updateTrayMenu()
|
||||||
})
|
})
|
||||||
|
ipcMain.on('appConfigUpdated', () => {
|
||||||
|
updateTrayMenu()
|
||||||
|
})
|
||||||
|
|
||||||
tray.setContextMenu(menu)
|
tray.setContextMenu(menu)
|
||||||
tray.setIgnoreDoubleClickEvents(true)
|
tray.setIgnoreDoubleClickEvents(true)
|
||||||
|
|||||||
@ -1,13 +1,22 @@
|
|||||||
import { Button, Card, CardBody, CardFooter, Switch } from '@nextui-org/react'
|
import { Button, Card, CardBody, CardFooter, Switch } from '@nextui-org/react'
|
||||||
import React, { useState } from 'react'
|
|
||||||
import { AiOutlineGlobal } from 'react-icons/ai'
|
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
|
import { useAppConfig } from '@renderer/hooks/use-config'
|
||||||
|
import { AiOutlineGlobal } from 'react-icons/ai'
|
||||||
|
import React from 'react'
|
||||||
|
import { triggerSysProxy } from '@renderer/utils/ipc'
|
||||||
|
|
||||||
const SysproxySwitcher: React.FC = () => {
|
const SysproxySwitcher: React.FC = () => {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const match = location.pathname.includes('/sysproxy')
|
const match = location.pathname.includes('/sysproxy')
|
||||||
const [enable, setEnable] = useState(false)
|
const { appConfig, patchAppConfig } = useAppConfig()
|
||||||
|
const { sysProxy } = appConfig || {}
|
||||||
|
const { enable } = sysProxy || {}
|
||||||
|
|
||||||
|
const onChange = async (enable: boolean): Promise<void> => {
|
||||||
|
await patchAppConfig({ sysProxy: { enable } })
|
||||||
|
await triggerSysProxy(enable)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
@ -31,7 +40,7 @@ const SysproxySwitcher: React.FC = () => {
|
|||||||
}}
|
}}
|
||||||
size="sm"
|
size="sm"
|
||||||
isSelected={enable}
|
isSelected={enable}
|
||||||
onValueChange={setEnable}
|
onValueChange={onChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</CardBody>
|
</CardBody>
|
||||||
|
|||||||
@ -1,13 +1,23 @@
|
|||||||
import { Button, Card, CardBody, CardFooter, Switch } from '@nextui-org/react'
|
import { Button, Card, CardBody, CardFooter, Switch } from '@nextui-org/react'
|
||||||
import React, { useState } from 'react'
|
import { useControledMihomoConfig } from '@renderer/hooks/use-controled-mihomo-config'
|
||||||
import { TbDeviceIpadHorizontalBolt } from 'react-icons/tb'
|
import { TbDeviceIpadHorizontalBolt } from 'react-icons/tb'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
|
import { patchMihomoConfig } from '@renderer/utils/ipc'
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
const TunSwitcher: React.FC = () => {
|
const TunSwitcher: React.FC = () => {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const match = location.pathname.includes('/tun')
|
const match = location.pathname.includes('/tun')
|
||||||
const [enable, setEnable] = useState(false)
|
|
||||||
|
const { controledMihomoConfig, patchControledMihomoConfig } = useControledMihomoConfig()
|
||||||
|
const { tun } = controledMihomoConfig || {}
|
||||||
|
const { enable } = tun || {}
|
||||||
|
|
||||||
|
const onChange = async (enable: boolean): Promise<void> => {
|
||||||
|
await patchControledMihomoConfig({ tun: { enable } })
|
||||||
|
await patchMihomoConfig({ tun: { enable } })
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
@ -31,7 +41,7 @@ const TunSwitcher: React.FC = () => {
|
|||||||
}}
|
}}
|
||||||
size="sm"
|
size="sm"
|
||||||
isSelected={enable}
|
isSelected={enable}
|
||||||
onValueChange={setEnable}
|
onValueChange={onChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</CardBody>
|
</CardBody>
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import useSWR from 'swr'
|
import useSWR from 'swr'
|
||||||
import { getAppConfig, setAppConfig } from '@renderer/utils/ipc'
|
import { getAppConfig, setAppConfig } from '@renderer/utils/ipc'
|
||||||
|
import { useEffect } from 'react'
|
||||||
|
|
||||||
interface RetuenType {
|
interface RetuenType {
|
||||||
appConfig: IAppConfig | undefined
|
appConfig: IAppConfig | undefined
|
||||||
@ -13,8 +14,18 @@ export const useAppConfig = (): RetuenType => {
|
|||||||
const patchAppConfig = async (value: Partial<IAppConfig>): Promise<void> => {
|
const patchAppConfig = async (value: Partial<IAppConfig>): Promise<void> => {
|
||||||
await setAppConfig(value)
|
await setAppConfig(value)
|
||||||
mutateAppConfig()
|
mutateAppConfig()
|
||||||
|
window.electron.ipcRenderer.send('appConfigUpdated')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.electron.ipcRenderer.on('appConfigUpdated', () => {
|
||||||
|
mutateAppConfig()
|
||||||
|
})
|
||||||
|
return (): void => {
|
||||||
|
window.electron.ipcRenderer.removeAllListeners('appConfigUpdated')
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
appConfig,
|
appConfig,
|
||||||
mutateAppConfig,
|
mutateAppConfig,
|
||||||
|
|||||||
@ -69,3 +69,7 @@ export async function removeProfileItem(id: string): Promise<void> {
|
|||||||
export async function restartCore(): Promise<void> {
|
export async function restartCore(): Promise<void> {
|
||||||
await window.electron.ipcRenderer.invoke('restartCore')
|
await window.electron.ipcRenderer.invoke('restartCore')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function triggerSysProxy(enable: boolean): Promise<void> {
|
||||||
|
await window.electron.ipcRenderer.invoke('triggerSysProxy', enable)
|
||||||
|
}
|
||||||
|
|||||||
39
src/shared/types.d.ts
vendored
39
src/shared/types.d.ts
vendored
@ -63,11 +63,49 @@ interface IMihomoConnectionDetail {
|
|||||||
rulePayload: string
|
rulePayload: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ISysProxyConfig {
|
||||||
|
enable: boolean
|
||||||
|
mode?: 'auto' | 'manual'
|
||||||
|
bypass?: string[]
|
||||||
|
pacScript?: string
|
||||||
|
}
|
||||||
|
|
||||||
interface IAppConfig {
|
interface IAppConfig {
|
||||||
core: 'mihomo' | 'mihomo-alpha'
|
core: 'mihomo' | 'mihomo-alpha'
|
||||||
silentStart: boolean
|
silentStart: boolean
|
||||||
|
sysProxy: ISysProxyConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IMihomoTunConfig {
|
||||||
|
enable: boolean
|
||||||
|
stack?: 'system' | 'gvisor' | 'mixed'
|
||||||
|
'auto-route'?: boolean
|
||||||
|
'auto-redirect'?: boolean
|
||||||
|
'auto-detect-interface'?: boolean
|
||||||
|
'dns-hijack'?: string[]
|
||||||
|
device?: string
|
||||||
|
mtu?: number
|
||||||
|
'strict-route'?: boolean
|
||||||
|
gso?: boolean
|
||||||
|
'gso-max-size'?: number
|
||||||
|
'udp-timeout'?: number
|
||||||
|
'iproute2-table-index'?: number
|
||||||
|
'iproute2-rule-index'?: number
|
||||||
|
'endpoint-independent-nat'?: boolean
|
||||||
|
'route-address-set'?: string[]
|
||||||
|
'route-exclude-address-set'?: string[]
|
||||||
|
'route-address'?: string[]
|
||||||
|
'route-exclude-address'?: string[]
|
||||||
|
'include-interface'?: string[]
|
||||||
|
'exclude-interface'?: string[]
|
||||||
|
'include-uid'?: number[]
|
||||||
|
'include-uid-range'?: string[]
|
||||||
|
'exclude-uid'?: number[]
|
||||||
|
'exclude-uid-range'?: string[]
|
||||||
|
'include-android-user'?: string[]
|
||||||
|
'include-package'?: string[]
|
||||||
|
'exclude-package'?: string[]
|
||||||
|
}
|
||||||
interface IMihomoConfig {
|
interface IMihomoConfig {
|
||||||
'external-controller': string
|
'external-controller': string
|
||||||
secret?: string
|
secret?: string
|
||||||
@ -81,6 +119,7 @@ interface IMihomoConfig {
|
|||||||
proxies?: []
|
proxies?: []
|
||||||
'proxy-groups'?: []
|
'proxy-groups'?: []
|
||||||
rules?: []
|
rules?: []
|
||||||
|
tun: IMihomoTunConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IProfileConfig {
|
interface IProfileConfig {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user