mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2025-12-27 05:00:30 +08:00
feat: add smart core & one-click smart
This commit is contained in:
parent
364578f210
commit
46aa654ee3
@ -51,6 +51,14 @@ else
|
|||||||
log "Warning: mihomo-alpha binary not found at $APP_PATH/Contents/Resources/sidecar/mihomo-alpha"
|
log "Warning: mihomo-alpha binary not found at $APP_PATH/Contents/Resources/sidecar/mihomo-alpha"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -f "$APP_PATH/Contents/Resources/sidecar/mihomo-smart" ]; then
|
||||||
|
chown root:admin "$APP_PATH/Contents/Resources/sidecar/mihomo-smart"
|
||||||
|
chmod +s "$APP_PATH/Contents/Resources/sidecar/mihomo-smart"
|
||||||
|
log "Set permissions for mihomo-smart"
|
||||||
|
else
|
||||||
|
log "Warning: mihomo-smart binary not found at $APP_PATH/Contents/Resources/sidecar/mihomo-smart"
|
||||||
|
fi
|
||||||
|
|
||||||
# 复制 helper 工具
|
# 复制 helper 工具
|
||||||
log "Installing helper tool..."
|
log "Installing helper tool..."
|
||||||
if [ -f "$APP_PATH/Contents/Resources/files/party.mihomo.helper" ]; then
|
if [ -f "$APP_PATH/Contents/Resources/files/party.mihomo.helper" ]; then
|
||||||
|
|||||||
@ -45,6 +45,31 @@ async function getLatestAlphaVersion() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ======= mihomo smart ======= */
|
||||||
|
const MIHOMO_SMART_URL_PREFIX = `https://github.com/vernesong/mihomo/releases/download/Prerelease-Alpha`
|
||||||
|
let MIHOMO_SMART_VERSION
|
||||||
|
|
||||||
|
const MIHOMO_SMART_MAP = {
|
||||||
|
'win32-x64': 'mihomo-windows-amd64-v1-go120-alpha-smart',
|
||||||
|
'win32-ia32': 'mihomo-windows-386-go120-alpha-smart',
|
||||||
|
'win32-arm64': 'mihomo-windows-arm64-alpha-smart',
|
||||||
|
'darwin-x64': 'mihomo-darwin-amd64-v1-go120-alpha-smart',
|
||||||
|
'darwin-arm64': 'mihomo-darwin-arm64-alpha-smart',
|
||||||
|
'linux-x64': 'mihomo-linux-amd64-v1-go120-alpha-smart',
|
||||||
|
'linux-arm64': 'mihomo-linux-arm64-alpha-smart'
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getLatestSmartVersion() {
|
||||||
|
try {
|
||||||
|
// Smart 内核版本
|
||||||
|
MIHOMO_SMART_VERSION = 'ca46a10'
|
||||||
|
console.log(`Using smart version: ${MIHOMO_SMART_VERSION}`)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error with smart version:', error.message)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ======= mihomo release ======= */
|
/* ======= mihomo release ======= */
|
||||||
const MIHOMO_VERSION_URL =
|
const MIHOMO_VERSION_URL =
|
||||||
'https://github.com/MetaCubeX/mihomo/releases/latest/download/version.txt'
|
'https://github.com/MetaCubeX/mihomo/releases/latest/download/version.txt'
|
||||||
@ -87,6 +112,10 @@ if (!MIHOMO_ALPHA_MAP[`${platform}-${arch}`]) {
|
|||||||
throw new Error(`unsupported platform "${platform}-${arch}"`)
|
throw new Error(`unsupported platform "${platform}-${arch}"`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!MIHOMO_SMART_MAP[`${platform}-${arch}`]) {
|
||||||
|
throw new Error(`unsupported platform "${platform}-${arch}"`)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* core info
|
* core info
|
||||||
*/
|
*/
|
||||||
@ -123,13 +152,33 @@ function mihomo() {
|
|||||||
downloadURL
|
downloadURL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mihomoSmart() {
|
||||||
|
const name = MIHOMO_SMART_MAP[`${platform}-${arch}`]
|
||||||
|
const isWin = platform === 'win32'
|
||||||
|
const urlExt = isWin ? 'zip' : 'gz'
|
||||||
|
const downloadURL = `${MIHOMO_SMART_URL_PREFIX}/${name}-${MIHOMO_SMART_VERSION}.${urlExt}`
|
||||||
|
const exeFile = `${name}${isWin ? '.exe' : ''}`
|
||||||
|
const zipFile = `${name}-${MIHOMO_SMART_VERSION}.${urlExt}`
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: 'mihomo-smart',
|
||||||
|
targetFile: `mihomo-smart${isWin ? '.exe' : ''}`,
|
||||||
|
exeFile,
|
||||||
|
zipFile,
|
||||||
|
downloadURL,
|
||||||
|
useProjectRoot: true // 标记需要使用项目根目录
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* download sidecar and rename
|
* download sidecar and rename
|
||||||
*/
|
*/
|
||||||
async function resolveSidecar(binInfo) {
|
async function resolveSidecar(binInfo) {
|
||||||
const { name, targetFile, zipFile, exeFile, downloadURL } = binInfo
|
const { name, targetFile, zipFile, exeFile, downloadURL, useProjectRoot } = binInfo
|
||||||
|
|
||||||
const sidecarDir = path.join(cwd, 'extra', 'sidecar')
|
// 对于 Smart 内核,使用项目根目录而不是 scripts 目录
|
||||||
|
const baseDir = useProjectRoot ? path.dirname(cwd) : cwd
|
||||||
|
const sidecarDir = path.join(baseDir, 'extra', 'sidecar')
|
||||||
const sidecarPath = path.join(sidecarDir, targetFile)
|
const sidecarPath = path.join(sidecarDir, targetFile)
|
||||||
|
|
||||||
fs.mkdirSync(sidecarDir, { recursive: true })
|
fs.mkdirSync(sidecarDir, { recursive: true })
|
||||||
@ -360,6 +409,11 @@ const tasks = [
|
|||||||
func: () => getLatestReleaseVersion().then(() => resolveSidecar(mihomo())),
|
func: () => getLatestReleaseVersion().then(() => resolveSidecar(mihomo())),
|
||||||
retry: 5
|
retry: 5
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'mihomo-smart',
|
||||||
|
func: () => getLatestSmartVersion().then(() => resolveSidecar(mihomoSmart())),
|
||||||
|
retry: 5
|
||||||
|
},
|
||||||
{ name: 'mmdb', func: resolveMmdb, retry: 5 },
|
{ name: 'mmdb', func: resolveMmdb, retry: 5 },
|
||||||
{ name: 'metadb', func: resolveMetadb, retry: 5 },
|
{ name: 'metadb', func: resolveMetadb, retry: 5 },
|
||||||
{ name: 'geosite', func: resolveGeosite, retry: 5 },
|
{ name: 'geosite', func: resolveGeosite, retry: 5 },
|
||||||
@ -432,7 +486,14 @@ async function runTask() {
|
|||||||
break
|
break
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`[ERROR]: task::${task.name} try ${i} ==`, err.message)
|
console.error(`[ERROR]: task::${task.name} try ${i} ==`, err.message)
|
||||||
if (i === task.retry - 1) throw err
|
if (i === task.retry - 1) {
|
||||||
|
if (task.optional) {
|
||||||
|
console.log(`[WARN]: Optional task::${task.name} failed, skipping...`)
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return runTask()
|
return runTask()
|
||||||
|
|||||||
@ -27,3 +27,9 @@ export {
|
|||||||
setOverride,
|
setOverride,
|
||||||
updateOverrideItem
|
updateOverrideItem
|
||||||
} from './override'
|
} from './override'
|
||||||
|
export {
|
||||||
|
createSmartOverride,
|
||||||
|
removeSmartOverride,
|
||||||
|
manageSmartOverride,
|
||||||
|
isSmartOverrideExists
|
||||||
|
} from './smartOverride'
|
||||||
|
|||||||
275
src/main/config/smartOverride.ts
Normal file
275
src/main/config/smartOverride.ts
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
import { getAppConfig } from './app'
|
||||||
|
import { addOverrideItem, removeOverrideItem, getOverrideItem } from './override'
|
||||||
|
|
||||||
|
const SMART_OVERRIDE_ID = 'smart-core-override'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Smart 内核的覆写配置模板
|
||||||
|
*/
|
||||||
|
function generateSmartOverrideTemplate(useLightGBM: boolean, collectData: boolean, strategy: string): string {
|
||||||
|
return `
|
||||||
|
// 配置会在启用 Smart 内核时自动应用
|
||||||
|
|
||||||
|
function main(config) {
|
||||||
|
try {
|
||||||
|
// 确保配置对象存在
|
||||||
|
if (!config || typeof config !== 'object') {
|
||||||
|
console.log('[Smart Override] Invalid config object')
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保代理组配置存在
|
||||||
|
if (!config['proxy-groups']) {
|
||||||
|
config['proxy-groups'] = []
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保代理组是数组
|
||||||
|
if (!Array.isArray(config['proxy-groups'])) {
|
||||||
|
console.log('[Smart Override] proxy-groups is not an array, converting...')
|
||||||
|
config['proxy-groups'] = []
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找现有的 Smart 代理组并更新
|
||||||
|
let smartGroupExists = false
|
||||||
|
for (let i = 0; i < config['proxy-groups'].length; i++) {
|
||||||
|
const group = config['proxy-groups'][i]
|
||||||
|
if (group && group.type === 'smart') {
|
||||||
|
smartGroupExists = true
|
||||||
|
console.log('[Smart Override] Found existing smart group:', group.name)
|
||||||
|
|
||||||
|
if (!group['policy-priority']) {
|
||||||
|
group['policy-priority'] = 'Premium:0.9;SG:1.3'
|
||||||
|
}
|
||||||
|
group.uselightgbm = ${useLightGBM}
|
||||||
|
group.collectdata = ${collectData}
|
||||||
|
group.strategy = '${strategy}'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没有 Smart 组且有可用代理,创建示例组
|
||||||
|
if (!smartGroupExists && config.proxies && Array.isArray(config.proxies) && config.proxies.length > 0) {
|
||||||
|
console.log('[Smart Override] Creating new smart group with', config.proxies.length, 'proxies')
|
||||||
|
|
||||||
|
// 获取所有代理的名称
|
||||||
|
const proxyNames = config.proxies
|
||||||
|
.filter(proxy => proxy && typeof proxy === 'object' && proxy.name)
|
||||||
|
.map(proxy => proxy.name)
|
||||||
|
|
||||||
|
if (proxyNames.length > 0) {
|
||||||
|
const smartGroup = {
|
||||||
|
name: 'Smart Group',
|
||||||
|
type: 'smart',
|
||||||
|
'policy-priority': 'Premium:0.9;SG:1.3',
|
||||||
|
uselightgbm: ${useLightGBM},
|
||||||
|
collectdata: ${collectData},
|
||||||
|
strategy: '${strategy}',
|
||||||
|
proxies: proxyNames
|
||||||
|
}
|
||||||
|
config['proxy-groups'].unshift(smartGroup)
|
||||||
|
console.log('[Smart Override] Created smart group at first position with proxies:', proxyNames)
|
||||||
|
} else {
|
||||||
|
console.log('[Smart Override] No valid proxies found, skipping smart group creation')
|
||||||
|
}
|
||||||
|
} else if (!smartGroupExists) {
|
||||||
|
console.log('[Smart Override] No proxies available, skipping smart group creation')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理规则替换
|
||||||
|
if (config.rules && Array.isArray(config.rules)) {
|
||||||
|
console.log('[Smart Override] Processing rules, original count:', config.rules.length)
|
||||||
|
|
||||||
|
// 收集所有代理组名称
|
||||||
|
const proxyGroupNames = new Set()
|
||||||
|
if (config['proxy-groups'] && Array.isArray(config['proxy-groups'])) {
|
||||||
|
config['proxy-groups'].forEach(group => {
|
||||||
|
if (group && group.name) {
|
||||||
|
proxyGroupNames.add(group.name)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加常见的内置目标
|
||||||
|
const builtinTargets = new Set([
|
||||||
|
'DIRECT',
|
||||||
|
'REJECT',
|
||||||
|
'REJECT-DROP',
|
||||||
|
'PASS',
|
||||||
|
'COMPATIBLE'
|
||||||
|
])
|
||||||
|
|
||||||
|
// 添加常见的规则参数,不应该替换
|
||||||
|
const ruleParams = new Set(['no-resolve', 'force-remote-dns', 'prefer-ipv6'])
|
||||||
|
|
||||||
|
console.log('[Smart Override] Found', proxyGroupNames.size, 'proxy groups:', Array.from(proxyGroupNames))
|
||||||
|
|
||||||
|
let replacedCount = 0
|
||||||
|
config.rules = config.rules.map(rule => {
|
||||||
|
if (typeof rule === 'string') {
|
||||||
|
// 检查是否是复杂规则格式(包含括号的嵌套规则)
|
||||||
|
if (rule.includes('((') || rule.includes('))')) {
|
||||||
|
console.log('[Smart Override] Skipping complex nested rule:', rule)
|
||||||
|
return rule
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理字符串格式的规则
|
||||||
|
const parts = rule.split(',').map(part => part.trim())
|
||||||
|
if (parts.length >= 3) {
|
||||||
|
let targetIndex = -1
|
||||||
|
let targetValue = ''
|
||||||
|
|
||||||
|
for (let i = 2; i < parts.length; i++) {
|
||||||
|
const part = parts[i]
|
||||||
|
if (!ruleParams.has(part)) {
|
||||||
|
targetIndex = i
|
||||||
|
targetValue = part
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetIndex !== -1 && targetValue) {
|
||||||
|
// 检查是否应该替换
|
||||||
|
const shouldReplace = !builtinTargets.has(targetValue) &&
|
||||||
|
(proxyGroupNames.has(targetValue) ||
|
||||||
|
!ruleParams.has(targetValue))
|
||||||
|
|
||||||
|
if (shouldReplace) {
|
||||||
|
parts[targetIndex] = 'Smart Group'
|
||||||
|
replacedCount++
|
||||||
|
console.log('[Smart Override] Replaced rule target:', targetValue, '→ Smart Group')
|
||||||
|
return parts.join(',')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (typeof rule === 'object' && rule !== null) {
|
||||||
|
// 处理对象格式
|
||||||
|
let targetField = ''
|
||||||
|
let targetValue = ''
|
||||||
|
|
||||||
|
if (rule.target) {
|
||||||
|
targetField = 'target'
|
||||||
|
targetValue = rule.target
|
||||||
|
} else if (rule.proxy) {
|
||||||
|
targetField = 'proxy'
|
||||||
|
targetValue = rule.proxy
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetField && targetValue) {
|
||||||
|
const shouldReplace = !builtinTargets.has(targetValue) &&
|
||||||
|
(proxyGroupNames.has(targetValue) ||
|
||||||
|
!ruleParams.has(targetValue))
|
||||||
|
|
||||||
|
if (shouldReplace) {
|
||||||
|
rule[targetField] = 'Smart Group'
|
||||||
|
replacedCount++
|
||||||
|
console.log('[Smart Override] Replaced rule target:', targetValue, '→ Smart Group')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rule
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('[Smart Override] Rules processed, replaced', replacedCount, 'non-DIRECT rules with Smart Group')
|
||||||
|
} else {
|
||||||
|
console.log('[Smart Override] No rules found or rules is not an array')
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('[Smart Override] Configuration processed successfully')
|
||||||
|
return config
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[Smart Override] Error processing config:', error)
|
||||||
|
// 发生错误时返回原始配置,避免破坏整个配置
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建或更新 Smart 内核覆写配置
|
||||||
|
*/
|
||||||
|
export async function createSmartOverride(): Promise<void> {
|
||||||
|
try {
|
||||||
|
// 获取应用配置
|
||||||
|
const {
|
||||||
|
smartCoreUseLightGBM = false,
|
||||||
|
smartCoreCollectData = false,
|
||||||
|
smartCoreStrategy = 'sticky-sessions'
|
||||||
|
} = await getAppConfig()
|
||||||
|
|
||||||
|
// 生成覆写模板
|
||||||
|
const template = generateSmartOverrideTemplate(
|
||||||
|
smartCoreUseLightGBM,
|
||||||
|
smartCoreCollectData,
|
||||||
|
smartCoreStrategy
|
||||||
|
)
|
||||||
|
|
||||||
|
// 检查是否已存在 Smart 覆写配置
|
||||||
|
const existingOverride = await getOverrideItem(SMART_OVERRIDE_ID)
|
||||||
|
|
||||||
|
if (existingOverride) {
|
||||||
|
// 如果已存在,更新配置
|
||||||
|
await addOverrideItem({
|
||||||
|
id: SMART_OVERRIDE_ID,
|
||||||
|
name: 'Smart Core Override',
|
||||||
|
type: 'local',
|
||||||
|
ext: 'js',
|
||||||
|
global: true,
|
||||||
|
file: template
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// 如果不存在,创建新的覆写配置
|
||||||
|
await addOverrideItem({
|
||||||
|
id: SMART_OVERRIDE_ID,
|
||||||
|
name: 'Smart Core Override',
|
||||||
|
type: 'local',
|
||||||
|
ext: 'js',
|
||||||
|
global: true,
|
||||||
|
file: template
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to create Smart override:', error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除 Smart 内核覆写配置
|
||||||
|
*/
|
||||||
|
export async function removeSmartOverride(): Promise<void> {
|
||||||
|
try {
|
||||||
|
const existingOverride = await getOverrideItem(SMART_OVERRIDE_ID)
|
||||||
|
if (existingOverride) {
|
||||||
|
await removeOverrideItem(SMART_OVERRIDE_ID)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to remove Smart override:', error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据应用配置管理 Smart 覆写
|
||||||
|
*/
|
||||||
|
export async function manageSmartOverride(): Promise<void> {
|
||||||
|
const { enableSmartCore = true, enableSmartOverride = true, core } = await getAppConfig()
|
||||||
|
|
||||||
|
if (enableSmartCore && enableSmartOverride && core === 'mihomo-smart') {
|
||||||
|
await createSmartOverride()
|
||||||
|
} else {
|
||||||
|
await removeSmartOverride()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查 Smart 覆写是否存在
|
||||||
|
*/
|
||||||
|
export async function isSmartOverrideExists(): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
const override = await getOverrideItem(SMART_OVERRIDE_ID)
|
||||||
|
return !!override
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -15,7 +15,8 @@ import {
|
|||||||
getControledMihomoConfig,
|
getControledMihomoConfig,
|
||||||
getProfileConfig,
|
getProfileConfig,
|
||||||
patchAppConfig,
|
patchAppConfig,
|
||||||
patchControledMihomoConfig
|
patchControledMihomoConfig,
|
||||||
|
manageSmartOverride
|
||||||
} from '../config'
|
} from '../config'
|
||||||
import { app, dialog, ipcMain, net } from 'electron'
|
import { app, dialog, ipcMain, net } from 'electron'
|
||||||
import {
|
import {
|
||||||
@ -83,6 +84,10 @@ export async function startCore(detached = false): Promise<Promise<void>[]> {
|
|||||||
const { current } = await getProfileConfig()
|
const { current } = await getProfileConfig()
|
||||||
const { tun } = await getControledMihomoConfig()
|
const { tun } = await getControledMihomoConfig()
|
||||||
const corePath = mihomoCorePath(core)
|
const corePath = mihomoCorePath(core)
|
||||||
|
|
||||||
|
// 管理 Smart 内核覆写配置
|
||||||
|
await manageSmartOverride()
|
||||||
|
|
||||||
await generateProfile()
|
await generateProfile()
|
||||||
await checkProfile()
|
await checkProfile()
|
||||||
await stopCore()
|
await stopCore()
|
||||||
@ -249,15 +254,32 @@ async function checkProfile(): Promise<void> {
|
|||||||
mihomoTestDir()
|
mihomoTestDir()
|
||||||
], { env })
|
], { env })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.error('Profile check failed:', error)
|
||||||
|
|
||||||
if (error instanceof Error && 'stdout' in error) {
|
if (error instanceof Error && 'stdout' in error) {
|
||||||
const { stdout } = error as { stdout: string }
|
const { stdout, stderr } = error as { stdout: string; stderr?: string }
|
||||||
|
console.log('Profile check stdout:', stdout)
|
||||||
|
console.log('Profile check stderr:', stderr)
|
||||||
|
|
||||||
const errorLines = stdout
|
const errorLines = stdout
|
||||||
.split('\n')
|
.split('\n')
|
||||||
.filter((line) => line.includes('level=error'))
|
.filter((line) => line.includes('level=error') || line.includes('error'))
|
||||||
.map((line) => line.split('level=error')[1])
|
.map((line) => {
|
||||||
throw new Error(`${i18next.t('mihomo.error.profileCheckFailed')}:\n${errorLines.join('\n')}`)
|
if (line.includes('level=error')) {
|
||||||
|
return line.split('level=error')[1]?.trim() || line
|
||||||
|
}
|
||||||
|
return line.trim()
|
||||||
|
})
|
||||||
|
.filter(line => line.length > 0)
|
||||||
|
|
||||||
|
if (errorLines.length === 0) {
|
||||||
|
const allLines = stdout.split('\n').filter(line => line.trim().length > 0)
|
||||||
|
throw new Error(`${i18next.t('mihomo.error.profileCheckFailed')}:\n${allLines.join('\n')}`)
|
||||||
} else {
|
} else {
|
||||||
throw error
|
throw new Error(`${i18next.t('mihomo.error.profileCheckFailed')}:\n${errorLines.join('\n')}`)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error(`${i18next.t('mihomo.error.profileCheckFailed')}: ${error}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -168,6 +168,21 @@ export const mihomoUpgrade = async (): Promise<void> => {
|
|||||||
return await instance.post('/upgrade')
|
return await instance.post('/upgrade')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Smart 内核 API
|
||||||
|
export const mihomoSmartGroupWeights = async (groupName: string): Promise<Record<string, number>> => {
|
||||||
|
const instance = await getAxios()
|
||||||
|
return await instance.get(`/group/${encodeURIComponent(groupName)}/weights`)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const mihomoSmartFlushCache = async (configName?: string): Promise<void> => {
|
||||||
|
const instance = await getAxios()
|
||||||
|
if (configName) {
|
||||||
|
return await instance.post(`/cache/smart/flush/${encodeURIComponent(configName)}`)
|
||||||
|
} else {
|
||||||
|
return await instance.post('/cache/smart/flush')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const startMihomoTraffic = async (): Promise<void> => {
|
export const startMihomoTraffic = async (): Promise<void> => {
|
||||||
await mihomoTraffic()
|
await mihomoTraffic()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -69,6 +69,10 @@ export function mihomoCoreDir(): string {
|
|||||||
|
|
||||||
export function mihomoCorePath(core: string): string {
|
export function mihomoCorePath(core: string): string {
|
||||||
const isWin = process.platform === 'win32'
|
const isWin = process.platform === 'win32'
|
||||||
|
// 处理 Smart 内核
|
||||||
|
if (core === 'mihomo-smart') {
|
||||||
|
return path.join(mihomoCoreDir(), `mihomo-smart${isWin ? '.exe' : ''}`)
|
||||||
|
}
|
||||||
return path.join(mihomoCoreDir(), `${core}${isWin ? '.exe' : ''}`)
|
return path.join(mihomoCoreDir(), `${core}${isWin ? '.exe' : ''}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,9 @@ import {
|
|||||||
mihomoUpgrade,
|
mihomoUpgrade,
|
||||||
mihomoUpgradeGeo,
|
mihomoUpgradeGeo,
|
||||||
mihomoVersion,
|
mihomoVersion,
|
||||||
patchMihomoConfig
|
patchMihomoConfig,
|
||||||
|
mihomoSmartGroupWeights,
|
||||||
|
mihomoSmartFlushCache
|
||||||
} from '../core/mihomoApi'
|
} from '../core/mihomoApi'
|
||||||
import { checkAutoRun, disableAutoRun, enableAutoRun } from '../sys/autoRun'
|
import { checkAutoRun, disableAutoRun, enableAutoRun } from '../sys/autoRun'
|
||||||
import {
|
import {
|
||||||
@ -141,6 +143,13 @@ export function registerIpcMainHandlers(): void {
|
|||||||
ipcErrorWrapper(mihomoGroupDelay)(group, url)
|
ipcErrorWrapper(mihomoGroupDelay)(group, url)
|
||||||
)
|
)
|
||||||
ipcMain.handle('patchMihomoConfig', (_e, patch) => ipcErrorWrapper(patchMihomoConfig)(patch))
|
ipcMain.handle('patchMihomoConfig', (_e, patch) => ipcErrorWrapper(patchMihomoConfig)(patch))
|
||||||
|
// Smart 内核 API
|
||||||
|
ipcMain.handle('mihomoSmartGroupWeights', (_e, groupName) =>
|
||||||
|
ipcErrorWrapper(mihomoSmartGroupWeights)(groupName)
|
||||||
|
)
|
||||||
|
ipcMain.handle('mihomoSmartFlushCache', (_e, configName) =>
|
||||||
|
ipcErrorWrapper(mihomoSmartFlushCache)(configName)
|
||||||
|
)
|
||||||
ipcMain.handle('checkAutoRun', ipcErrorWrapper(checkAutoRun))
|
ipcMain.handle('checkAutoRun', ipcErrorWrapper(checkAutoRun))
|
||||||
ipcMain.handle('enableAutoRun', ipcErrorWrapper(enableAutoRun))
|
ipcMain.handle('enableAutoRun', ipcErrorWrapper(enableAutoRun))
|
||||||
ipcMain.handle('disableAutoRun', ipcErrorWrapper(disableAutoRun))
|
ipcMain.handle('disableAutoRun', ipcErrorWrapper(disableAutoRun))
|
||||||
@ -251,6 +260,18 @@ export function registerIpcMainHandlers(): void {
|
|||||||
ipcMain.handle('alert', (_e, msg) => {
|
ipcMain.handle('alert', (_e, msg) => {
|
||||||
dialog.showErrorBox('Mihomo Party', msg)
|
dialog.showErrorBox('Mihomo Party', msg)
|
||||||
})
|
})
|
||||||
|
ipcMain.handle('showDetailedError', (_e, title, message) => {
|
||||||
|
dialog.showErrorBox(title, message)
|
||||||
|
})
|
||||||
|
ipcMain.handle('getSmartOverrideContent', async () => {
|
||||||
|
const { getOverrideItem } = await import('../config')
|
||||||
|
try {
|
||||||
|
const override = await getOverrideItem('smart-core-override')
|
||||||
|
return override?.file || null
|
||||||
|
} catch (error) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
})
|
||||||
ipcMain.handle('resetAppConfig', resetAppConfig)
|
ipcMain.handle('resetAppConfig', resetAppConfig)
|
||||||
ipcMain.handle('relaunchApp', () => {
|
ipcMain.handle('relaunchApp', () => {
|
||||||
app.relaunch()
|
app.relaunch()
|
||||||
|
|||||||
@ -1,5 +1,10 @@
|
|||||||
export const defaultConfig: IAppConfig = {
|
export const defaultConfig: IAppConfig = {
|
||||||
core: 'mihomo',
|
core: 'mihomo',
|
||||||
|
enableSmartCore: true,
|
||||||
|
enableSmartOverride: true,
|
||||||
|
smartCoreUseLightGBM: false,
|
||||||
|
smartCoreCollectData: false,
|
||||||
|
smartCoreStrategy: 'sticky-sessions',
|
||||||
silentStart: false,
|
silentStart: false,
|
||||||
appTheme: 'system',
|
appTheme: 'system',
|
||||||
useWindowFrame: false,
|
useWindowFrame: false,
|
||||||
|
|||||||
@ -114,6 +114,15 @@
|
|||||||
"mihomo.selectCoreVersion": "Select Core Version",
|
"mihomo.selectCoreVersion": "Select Core Version",
|
||||||
"mihomo.stableVersion": "Stable",
|
"mihomo.stableVersion": "Stable",
|
||||||
"mihomo.alphaVersion": "Alpha",
|
"mihomo.alphaVersion": "Alpha",
|
||||||
|
"mihomo.smartVersion": "Smart",
|
||||||
|
"mihomo.enableSmartCore": "Enable Smart Core",
|
||||||
|
"mihomo.enableSmartOverride": "Use Auto Smart Rule Override",
|
||||||
|
"mihomo.smartOverrideTooltip": "Use Party's built-in smart override script to extract all nodes from subscriptions and replace default rules. Perfect for users who don't want to tinker, one-click functionality; if using global mode, please select the node named 'Smart Group'",
|
||||||
|
"mihomo.smartCoreUseLightGBM": "Use LightGBM",
|
||||||
|
"mihomo.smartCoreCollectData": "Collect Data",
|
||||||
|
"mihomo.smartCoreStrategy": "Strategy Mode",
|
||||||
|
"mihomo.smartCoreStrategyStickySession": "Sticky Sessions",
|
||||||
|
"mihomo.smartCoreStrategyRoundRobin": "Round Robin",
|
||||||
"mihomo.mixedPort": "Mixed Port",
|
"mihomo.mixedPort": "Mixed Port",
|
||||||
"mihomo.confirm": "Confirm",
|
"mihomo.confirm": "Confirm",
|
||||||
"mihomo.socksPort": "Socks Port",
|
"mihomo.socksPort": "Socks Port",
|
||||||
|
|||||||
@ -114,6 +114,15 @@
|
|||||||
"mihomo.selectCoreVersion": "选择内核版本",
|
"mihomo.selectCoreVersion": "选择内核版本",
|
||||||
"mihomo.stableVersion": "稳定版",
|
"mihomo.stableVersion": "稳定版",
|
||||||
"mihomo.alphaVersion": "预览版",
|
"mihomo.alphaVersion": "预览版",
|
||||||
|
"mihomo.smartVersion": "Smart 版",
|
||||||
|
"mihomo.enableSmartCore": "启用 Smart 内核",
|
||||||
|
"mihomo.enableSmartOverride": "使用自动 Smart 规则覆写",
|
||||||
|
"mihomo.smartOverrideTooltip": "使用 Party 自带的智能覆写脚本,提取订阅中的所有节点,并替换默认规则,适合不想折腾的用户,功能一键生效;如果使用全局模式,请选择名称为“Smart Group 的节点",
|
||||||
|
"mihomo.smartCoreUseLightGBM": "使用 LightGBM",
|
||||||
|
"mihomo.smartCoreCollectData": "收集数据",
|
||||||
|
"mihomo.smartCoreStrategy": "策略模式",
|
||||||
|
"mihomo.smartCoreStrategyStickySession": "粘性会话",
|
||||||
|
"mihomo.smartCoreStrategyRoundRobin": "轮询",
|
||||||
"mihomo.mixedPort": "混合端口",
|
"mihomo.mixedPort": "混合端口",
|
||||||
"mihomo.confirm": "确认",
|
"mihomo.confirm": "确认",
|
||||||
"mihomo.socksPort": "Socks 端口",
|
"mihomo.socksPort": "Socks 端口",
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Button, Divider, Input, Select, SelectItem, Switch } from '@heroui/react'
|
import { Button, Divider, Input, Select, SelectItem, Switch, Tooltip } from '@heroui/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'
|
||||||
@ -6,13 +6,14 @@ import { useAppConfig } from '@renderer/hooks/use-app-config'
|
|||||||
import { useControledMihomoConfig } from '@renderer/hooks/use-controled-mihomo-config'
|
import { useControledMihomoConfig } from '@renderer/hooks/use-controled-mihomo-config'
|
||||||
import { platform } from '@renderer/utils/init'
|
import { platform } from '@renderer/utils/init'
|
||||||
import { FaNetworkWired } from 'react-icons/fa'
|
import { FaNetworkWired } from 'react-icons/fa'
|
||||||
import { IoMdCloudDownload } from 'react-icons/io'
|
import { IoMdCloudDownload, IoMdInformationCircleOutline } from 'react-icons/io'
|
||||||
import PubSub from 'pubsub-js'
|
import PubSub from 'pubsub-js'
|
||||||
import {
|
import {
|
||||||
mihomoUpgrade,
|
mihomoUpgrade,
|
||||||
restartCore,
|
restartCore,
|
||||||
startSubStoreBackendServer,
|
startSubStoreBackendServer,
|
||||||
triggerSysProxy
|
triggerSysProxy,
|
||||||
|
showDetailedError
|
||||||
} from '@renderer/utils/ipc'
|
} from '@renderer/utils/ipc'
|
||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import InterfaceModal from '@renderer/components/mihomo/interface-modal'
|
import InterfaceModal from '@renderer/components/mihomo/interface-modal'
|
||||||
@ -21,7 +22,8 @@ import { useTranslation } from 'react-i18next'
|
|||||||
|
|
||||||
const CoreMap = {
|
const CoreMap = {
|
||||||
mihomo: 'mihomo.stableVersion',
|
mihomo: 'mihomo.stableVersion',
|
||||||
'mihomo-alpha': 'mihomo.alphaVersion'
|
'mihomo-alpha': 'mihomo.alphaVersion',
|
||||||
|
'mihomo-smart': 'mihomo.smartVersion'
|
||||||
}
|
}
|
||||||
|
|
||||||
const Mihomo: React.FC = () => {
|
const Mihomo: React.FC = () => {
|
||||||
@ -29,6 +31,11 @@ const Mihomo: React.FC = () => {
|
|||||||
const { appConfig, patchAppConfig } = useAppConfig()
|
const { appConfig, patchAppConfig } = useAppConfig()
|
||||||
const {
|
const {
|
||||||
core = 'mihomo',
|
core = 'mihomo',
|
||||||
|
enableSmartCore = true,
|
||||||
|
enableSmartOverride = true,
|
||||||
|
smartCoreUseLightGBM = false,
|
||||||
|
smartCoreCollectData = false,
|
||||||
|
smartCoreStrategy = 'sticky-sessions',
|
||||||
maxLogDays = 7,
|
maxLogDays = 7,
|
||||||
sysProxy,
|
sysProxy,
|
||||||
disableLoopbackDetector,
|
disableLoopbackDetector,
|
||||||
@ -82,7 +89,14 @@ const Mihomo: React.FC = () => {
|
|||||||
await patchAppConfig({ [key]: value })
|
await patchAppConfig({ [key]: value })
|
||||||
await restartCore()
|
await restartCore()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
alert(e)
|
const errorMessage = e instanceof Error ? e.message : String(e)
|
||||||
|
console.error('Core restart failed:', errorMessage)
|
||||||
|
|
||||||
|
if (errorMessage.includes('配置检查失败') || errorMessage.includes('Profile Check Failed')) {
|
||||||
|
await showDetailedError(t('mihomo.error.profileCheckFailed'), errorMessage)
|
||||||
|
} else {
|
||||||
|
alert(errorMessage)
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
PubSub.publish('mihomo-core-changed')
|
PubSub.publish('mihomo-core-changed')
|
||||||
}
|
}
|
||||||
@ -92,7 +106,61 @@ const Mihomo: React.FC = () => {
|
|||||||
<>
|
<>
|
||||||
{lanOpen && <InterfaceModal onClose={() => setLanOpen(false)} />}
|
{lanOpen && <InterfaceModal onClose={() => setLanOpen(false)} />}
|
||||||
<BasePage title={t('mihomo.title')}>
|
<BasePage title={t('mihomo.title')}>
|
||||||
|
{/* Smart 内核设置 */}
|
||||||
<SettingCard>
|
<SettingCard>
|
||||||
|
<div className={`rounded-md border p-2 transition-all duration-200 ${
|
||||||
|
enableSmartCore
|
||||||
|
? 'border-blue-300 bg-blue-50/30 dark:border-blue-700 dark:bg-blue-950/20'
|
||||||
|
: 'border-gray-300 bg-gray-50/30 dark:border-gray-600 dark:bg-gray-800/20'
|
||||||
|
}`}>
|
||||||
|
<SettingItem
|
||||||
|
title={t('mihomo.enableSmartCore')}
|
||||||
|
divider
|
||||||
|
>
|
||||||
|
<Switch
|
||||||
|
size="sm"
|
||||||
|
isSelected={enableSmartCore}
|
||||||
|
color={enableSmartCore ? 'primary' : 'default'}
|
||||||
|
onValueChange={async (v) => {
|
||||||
|
await patchAppConfig({ enableSmartCore: v })
|
||||||
|
if (v && core !== 'mihomo-smart') {
|
||||||
|
await handleConfigChangeWithRestart('core', 'mihomo-smart')
|
||||||
|
} else if (!v && core === 'mihomo-smart') {
|
||||||
|
await handleConfigChangeWithRestart('core', 'mihomo')
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</SettingItem>
|
||||||
|
|
||||||
|
{/* Smart 覆写开关 */}
|
||||||
|
{enableSmartCore && (
|
||||||
|
<SettingItem
|
||||||
|
title={
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span>{t('mihomo.enableSmartOverride')}</span>
|
||||||
|
<Tooltip
|
||||||
|
content={t('mihomo.smartOverrideTooltip')}
|
||||||
|
placement="top"
|
||||||
|
className="max-w-xs"
|
||||||
|
>
|
||||||
|
<IoMdInformationCircleOutline className="text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300 cursor-help" />
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
divider={core === 'mihomo-smart'}
|
||||||
|
>
|
||||||
|
<Switch
|
||||||
|
size="sm"
|
||||||
|
isSelected={enableSmartOverride}
|
||||||
|
color="primary"
|
||||||
|
onValueChange={async (v) => {
|
||||||
|
await patchAppConfig({ enableSmartOverride: v })
|
||||||
|
await restartCore()
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</SettingItem>
|
||||||
|
)}
|
||||||
|
|
||||||
<SettingItem
|
<SettingItem
|
||||||
title={t('mihomo.coreVersion')}
|
title={t('mihomo.coreVersion')}
|
||||||
actions={
|
actions={
|
||||||
@ -128,23 +196,94 @@ const Mihomo: React.FC = () => {
|
|||||||
<IoMdCloudDownload className="text-lg" />
|
<IoMdCloudDownload className="text-lg" />
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
divider
|
divider={enableSmartCore && core === 'mihomo-smart'}
|
||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
classNames={{ trigger: 'data-[hover=true]:bg-default-200' }}
|
classNames={{
|
||||||
|
trigger: enableSmartCore
|
||||||
|
? 'data-[hover=true]:bg-blue-100 dark:data-[hover=true]:bg-blue-900/50'
|
||||||
|
: 'data-[hover=true]:bg-default-200'
|
||||||
|
}}
|
||||||
className="w-[100px]"
|
className="w-[100px]"
|
||||||
size="sm"
|
size="sm"
|
||||||
aria-label={t('mihomo.selectCoreVersion')}
|
aria-label={t('mihomo.selectCoreVersion')}
|
||||||
selectedKeys={new Set([core])}
|
selectedKeys={new Set([core])}
|
||||||
disallowEmptySelection={true}
|
disallowEmptySelection={true}
|
||||||
onSelectionChange={async (v) => {
|
onSelectionChange={async (v) => {
|
||||||
handleConfigChangeWithRestart('core', v.currentKey as 'mihomo' | 'mihomo-alpha')
|
handleConfigChangeWithRestart('core', v.currentKey as 'mihomo' | 'mihomo-alpha' | 'mihomo-smart')
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{enableSmartCore ? (
|
||||||
|
<SelectItem key="mihomo-smart">{t(CoreMap['mihomo-smart'])}</SelectItem>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
<SelectItem key="mihomo">{t(CoreMap['mihomo'])}</SelectItem>
|
<SelectItem key="mihomo">{t(CoreMap['mihomo'])}</SelectItem>
|
||||||
<SelectItem key="mihomo-alpha">{t(CoreMap['mihomo-alpha'])}</SelectItem>
|
<SelectItem key="mihomo-alpha">{t(CoreMap['mihomo-alpha'])}</SelectItem>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Select>
|
</Select>
|
||||||
</SettingItem>
|
</SettingItem>
|
||||||
|
|
||||||
|
{/* Smart 内核配置项 */}
|
||||||
|
{enableSmartCore && core === 'mihomo-smart' && (
|
||||||
|
<>
|
||||||
|
<SettingItem
|
||||||
|
title={t('mihomo.smartCoreUseLightGBM')}
|
||||||
|
divider
|
||||||
|
>
|
||||||
|
<Switch
|
||||||
|
size="sm"
|
||||||
|
color="primary"
|
||||||
|
isSelected={smartCoreUseLightGBM}
|
||||||
|
onValueChange={async (v) => {
|
||||||
|
await patchAppConfig({ smartCoreUseLightGBM: v })
|
||||||
|
await restartCore()
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</SettingItem>
|
||||||
|
|
||||||
|
<SettingItem
|
||||||
|
title={t('mihomo.smartCoreCollectData')}
|
||||||
|
divider
|
||||||
|
>
|
||||||
|
<Switch
|
||||||
|
size="sm"
|
||||||
|
color="primary"
|
||||||
|
isSelected={smartCoreCollectData}
|
||||||
|
onValueChange={async (v) => {
|
||||||
|
await patchAppConfig({ smartCoreCollectData: v })
|
||||||
|
await restartCore()
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</SettingItem>
|
||||||
|
|
||||||
|
<SettingItem
|
||||||
|
title={t('mihomo.smartCoreStrategy')}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
classNames={{ trigger: 'data-[hover=true]:bg-blue-100 dark:data-[hover=true]:bg-blue-900/50' }}
|
||||||
|
className="w-[150px]"
|
||||||
|
size="sm"
|
||||||
|
aria-label={t('mihomo.smartCoreStrategy')}
|
||||||
|
selectedKeys={new Set([smartCoreStrategy])}
|
||||||
|
disallowEmptySelection={true}
|
||||||
|
onSelectionChange={async (v) => {
|
||||||
|
const strategy = v.currentKey as 'sticky-sessions' | 'round-robin'
|
||||||
|
await patchAppConfig({ smartCoreStrategy: strategy })
|
||||||
|
await restartCore()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SelectItem key="sticky-sessions">{t('mihomo.smartCoreStrategyStickySession')}</SelectItem>
|
||||||
|
<SelectItem key="round-robin">{t('mihomo.smartCoreStrategyRoundRobin')}</SelectItem>
|
||||||
|
</Select>
|
||||||
|
</SettingItem>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</SettingCard>
|
||||||
|
|
||||||
|
{/* 常规内核设置 */}
|
||||||
|
<SettingCard>
|
||||||
<SettingItem title={t('mihomo.mixedPort')} divider>
|
<SettingItem title={t('mihomo.mixedPort')} divider>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
{mixedPortInput !== mixedPort && (
|
{mixedPortInput !== mixedPort && (
|
||||||
|
|||||||
@ -79,6 +79,22 @@ export async function mihomoGroupDelay(group: string, url?: string): Promise<IMi
|
|||||||
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('mihomoGroupDelay', group, url))
|
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('mihomoGroupDelay', group, url))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function mihomoSmartGroupWeights(groupName: string): Promise<Record<string, number>> {
|
||||||
|
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('mihomoSmartGroupWeights', groupName))
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function mihomoSmartFlushCache(configName?: string): Promise<void> {
|
||||||
|
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('mihomoSmartFlushCache', configName))
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function showDetailedError(title: string, message: string): Promise<void> {
|
||||||
|
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('showDetailedError', title, message))
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getSmartOverrideContent(): Promise<string | null> {
|
||||||
|
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('getSmartOverrideContent'))
|
||||||
|
}
|
||||||
|
|
||||||
export async function patchMihomoConfig(patch: Partial<IMihomoConfig>): Promise<void> {
|
export async function patchMihomoConfig(patch: Partial<IMihomoConfig>): Promise<void> {
|
||||||
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('patchMihomoConfig', patch))
|
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('patchMihomoConfig', patch))
|
||||||
}
|
}
|
||||||
|
|||||||
7
src/shared/types.d.ts
vendored
7
src/shared/types.d.ts
vendored
@ -216,7 +216,12 @@ interface ISysProxyConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface IAppConfig {
|
interface IAppConfig {
|
||||||
core: 'mihomo' | 'mihomo-alpha'
|
core: 'mihomo' | 'mihomo-alpha' | 'mihomo-smart'
|
||||||
|
enableSmartCore: boolean
|
||||||
|
enableSmartOverride: boolean
|
||||||
|
smartCoreUseLightGBM: boolean
|
||||||
|
smartCoreCollectData: boolean
|
||||||
|
smartCoreStrategy: 'sticky-sessions' | 'round-robin'
|
||||||
disableLoopbackDetector: boolean
|
disableLoopbackDetector: boolean
|
||||||
disableEmbedCA: boolean
|
disableEmbedCA: boolean
|
||||||
disableSystemCA: boolean
|
disableSystemCA: boolean
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user