路由详情加附加规则:每路入站自己的分流表

用内核的 sub-rules 机制:listener 写 rule: 指向顶层 sub-rules 里的表
(listener/inbound/base.go:96,tunnel.go:713-721)。两个硬约束决定了
形态:proxy 优先级更高且完全短路规则匹配(tunnel.go:318-325),有附加
规则时 listener 只能写 rule;子规则表没命中时兜底是 DIRECT 而不是这一
路的出站(tunnel.go match 循环末尾),表底那条 MATCH,专属组 是承重的,
由 Patchbay 自动维护、界面上单独画不参与编辑。不变式:附加规则空 ⇔
proxy 直连专属组,非空 ⇔ rule 形态。

三处既有逻辑教会认 rule 形态:applySetup 不再无条件写 proxy(会把附加
规则静默短路掉);referencesTo 扫 sub-rules 里的规则——表底 MATCH 是
rule 形态下专属组活着的唯一理由,不数它就会被当孤儿清掉;pruneGenerated
清理没有 listener 引用的生成表。panelGroups 和 syncGenerated 的「是否
由 Patchbay 接线」收敛成一个 managedWiring。

listener 的 rule 指向不存在的表时内核静默退回全局规则(getRules 的
else 分支),-t 和重载都不拦,自检里补上这条(vendor 本地改动,记入
ORIGIN.md)。界面:详情列新增附加规则区块,逐条增删改和排序复用
RuleForm,带内网直连预设;生成形状过了 mihomo -t 实测。
This commit is contained in:
2026-08-12 04:01:08 +08:00
parent d1214d4cbd
commit c3c0f56e56
6 changed files with 507 additions and 11 deletions
+1
View File
@@ -12,6 +12,7 @@
|---|---|---|
| `index.test.ts` | 测试框架的导入从 `vitest` 换成 `bun:test` | 本项目用 Bun 自带的测试运行器,不引入 vitest。两者的 `describe` / `it` / `expect` 接口一致,用例本身一行没动 |
| `index.ts` | `stringifyTouched` 结尾的 `String(doc)` 换成 `doc.toString({ flowCollectionPadding: false, lineWidth: 0 })` | 上游用默认输出参数,会把 `[a, b]` 改写成 `[ a, b ]`,并且在超过 80 列时折行——目标机器的订阅地址就够长。这两样都会让没被改动的段落出现在 diff 里 |
| `index.ts` | `validateDocument` 末尾新增:listener 的 `rule:` 指向不存在的 sub-rules 表时报 `missing-reference` | 内核对这种引用静默退回全局规则(tunnel.go getRules 的 else 分支),`mihomo -t` 和重载都不会拦,只有这层自检能拦住 |
## 配套的本项目代码
+19
View File
@@ -1056,6 +1056,25 @@ export function validateDocument(data: ConfigObject): ConfigDiagnostic[] {
}
})
}
// Patchbay local addition (see ORIGIN.md): a listener whose `rule:` names a
// missing sub-rules table silently falls back to the global rules (mihomo
// tunnel.go getRules), so neither `mihomo -t` nor a reload will ever flag it.
if (Array.isArray(data.listeners)) {
data.listeners.forEach((entry, index) => {
if (!isObject(entry)) return
const rule = entry.rule
if (typeof rule !== 'string' || !rule) return
if (!isObject(subRules) || !(rule in subRules)) {
diagnostics.push({
path: ['listeners', index, 'rule'],
code: 'missing-reference',
message: `Unknown sub-rule: ${rule}`,
severity: 'error',
})
}
})
}
return diagnostics
}