im0o
|
cb8effe05b
|
把入站固定到某条订阅线路
订阅线路不在内核的全局名字表里,入站的 proxy 指不到它(决策记录 0005)。做法是自动建
一个只装它的策略组再指过去,用户看到的只是「这个口固定走这条线」,组是实现细节:
不出现在策略组列表里,列表和详情里都显示成线路本身的名字,没人再引用时自动删掉。
筛选条件必须做对两件事,都写了测试:转义正则元字符(线路名形如 [vmess]DMIT.LAX.Pro
里的方括号和点不转义会匹配错),以及前后加锚点(内核是部分匹配,不加锚点时「香港01」
会把「香港011」也捞进来)。线路名含反引号时表达不了——那是内核切分多个筛选条件的
分隔符——这种情况明说做不到而不是生成一个会静默匹配错的组。
实测:生成的配置 mihomo -t 通过;起一个临时内核问 /proxies,这个组解析出来的成员
恰好只有那一条线路,且确实进了名字表所以入站指得到。
|
2026-08-10 19:33:44 +08:00 |
|
im0o
|
08ab73a4f1
|
默认入站不再显示整块出站选择
它由配置顶层的端口字段声明,没有 proxy 字段可写,画一排点不了的卡片只会让人以为
是坏了。之前藏掉这块会让面板变空,所以留着;现在「流量去向」那一节顶上来了,
默认入站照样有内容可看——它的流量去向由规则表决定,那一节反而是它唯一相关的部分。
「默认」标记和不给删除本来就有:列表里带 tag,详情里不显示编辑和删除按钮。
|
2026-08-10 19:13:54 +08:00 |
|
im0o
|
43d410d02c
|
去掉解释性提示和链条上的类型标注
链条回到纯名字。类型标注和「某某组自己决定选中哪一条」那句解释是我上一版加的,
用来说明为什么那一层点不了——但不能点的东西本来就没画出来,解释一个看不见的东西
只是噪音。
默认入站那条压成一句,内核未连接那条压成四个字,没有附加规则时整行不显示而不是
显示一个破折号。shared 里跟着没人用的 autoDecidedHops 一并删掉。
|
2026-08-10 18:58:34 +08:00 |
|
im0o
|
5049879a70
|
可切换的那一层改成最后一个 Selector,不是最后一个有成员的组
原来的规则会落在 AUTO 上,而 AUTO 是 url-test 类型——它按延迟自己挑,手动选它没有
意义,点完会被下一轮延迟测试算回去。内核里只有 Selector 是「由人来选」的
(constant/adapters.go:240-248 列了全部五种),URLTest 挑最快、Fallback 挑第一个可用、
LoadBalance 分摊,Relay 已被移除。
链条上现在每一跳都标出类型(PROXY Selector → AUTO URLTest → 线路 Vless),并明说
自动决定的那几层不接受手动指定——不说清楚的话,用户看到链条里有个组却点不了,
只会以为是坏了。
|
2026-08-10 18:38:59 +08:00 |
|
im0o
|
c5ac59ecf9
|
按审查结论重构:先补测试网,再搬代码
顺序是刻意的。前端一行测试都没有,直接挪代码挪坏了 bun test 不会红,所以先把纯逻辑
抽到能被测试的位置并补上用例,最后才动组件。测试从 37 条增加到 77 条。
抽出来的四块:
- shared/outbound-chain.ts 「这个端口现在走哪条线」的链路解析,带防环,9 条测试
- web/delay-test.ts 延迟测试失败时说什么,6 个分支原本一条测试都没有
- web/runtime.ts 运行时状态的模块级单例,照 prefs.ts 已有的模式
- web/components/InboundList.vue 入站列表
出站的文本原本散成四份(读一份、显示一份、写回一份、表单又抄一份),加一种出站模式
要同时改四处,漏一个就是显示与写回不一致。合并成 OUTBOUND_PRESETS 一张表。
给认证和透传白名单补了 20 条测试。两者都是安全边界、都是纯函数、都不需要内核在线,
之前却只靠需要活内核的冒烟脚本间接覆盖。其中「形似但不是健康检查的路径」几条确认了
正则没写松。
另外:配置快照不再把整份文件原文下发(前端从不读,白白让响应体积翻倍);
yaml-cosmetics 的测试改走生产路径,之前它自己拼了一遍三步流程,落盘链路漏掉其中一步
测试照样会绿。
|
2026-08-10 18:21:23 +08:00 |
|
im0o
|
6b208847a2
|
修掉审查查出的五个问题
保存失败会丢掉整张表单:对话框在 await commit 之前就关了,重开是空的。改成只有成功才关。
错误响应原本有两种形状({error} 和 {message,hint}),前端只读 message,于是服务端
写好的中文提示一律退化成「请求失败(HTTP 4xx)」。统一成 { message, hint? }。
路由处理器没有兜底:请求体不是合法 JSON、配置文件运行中被删,都会返回一个没有响应体
的 500。这条链路的立意是出事时把用户救回来,而出事时给的偏偏是最没信息量的一句话。
延迟测试失败被写进 done,而 done 的样式是成功绿。拆出中性的 notice——测不通是关于
线路的结论,既不是操作失败也不是成功。
刷新原本只有一个动词,测一条线路的延迟会导致整份配置被重读、重新解析、跑一遍引用校验,
外加四个往返。拆成 saved 和 runtime-changed 两个事件,运行时动作只重读运行时状态。
|
2026-08-10 14:29:46 +08:00 |
|
im0o
|
007d137b5d
|
修掉开发模式下前端加载不出来的问题
Vite 的代理规则写成字符串 '/api' 是前缀匹配,会把 web/api.ts 这个模块的请求
(路径 /api.ts)也转发给后端,于是开发模式下整个页面都起不来。改成正则 '^/api/'。
实测 /api.ts、/App.vue、/main.ts 现在都返回 200 text/javascript。
|
2026-08-10 14:18:58 +08:00 |
|
im0o
|
6029eacf50
|
修掉资源 404 被当成页面返回的 bug;加一条命令起开发模式
单页应用的兜底原本对任何找不到的路径都回 index.html,包括带扩展名的资源。
资源文件是带哈希的,每次打包换名字,浏览器缓存了旧 index.html 时会去请求一个已经
不存在的 .js,然后拿到一份 HTML,报出「MIME 类型不对」——一句完全指不到病根的错误。
现在带扩展名的路径找不到就回 404,index.html 也不再允许缓存。
另外 dev:all 一条命令同时起后端(--hot)和前端(Vite),省掉记两个终端和两个端口。
|
2026-08-10 14:15:22 +08:00 |
|
im0o
|
860da5d28f
|
订阅线路的类型、延迟和测速都改走 provider 接口
404 不是 bug。内核的 /proxies 只返回全局名字表(内置出站、自有线路、策略组),
订阅线路不在里面——跟「订阅线路不能被入站直接引用」是同一条约束,我没想到它同样
适用于运行时接口。所以 /proxies/{订阅线路}/delay 一律 404,而订阅线路的卡片也一直
没有协议和延迟,因为那些数据同样查不到。
现在运行时状态从两处合成:/proxies 给内置出站和策略组,/providers/proxies 给订阅线路
(它返回的线路本来就带完整的协议和延迟历史)。测速按线路归属选接口,订阅线路走
{订阅}/{线路}/healthcheck。实测该接口对同一条线路返回 200 和 325 毫秒。
|
2026-08-10 13:41:42 +08:00 |
|
im0o
|
71adcd60ef
|
界面文案改成中性措辞;延迟测试报出真实原因
原来那句「X 测不通」把两种要查不同地方的情况混在了一起。内核的语义是精确的
(hub/route/proxies.go:122-145):504 表示在给定超时内没有完成,503 表示连接建立失败
或测得延迟为 0。现在分开报,超时会写明是几秒,503 且内核没给具体错误时说明可能是
线路失效或本机到该服务器网络不通。
其余文案统一过一遍:「本机之外也能连」「这个名字已经被占用了」「还没做」这类口语改成
「允许来自其它主机的连接」「名称已存在」「尚未实现」。
|
2026-08-10 13:38:02 +08:00 |
|
im0o
|
e8b8181ef6
|
本地开发换成真订阅;闪电挪到卡片上;忙碌状态改成按卡片
占位线路删了。它们指向 127.0.0.1:1080,从来没测通过,而 URLTest 只在你选的那条
「对测试地址是活的」时才认账(urltest.go:106-111)——所以点了立刻被切回去,
一个正常行为看起来像 bug。现在本地内核直接用真订阅,通过隧道拉。
订阅地址带访问令牌,不能进 git:dev/config.yaml 变成模板,dev:reset 从 .env 取值生成
dev/home/config.yaml。顺带确认内核认 base64 分享链接格式(provider.go:384-390 回退到
ConvertsV2Ray),所以 Sub-Store 的输出直接能用。
闪电从组标题挪到每张卡的左下角,也就是延迟显示的位置:测过显示毫秒数,没测过显示闪电,
两种都能点,点了测这一条。忙碌状态从「禁用整个界面」改成只有正在提交的那张卡显示虚线边框。
|
2026-08-10 13:21:27 +08:00 |
|
im0o
|
5cdc183190
|
去掉转换入口,加测延迟,改掉刷新时丢状态的毛病
最要紧的是第三条:之前每次改完都会先切到「读取中」,页面被拆掉重建,
选中的那一路入站随之丢失,改个设置还得重新找回原来的位置。现在只有首次加载显示占位,
之后都是原地更新。切换策略组还做成了乐观更新——那一步不写配置文件,
没必要让点击等一个往返,真失败了随后的刷新会纠正回来。
测延迟按钮让内核并发测整个策略组。测不通是关于线路的结论而不是 Patchbay 出了问题,
所以全部超时用中性提示,不弹红框。
|
2026-08-10 12:53:56 +08:00 |
|
im0o
|
0062a261f7
|
补上真正日常要点的那个动作:切换策略组当前选中谁
之前的面板只做了「这个入站指向哪个出站」,那是改配置文件。但 metacubexd 里点一条线路
改的根本不是入站,是策略组的当前选中——调 PUT /proxies/{组},不写文件、立刻生效。
mixed-port 走规则表,末尾 MATCH,PROXY 把流量交给 PROXY 组,所以换那个组的选中就等于
换了这个端口的出口。这是每天都要点的动作,之前整个漏了。
面板顶部现在显示完整链条(PROXY → AUTO → 某条线路),并让人在最后一个策略组上换选中。
只显示第一层等于没回答「这个端口现在走哪条线」。
透传的白名单里为此开了唯一一个写操作,单独一条路由而不是放开整个转发。
|
2026-08-10 12:44:31 +08:00 |
|
im0o
|
f97981b146
|
默认入站:显示可选出站,并给一条转成命名入站的路
上一版把默认入站的整个出站块都藏了,结果策略组也看不见。改成只藏 RULE/DIRECT/GLOBAL
那三张卡(它固定是 RULE),策略组和线路照常列出来当上下文,只是不可点。
顺带修一个显示错误:老式顶层端口没有 listen 字段,实际地址是内核从 allow-lan 和
bind-address 推出来的(listener/listener.go:709-718)——allow-lan 关着时绑的是
127.0.0.1,而界面一律显示 0.0.0.0,会让人以为局域网连得上。
转换时会把老式端口字段删掉并把推导出的地址显式写进 listen:不删会导致同一个端口被声明
两次内核起不来,不写 listen 则以后改 allow-lan 会连带影响这个端口。
|
2026-08-10 12:37:33 +08:00 |
|
im0o
|
cf24755375
|
路由页做完:新增、编辑、删除入站
弹窗用原生 <dialog>,焦点捕获和 Esc 关闭是浏览器自带的,自己实现只会更差。
表单字段由那张从内核源码提取的字段表驱动:公共字段加当前类型的必填项。
20 种类型合计 398 个字段,全铺出来没人填得完,冷门的留给配置文件手写。
默认入站不再显示出站选择块——那一整块对它都是不可选的,画出来只是噪音,
换成一行说明。另外去掉了行里那根装饰线,导航把仪表盘挪到路由前面。
|
2026-08-10 12:27:39 +08:00 |
|
im0o
|
e678e7716b
|
限制接线的宽度,别让它看起来像折线图
那根线原本占满整个弹性列,被误认成流量曲线。它纯粹是装饰,不承载任何数据,
而一个看起来像信息却什么都不表示的东西就是缺陷。收窄到 72px,明确读作一段线。
|
2026-08-10 12:13:02 +08:00 |
|
im0o
|
69ae918e7c
|
出站选项改成卡片,带协议和延迟
参照 fl-clash:一张卡三行——名字、协议(策略组显示「类型(当前选中)」)、最近一次延迟。
延迟按 200/500 毫秒分三档着色,没测过就留空而不是显示 0。
这些数据配置文件里都没有,全部来自内核的 /proxies。
另外主区最大宽度从 960 提到 1600,去掉选中行的左侧高亮条。
|
2026-08-10 12:09:03 +08:00 |
|
im0o
|
206e14c7e7
|
路由页改成主从布局,出站可以真的改了
右侧详情面板取代原来的手风琴展开:空间用起来了,选中状态更清楚,行也不会被推来推去。
出站选择做成分组的按钮网格而不是下拉框——一眼看得到全部可选项和当前状态。
点一下就走完整的落盘链路(校验、备份、写入、重载),失败时按停在哪一步显示不同的话。
订阅线路那一档暂时禁用:选中它需要先自动建一个筛选组,那部分还没做。
顺带两处从截图里看出来的问题:连接线原本是固定 40px 的短横,读起来像装饰不像连接,
改成占据弹性列真的把两头连起来;默认入站的名字原本是「HTTP 和 SOCKS5 共用」,
和类型列重复,改成它来自的配置键 mixed-port。
|
2026-08-10 11:55:53 +08:00 |
|
im0o
|
1fc052028e
|
改成左右布局,接上图标,措辞换成配置里的原词
图标用 unplugin-icons 在打包时内联成 SVG,运行时不发网络请求——目标机器可能没外网,
而且一个图标一次请求对 2 核的机器不划算。autoInstall 关掉,不让构建过程偷偷联网装东西。
出站显示从「跟着规则走」改成 RULE,其余解释性长句删掉或收进 title。
新增了紧凑模式(只显示图标),默认关:这工具是隔一阵子才动一次的,纯图标对偶尔来的人不友好。
|
2026-08-10 11:37:07 +08:00 |
|
im0o
|
c6cb91db3f
|
补上 README 和启动脚本
之前跑起来要记一串命令和路径,现在 bun run start 一条就够。
另外补了 dev:kernel 和 dev:reset,本地那套「写坏配置看它怎么救」的流程不用再手敲二进制路径。
|
2026-08-10 04:43:08 +08:00 |
|
im0o
|
7a764f5fe1
|
搭出前端骨架和入站列表
设计基调定为:层次靠底色和一像素描边而不是投影,一屏最多两层容器,间距给足。
tokens.css 顶部写了这三条规则,后面的组件都是它们的推论。
入站列表把两套写法合并成一张表:老式顶层端口字段(mixed-port 这些)和 listeners 数组。
只画 listeners 的话,一台只用 mixed-port 的机器打开会是空板,而那个端口正在跑——
这等于对用户撒谎。合并逻辑在 shared/inbounds.ts,带 10 个测试。
后端顺带能提供打包后的静态文件了,一个进程就能跑起来。
|
2026-08-10 04:10:17 +08:00 |
|
im0o
|
ada547adf7
|
加上 HTTP 接口层和令牌认证
接口分三类:配置读写走保护链路,内核状态和只读透传,静态字段表。
透传用白名单而不是黑名单——写操作属于运行时面板,等做到那步再单独开,
现在不留一个什么都能转发的口子。
令牌即便在只监听本机时也强制校验:同一台机器上跑着容器和别的服务,
「只监听 127.0.0.1」不等于「只有你能访问」。比较用常数时间,避免靠响应耗时猜。
scripts/api-smoke.ts 对着真服务和真内核跑 17 项检查,端到端确认过
改配置之后内核会重载、新端口真的被监听起来。
|
2026-08-10 03:37:49 +08:00 |
|
im0o
|
71b35d5a24
|
从内核源码提取入站类型的字段表
20 种类型、6 个公共字段、398 个专有字段,用来驱动界面表单。
类型清单取自 listener/parse.go 的 ParseListener switch 而不是文件名:
listener/inbound/ 下 24 个非测试文件里有 11 个只是被内嵌的选项组(TLS 伪装、多路复用这类),
不能单独当 type 写;hysteria2-realm 的类型名带中划线而文件名带下划线,靠文件名猜会错。
|
2026-08-10 03:14:56 +08:00 |
|
im0o
|
ac91b96ef8
|
写出配置落盘的保护链路
顺序是:检查基准是否过时 → 自己校验 → 临时文件上跑 mihomo -t → 备份 → 写入 → 重载,
最后两步任一失败就从备份还原并让内核载回原样。
自己校验那一步不能省:实测 v1.19.29,入站的 proxy 指向不存在的出站时 mihomo -t 会通过、
重载会成功,直到有流量走到那个入站才在日志里报错。这类错误只有 Patchbay 查得出来。
路径在读环境变量时就转成绝对路径,因为内核的 PUT /configs 拒绝相对路径。
|
2026-08-10 02:56:04 +08:00 |
|
im0o
|
26bb0f3456
|
把分隔符里的字面 NUL 字节改成转义写法
源码里直接写 NUL 字节会让 git 把整个文件判定成二进制,此后再也看不到这个文件的 diff。
用 \u0000 转义,运行时的值不变。
|
2026-08-10 02:44:50 +08:00 |
|
im0o
|
f7db96fb0e
|
搭起项目骨架,验证配置文件往返
核心是确认「改配置而不弄乱文件」这件事成立:新增一路入站之后,其余 52 行逐字节不变。
搬进来的改写引擎用默认输出参数时会重排整个文件——行尾注释的对齐空格消失、流式数组被加上内边距——
连根本没改动的段落也一起波及。不修的话「改一处只动一处」这个承诺直接落空,所以关掉了它的自动排版,
并在写回之后补了一步逐行还原。
|
2026-08-10 02:43:04 +08:00 |
|