OxideTerm 节点会话所有权
每当变更可能影响创建、共享、关闭、重连或观察远程会话或后台任务的组件时,请使用此技能。
核心不变量
已连接的 SSH 节点独立于任何使用它的终端面板。UI 生命周期不得暗中成为后端生命周期。
flowchart TD
W["工作空间或应用程序生命周期"] --> R["NodeRouter 与连接注册表"]
R --> N["物理 SSH 节点连接"]
N --> T["终端消费者"]
N --> S["SFTP 消费者"]
N --> F["转发消费者"]
R --> H["健康检查与重连任务"]
强制性规则
- 节点存活状态属于连接注册表、
NodeRouter或显式的节点断开操作。 - 关闭终端面板会移除该终端消费者。它不得断开共享节点。
- SFTP 必须获取一个真正的节点支持的 SFTP 会话。模拟文件传输的 shell 命令仅作为文档中说明的兼容性回退。
- 端口转发拥有自己的监听器和桥接任务。这些任务必须保持存活,无需开放的终端面板,且必须在转发规则或所属节点停止时停止。
- 重连、健康检查、宽限期和子进程桥接需要一个显式的所有者以及绑定到节点、工作空间或应用程序生命周期的取消路径。
- 长时间运行的工作不得在一次性运行时上运行,该运行时会随着命令处理程序的返回而被丢弃。
- 通过跳板主机连接的子节点必须在其子传输需要期间保持与父节点的连接。
- UI 组件通过路由器或注册表事件观察运行时状态。它们不得根据终端的存在推断节点存活。
- 在所有权转移处添加简洁的英文注释:创建、共享、失效、重新获取、取消以及 UI 拆除后的有意存活。
禁止的绕过方式
- 不得因为节点支持的 API 不便而打开第二个未管理的 SSH 传输。
- 不得通过选择与主机关联的第一个终端面板来查找连接。
- 不得仅将长期任务存储在临时对话框、命令处理程序或终端视图中。
- 不得仅仅因为一个通道、面板、SFTP 请求或转发消费者关闭而将节点标记为已断开。
- 不得让生成的子进程或 Tokio 任务在没有关闭信号和有边界的完成路径的情况下脱离。
推荐实践
- 将每个后端依赖项表示为注册表中的消费者或所有者,而不是依赖偶然的
Arc保留。 - 在连接条目上保留物理传输状态,在
NodeRouter中保留逻辑拓扑。 - 使断开级联遵循记录的父子连接标识,而不是匹配主机字符串。
- 将任务句柄或取消发送器保留在生命周期定义作业的对象上。
- 优先选择事件驱动的 UI 更新,而不是轮询终端状态。
兼容性路径
仅当兼容性回退是显式的、有边界的且准确报告时才允许。它们不得描述为原生的 SFTP、转发或节点会话实现。即使对于临时回退,也要记录所有者与清理路径。
示例
错误:
// 关闭面板意外地销毁了共享节点的唯一所有者。
struct TerminalPane {
ssh_transport: SshTransport,
}
正确形式:
// 面板仅拥有其消费者注册;注册表拥有传输存活状态。
struct TerminalPane {
connection_id: String,
terminal_consumer: ConnectionConsumer,
}
错误:
tokio::runtime::Runtime::new()?.spawn(run_forward_listener());
// 运行时在命令返回时被丢弃。
正确形式:
// 转发所有者保留取消和完成句柄。
struct ForwardingJob {
shutdown_tx: Option<oneshot::Sender<()>>,
worker: JoinHandle<()>,
}
审查清单
- 确定物理连接所有者。
- 列出每个终端、SFTP、转发、重连、健康检查和子节点消费者。
- 验证关闭一个消费者不会关闭不相关的消费者。
- 验证显式节点断开操作会停止依赖的任务和子传输。
- 检查每个生成的任务或进程是否具有保留的所有者、取消信号和清理路径。
- 检查 UI 状态是否消费节点事件,而不是终端派生的存活状态。
- 精确说明任何剩余的兼容性回退。
验证
- 关闭最后一个终端,并证明该节点仍然可以被其他已注册的消费者使用。
- 在不要求终端面板的情况下打开 SFTP。
- 启动本地、远程和动态转发,并验证监听器在面板关闭后仍然存活。
- 断开父节点,并验证依赖的子节点和作业一致地转换。
- 在宽限期内重连,而不丢失不相关的 UI 状态。
- 确认任务/进程清理在显式断开和应用程序关闭后完成。