github AnalyseDeCircuit/oxideterm v1.4.0
OxideTerm v1.4.0

latest releases: v2.2.0, v2.1.0, v2.0.31...
5 months ago

🐛 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} 
/>

适用组件:

  • SFTPView
  • ForwardsView
  • IdeWorkspace

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 错误

测试验证

  1. 连接 SSH → 打开 SFTP 标签页 → 进入目录
  2. 模拟断网或服务器超时
  3. 等待/触发重连
  4. 验证:
    • [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.app

Windows

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

Documentation · Report Issues · Changelog

Don't miss a new oxideterm release

NewReleases is sending notifications on new releases.