🐛 Bug 修复
Store 间同步缺失导致 connectionState=undefined 死锁
问题现象:
- SSH 重连成功后,SFTPView 和 TransferQueue 卡在 "Waiting for connection"
- 控制台显示
connectionState=undefined, isConnectionReady=false - StateDrift 日志显示
Auto-fixed 1 drift(s)但 UI 无反应
根本原因:
sessionTreeStore.connectNodeInternal() 和 syncDrift() 只更新 rawNodes,
不同步 appStore.connections,而 SFTPView/TransferQueue 依赖后者判断连接状态。
旧数据流(断裂):
[Backend] SSH Connected
→ [sessionTreeStore] rawNodes 更新 ✅
→ [appStore] connections Map 未更新 ❌
→ [SFTPView] connectionState = undefined → 卡死 💀
解决方案:
在以下位置添加 await useAppStore.getState().refreshConnections():
| 文件 | 位置 | 触发时机 |
|---|---|---|
sessionTreeStore.ts
| connectNodeInternal()
| SSH 连接建立成功后 |
sessionTreeStore.ts
| syncDrift()
| StateDrift 自动修复后 |
新数据流(完整):
[Backend] SSH Connected
→ [sessionTreeStore] rawNodes 更新
→ [refreshConnections()] appStore.connections 同步
→ [SFTPView] connectionState = 'active' → 正常初始化 ✅
影响范围:
- SFTPView
- TransferQueue
- ForwardsView
- IdeWorkspace
✨ 新特性
Key-Driven Reset 模式
为解决重连后组件持有过期状态的问题,在 AppLayout.tsx 中实现复合 Key:
// 当 connectionId 变化时,React 自动销毁旧组件、创建新实例
<SFTPView
key={`sftp-${tab.sessionId}-${getSession(tab.sessionId)?.connectionId ?? ''}`}
sessionId={tab.sessionId}
/>适用组件:
SFTPViewForwardsViewIdeWorkspace
SFTP 路径记忆
跨重连保持用户目录位置:
// 全局 Map(模块顶层)
const sftpPathMemory = new Map<string, string>();
// 组件挂载时恢复
const savedPath = sftpPathMemory.get(sessionId);
// 路径变化时保存
sftpPathMemory.set(sessionId, remotePath);TransferQueue 状态门禁
连接未就绪时静默等待,避免 CONNECTION_NOT_FOUND 错误:
const isConnectionReady = connectionState === 'active' || connectionState === 'idle';
if (!isConnectionReady) {
console.debug('[TransferQueue] Waiting for connection');
return; // 不执行任何 API 调用
}📚 文档更新
docs/reference/SFTP.md: 新增「连接鲁棒性架构」章节docs/reference/ARCHITECTURE.md: 更新 SessionTreeStore 章节,补充双 Store 同步说明docs/reference/SYSTEM_INVARIANTS.md: 新增「前端 Store 间同步约束」章节
🔧 后端修复
AcceptTimeout 事件通知
WebSocket 接受超时时,后端现在正确发送 connection-status-changed 事件:
// src-tauri/src/commands/ssh.rs
TerminationReason::AcceptTimeout(secs) => {
// 通知前端连接已断开
emit_connection_status_changed(app.clone(), &session_id, "disconnected").await;
}连接池统计修复
SFTP 和端口转发现在正确更新 ConnectionRegistry:
// sftp.rs - sftp_init/sftp_close
connection_registry.set_sftp_session(&connection_id, Some(session_id)).await;
// forwarding.rs - create/stop/delete_port_forward
connection_registry.add_forward(&connection_id, &forward_id).await;
connection_registry.remove_forward(&connection_id, &forward_id).await;相关 Issue
- 修复 #TBD: SSH 重连后 SFTP 标签页卡死
- 修复 #TBD: TransferQueue CONNECTION_NOT_FOUND 错误
测试验证
- 连接 SSH → 打开 SFTP 标签页 → 进入目录
- 模拟断网或服务器超时
- 等待/触发重连
- 验证:
[SFTPView] Init:日志紧随[StateDrift] Auto-fixed出现- SFTP 恢复到之前的目录
- TransferQueue 无 CONNECTION_NOT_FOUND 错误
📦 Installation Tips / 安装提示
macOS
Downloaded .dmg files are quarantined by Gatekeeper. Run in Terminal:
下载的 .dmg 文件会被 Gatekeeper 隔离,请在终端执行:
xattr -cr ~/Downloads/OxideTerm_*.dmg
# or after install / 或安装后
xattr -cr /Applications/OxideTerm.appWindows
If SmartScreen warns, click More info → Run anyway.
若 SmartScreen 弹出警告,点击 更多信息 → 仍要运行。
Linux
# AppImage
chmod +x OxideTerm_*_linux_*.AppImage && ./OxideTerm_*_linux_*.AppImage
# Debian/Ubuntu
sudo dpkg -i OxideTerm_*_linux_*.deb && sudo apt-get install -f