From e336b3c88db88de644f06994465553100d097721 Mon Sep 17 00:00:00 2001 From: zjdndjf <186369260+zjdndjf@users.noreply.github.com> Date: Fri, 10 Apr 2026 21:25:20 +0800 Subject: [PATCH] fix: apply smart override after rule override --- src/main/config/smartOverride.ts | 4 +- src/main/core/factory.ts | 143 ++++++++++++++++++------------- 2 files changed, 85 insertions(+), 62 deletions(-) diff --git a/src/main/config/smartOverride.ts b/src/main/config/smartOverride.ts index 48ac728..680f337 100644 --- a/src/main/config/smartOverride.ts +++ b/src/main/config/smartOverride.ts @@ -131,11 +131,11 @@ function main(config) { // 找到策略组名称的位置 let targetIndex = -1 - // MATCH 规则:MATCH,策略组 + // MATCH 规则:MATCH,策略组 if (parts[0] === 'MATCH' && parts.length === 2) { targetIndex = 1 } else if (parts.length >= 3) { - // 其他规则:TYPE,MATCHER,策略组[,参数...] + // 其他规则:TYPE,MATCHER,策略组 [,参数...] // 策略组通常在第 3 个位置(索引 2),但需要跳过参数 for (let i = 2; i < parts.length; i++) { if (!ruleParamsSet.has(parts[i])) { diff --git a/src/main/core/factory.ts b/src/main/core/factory.ts index a674372..1b201b4 100644 --- a/src/main/core/factory.ts +++ b/src/main/core/factory.ts @@ -24,6 +24,7 @@ import { deepMerge } from '../utils/merge' import { createLogger } from '../utils/logger' const factoryLogger = createLogger('Factory') +const SMART_OVERRIDE_ID = 'smart-core-override' let runtimeConfigStr: string = '' let runtimeConfig: IMihomoConfig = {} as IMihomoConfig @@ -68,7 +69,11 @@ export async function generateProfile(): Promise { controlSniff = true, useNameserverPolicy } = await getAppConfig() - const currentProfile = await overrideProfile(current, await getProfile(current)) + const baseProfile = await getProfile(current) + const overrideIds = await getOrderedOverrideIds(current) + const profileWithNormalOverride = await applyOverrides(baseProfile, overrideIds.normal) + const profileWithRuleOverride = await applyRuleOverride(current, profileWithNormalOverride) + const currentProfile = await applyOverrides(profileWithRuleOverride, overrideIds.smart) let controledMihomoConfig = await getControledMihomoConfig() // 根据开关状态过滤控制配置 @@ -84,60 +89,6 @@ export async function generateProfile(): Promise { delete controledMihomoConfig?.dns?.['nameserver-policy'] } - // 应用规则文件 - try { - const ruleFilePath = rulePath(current || 'default') - if (existsSync(ruleFilePath)) { - const ruleFileContent = await readFile(ruleFilePath, 'utf-8') - const ruleData = parse(ruleFileContent) as { - prepend?: string[] - append?: string[] - delete?: string[] - } | null - - if (ruleData && typeof ruleData === 'object') { - // 确保 rules 数组存在 - if (!currentProfile.rules) { - currentProfile.rules = [] as unknown as [] - } - - let rules = [...currentProfile.rules] as unknown as string[] - - // 处理前置规则 - if (ruleData.prepend?.length) { - const { normalRules: prependRules, insertRules } = processRulesWithOffset( - ruleData.prepend, - rules - ) - rules = [...prependRules, ...insertRules] - } - - // 处理后置规则 - if (ruleData.append?.length) { - const { normalRules: appendRules, insertRules } = processRulesWithOffset( - ruleData.append, - rules, - true - ) - rules = [...insertRules, ...appendRules] - } - - // 处理删除规则 - if (ruleData.delete?.length) { - const deleteSet = new Set(ruleData.delete) - rules = rules.filter((rule) => { - const ruleStr = Array.isArray(rule) ? rule.join(',') : rule - return !deleteSet.has(ruleStr) - }) - } - - currentProfile.rules = rules as unknown as [] - } - } - } catch (error) { - factoryLogger.error('Failed to read or apply rule file', error) - } - const profile = deepMerge(currentProfile, controledMihomoConfig) // 确保可以拿到基础日志信息 // 使用 debug 可以调试内核相关问题 `debug/pprof` @@ -160,6 +111,66 @@ export async function generateProfile(): Promise { return current } +async function applyRuleOverride( + current: string | undefined, + profile: IMihomoConfig +): Promise { + try { + const ruleFilePath = rulePath(current || 'default') + if (!existsSync(ruleFilePath)) { + return profile + } + + const ruleFileContent = await readFile(ruleFilePath, 'utf-8') + const ruleData = parse(ruleFileContent) as { + prepend?: string[] + append?: string[] + delete?: string[] + } | null + + if (!ruleData || typeof ruleData !== 'object') { + return profile + } + + if (!profile.rules) { + profile.rules = [] as unknown as [] + } + + let rules = [...profile.rules] as unknown as string[] + + if (ruleData.prepend?.length) { + const { normalRules: prependRules, insertRules } = processRulesWithOffset( + ruleData.prepend, + rules + ) + rules = [...prependRules, ...insertRules] + } + + if (ruleData.append?.length) { + const { normalRules: appendRules, insertRules } = processRulesWithOffset( + ruleData.append, + rules, + true + ) + rules = [...insertRules, ...appendRules] + } + + if (ruleData.delete?.length) { + const deleteSet = new Set(ruleData.delete) + rules = rules.filter((rule) => { + const ruleStr = Array.isArray(rule) ? rule.join(',') : rule + return !deleteSet.has(ruleStr) + }) + } + + profile.rules = rules as unknown as [] + return profile + } catch (error) { + factoryLogger.error('Failed to read or apply rule file', error) + return profile + } +} + async function prepareProfileWorkDir(current: string | undefined): Promise { if (!existsSync(mihomoProfileWorkDir(current))) { await mkdir(mihomoProfileWorkDir(current), { recursive: true }) @@ -193,14 +204,26 @@ async function prepareProfileWorkDir(current: string | undefined): Promise ]) } -async function overrideProfile( - current: string | undefined, - profile: IMihomoConfig -): Promise { +async function getOrderedOverrideIds(current: string | undefined): Promise<{ + normal: string[] + smart: string[] +}> { const { items = [] } = (await getOverrideConfig()) || {} const globalOverride = items.filter((item) => item.global).map((item) => item.id) const { override = [] } = (await getProfileItem(current)) || {} - for (const ov of new Set(globalOverride.concat(override))) { + const orderedOverrideIds = [...new Set(globalOverride.concat(override))] + + return { + normal: orderedOverrideIds.filter((id) => id !== SMART_OVERRIDE_ID), + smart: orderedOverrideIds.filter((id) => id === SMART_OVERRIDE_ID) + } +} + +async function applyOverrides( + profile: IMihomoConfig, + overrideIds: string[] +): Promise { + for (const ov of overrideIds) { const item = await getOverrideItem(ov) const content = await getOverride(ov, item?.ext || 'js') switch (item?.ext) {