0.8.23 — 远程路径补全逐字符卡顿修复(issue #41 / PR #42)+ 机器身份硬化
0.8.23
性能修复:远程路径自动补全逐字符卡顿(issue #41,PR #42 by @GDWhisper)+ 机器身份硬化
issue #41 —— 在工作目录选择器里输入远程路径,每敲一个字符都重连一次 SSH
- 现象:远程 tab 的路径输入框里补全每敲一个字符卡 0.5–2 秒,打字快了请求还会排队、
越打越慢;与目录条目多少关系不大,链路稍有延迟就非常明显。 - 根因:输入时每敲一个字符都会
POST /dsh-remote/current,而该路由会经
applyActiveMachine → pool.setTarget无条件关闭 SSH 连接并清空平台检测缓存
(setTarget里this.close()是唯一的收尾分支)。于是每次按键的真实成本是
「重连 + 重新探测平台 + 重列同一目录」,而不是单纯查目录。 - 修复(PR #42,@GDWhisper):三层,缺一不可。
SshPool.setTarget目标未变即空操作:不再关闭活连接、不再清平台缓存。
调用方若因共享 config 已被就地改写而无法与自身比较,可传入改动前的快照
作为 diff 基线(previous参数)—— 这是"切换机器必须断开旧连接"(issue #25
的错主机隐患)得以保留的关键。setCurrent幂等:同一台机器且已生效时,不重写注册表、不重读凭据、不重设池。
指纹在applyActiveMachine内部维护,因此开机恢复、rw_connect save:true、
POST /current三条路径都不会漂移。- 选择器客户端缓存:
POST /current只在切换机器时发(ensureCurrent,
并发调用共享同一个 in-flight promise,失败则 reject 而不是污染缓存);
目录列表按(机器, 目录)做 30s TTL 缓存 + 同键并发合并(fetchDirList);
过期的补全响应按序号丢弃,不会覆盖新输入;重新打开选择器整体重置。
- 实测(真机 9.134.186.191:36000,真实 SSH/SFTP + 从
lib/client.js提取的真实
选择器逻辑,非 mock):预热后单字符补全 1099ms → 31ms(35 倍),
每字符主机请求 2 → 0;重打同一路径 1146ms → 31ms、0 次请求。首次按键
(必然冷拨号)仍约 1.1s,之后同一目录内连续输入基本秒出。 - 顺手修掉的两个正确性缺陷(同一 PR 自审):切换机器时
applyMachine会就地
改写共享 config(pool.config就是这个 config),于是与自身比较恒等、空操作恒成立、
机器切换后仍复用旧 SSH 客户端(错主机);映射改为显式传改动前快照。另外
invalidate()现在与close()一样触发onCloseHook,避免转发管理器挂在已死客户端
上的close → stopAll()监听器把重新挂到新客户端的转发拆掉。 - 机器身份硬化(0.8.23 补丁,合并后追加):PR #42 删掉了每次按键的
POST /current,而那正是「让 active pool 钉在选择器机器上」的机制;配合新的客户端
缓存,缓存命中的重打字是零主机请求,于是 commit 前没有任何东西重新应用选择器
机器,而/mirror不携带机器身份 ⇒ 会用当时 active 的机器建镜像。/ls的
identity 回显挡不住这一点:缓存按 machine id 键控,命中时不校验任何东西。
真机复现:选择器显示 A 的目录树,外部「设为当前」切到 B 后提交,镜像 identity
变成 B。pre-0.8.23 因 commit 前总会重发/current而偶然掩盖。修法:/mirror与
/home接受可选machineId命名调用方所展示的机器,host 在目录探测之前
重新断言该机器;未知 id 返回 404 拒绝(静默回退到 active 本身就是危险);
缺省 id 保持原语义,老客户端与设置页的 workspace 流程完全不受影响。
新增test/mirror-machine-identity.test.js(4 种路由层顺序 + 客户端调用形状)。