7.9 KiB
Code Review: reg 与自动重连逻辑
审查范围:App.tsx 自动重连、auth.ts syncConfigToServer、processHandlers.ts Lanproxy 启动
结论:逻辑正确,注释与行为一致;有少量可改进点。
1. 已做对的部分
1.1 先 reg 成功再启动服务
- savedKey 路径:
syncConfigToServer()被await,只有result为真时才调用startServicesSequentially(),不会在 reg 失败时启动服务。 - 配置来源:
syncConfigToServer内用本次 reg 的response.serverHost/response.serverPort调用saveServerConfig(),lanproxy 启动时从 settings 读到的已是本次 reg 写入的最新值。
1.2 reg 返回可能变化的处理
syncConfigToServer在 reg 成功后将本次返回的serverHost/serverPort写回配置,并返回 response;调用方在 reg 成功后再启动,符合「用本次最新结果」的语义。- 注释在 App.tsx 与 auth.ts 中已说明「reg 返回可能会变化,先写配置再启动」。
1.3 失败与提示
- reg 失败(
result为 null)时只打日志 + notification,不启动服务,行为与注释一致。 - 异常被 try/catch 捕获,避免未处理 Promise rejection。
1.4 代码质量
- 当前修改未引入新的 lint 报错。
- 类型与现有风格一致(仅个别
as any为既有写法)。
2. 可改进点(非必须)
2.1 「向导刚完成」路径未再调 reg
- 现状:
setupJustCompleted.current === true时直接startServicesSequentially(...),不调用syncConfigToServer。 - 原因:向导完成时通常刚执行过登录,
loginAndRegister已调过 reg 并执行saveServerConfig,配置已是最新。 - 建议:若希望与「重新打开客户端」完全统一(始终先 reg 再启动),可在该分支也先
await syncConfigToServer({ suppressToast: true }),成功后再startServicesSequentially;否则保持现状即可,在注释中注明「向导刚完成时假定登录流程已执行 reg,直接使用当前配置启动」。
2.2 自动重连中的 catch 未对用户提示
- 现状:
autoReconnect的catch仅console.error('[App] 自动重连失败:', error),用户无 toast。 - 建议:若希望网络异常等未预期错误也有提示,可在 catch 里补一次
notification.warning(与result为 null 时的文案区分开,例如「自动重连异常,请稍后重试或手动启动服务」),避免重复可复用现有「自动重连失败」的 key 或 message。
2.3 类型收紧(低优先级)
startServicesSequentially内agentConfig、lpConfig使用as any,后续可改为具体类型(如从 shared 或 api 类型中抽取),便于后续扩展 reg 返回字段时的类型安全。
3. 与 processHandlers 的衔接
- Lanproxy 启动仍从主进程
readSetting('lanproxy_config')/lanproxy.server_host/lanproxy.server_port读配置;这些值由渲染进程侧saveServerConfig经 IPC 写入,顺序为「reg 成功 → syncConfigToServer 写配置 → 再启动服务」,因此主进程读到的已是本次 reg 写入的最新配置,无需改 processHandlers。
4. 已修复:账号切换后 lanproxy 使用旧 clientKey(2026-03-12)
问题
场景一:不退出直接切换账号
handleLogin 在 handleStartService('lanproxy') 时传入新账号的 clientKey,但主进程 startLanproxyProcess 检测到 ctx.lanproxy.running === true(旧进程仍在),直接返回 success: true 而不重启 → 旧 key 继续使用 → 服务端认为是旧账号 → 新账号会话显示「客户端离线」。
场景二:退出登录后用新账号登录
handleLogout 会停止所有服务(agent/fileServer/lanproxy/mcpProxy/computerServer)并清除 auth 信息。用户用新账号登录时 handleLogin 执行 loginAndRegister → 写入新 configKey/savedKey → 启动服务。由于 logout 已停掉所有服务,lanproxy 的 ctx.lanproxy.running === false,新进程用新 clientKey 正常启动。此场景在修复前已能正常工作。
修复
在 processHandlers.ts 的 startLanproxyProcess 中,将「已运行则跳过」改为「已运行则异步停止(等待进程退出)再用本次传入的 config 重启」:
if (ctx.lanproxy.running) {
// 切换账号后 clientKey 会变化,必须用新配置重启,不能跳过。
// 否则旧进程继续使用旧 clientKey 导致「本地显示已联通、会话显示离线」。
log.info('[Lanproxy] 已在运行,先停止再用新配置重启');
await ctx.lanproxy.stopAsync();
}
stopAsync() 发送 SIGTERM 并等待进程 exit 事件(5s 超时后 SIGKILL),确保端口/资源释放后再启动新进程。
修改点:
src/main/processManager.ts:新增stopAsync()方法(含 stdio 监听器清理,防止 Windows 句柄泄漏)src/main/ipc/processHandlers.ts:startLanproxyProcess内的 running 守卫改用await stopAsync()
| 场景 | 修复前 | 修复后 |
|---|---|---|
| 不退出直接切换 | ❌ lanproxy 用旧 key,新账号离线 | ✅ 先停旧进程再用新 config 启动 |
| 退出后用新账号登录 | ✅ logout 已停服务,正常启动 | ✅ 未运行,直接启动 |
| 任何路径调用 lanproxy:start | ❌ 已运行时跳过 | ✅ 始终应用本次传入的配置 |
5. 总结
| 项目 | 状态 |
|---|---|
| reg 成功后才启动服务 | 正确 |
| 使用本次 reg 返回的配置 | 正确(通过 saveServerConfig 写再读) |
| 注释与行为一致 | 是 |
| 失败分支与提示 | 正确,catch 可考虑补用户提示 |
| 向导完成路径 | 合理,若需统一可先 reg 再启动 |
| 账号切换时先停旧服务 | 已修复(2026-03-12) |
| 手动启动单个服务时先 reg | 已补充(2026-03-12) |
结论:当前实现满足「等待 reg 成功返回后才启动服务」且「使用 reg 可能变化后的最新配置」;账号切换场景已通过先停后启修复;手动启动单个服务场景已补充先 reg 再启动。
6. 手动启动单个服务时补充 reg 调用(2026-03-12)
问题
场景:用户在 ClientPage 点击某个服务的「启动」按钮(非「启动全部」、非登录流程)。
此前 handleStartService(svc.key) 直接启动目标服务,不调用 reg。这意味着:
- 如果后端
serverHost/serverPort发生过变化(如服务端重新分配端口),lanproxy 启动时读到的是旧值。 - 与「登录」和「启动全部」行为不一致——它们都在启动服务前/后调用
syncConfigToServer()。
修复
新增 handleStartServiceManual 包装函数,UI 按钮 onClick 改为调用此函数:
const handleStartServiceManual = async (key: string) => {
// 先 reg,确保 lanproxy 等服务启动时使用最新的后端返回数据
try {
await syncConfigToServer({ suppressToast: true });
} catch (e) {
console.error('[ClientPage] 手动启动服务前 reg 同步失败:', e);
}
await handleStartService(key);
onAuthChange?.();
};
时序对比
| 场景 | reg 时机 | 启动时机 |
|---|---|---|
登录流程 (handleLogin) |
loginAndRegister() + 启动非代理服务后 syncConfigToServer() |
reg 后启动 lanproxy |
启动全部 (handleStartAll) |
启动非代理服务后 syncConfigToServer() |
reg 后启动 lanproxy |
手动启动单个 (handleStartServiceManual) |
先 syncConfigToServer() |
reg 后启动目标服务 |
三个场景均保证 reg 在服务启动之前完成,lanproxy 读到的 serverIp/serverPort 为 reg 返回的最新值。
修改点
src/renderer/components/pages/ClientPage.tsx:新增handleStartServiceManual,单个服务「启动」按钮 onClick 改用此函数