远程连接与多会话工作区
远程连接与多会话工作区
相关源文件
以下文件为本维基页面的生成提供了上下文:
assets/demos/edited_timeline.jsonassets/demos/jcode_mermaid_demo.mp4src/replay.rssrc/tui/app/commands.rssrc/tui/app/input.rssrc/tui/app/local.rssrc/tui/app/remote.rssrc/tui/app/remote/key_handling.rssrc/tui/app/remote/server_events.rssrc/tui/app/replay.rssrc/tui/app/run_shell.rssrc/tui/app/state_ui.rssrc/tui/app/state_ui_runtime.rssrc/tui/app/tests.rssrc/tui/app/tui_lifecycle.rssrc/tui/app/tui_state.rssrc/tui/app/turn.rssrc/tui/info_widget_overview.rssrc/tui/info_widget_swarm_background.rssrc/tui/info_widget_tests.rssrc/tui/ui_overlays.rssrc/video_export.rs
本文档详细介绍了远程服务器连接的生命周期、服务器重载时保持客户端状态不丢失的机制,以及 TUI 特有的工作区导航功能。
RemoteConnection 生命周期
RemoteConnection 表示 TUI 客户端与 jcode 服务器之间的持久连接。如果应用程序通过 run_remote 以远程模式启动,该连接会在 TUI 启动阶段初始化 src/tui/app/run_shell.rs:179。
连接与重试策略
客户端在初始连接和重新连接时采用指数退避策略。该策略主要通过 connect_with_retry 和 RemoteRunState 进行管理 src/tui/app/remote/reconnect.rs:32。
- 阶段转换:
RemoteRunState跟踪从Connecting到FinalizingReload再到Running的完整生命周期src/tui/app/remote/reconnect.rs:32。 - 退避逻辑:如果连接失败,客户端会增加重试次数,并使用
AUTO_RETRY_BASE_DELAY_SECS计算延迟时间src/tui/app/tui_lifecycle.rs:151。 - 结果处理:
ConnectOutcome枚举决定了连接结果是Success、Refused,还是需要ReloadHandoffsrc/tui/app/remote/reconnect.rs:32。 - 网络感知:如果客户端检测到处于离线状态,会进入
ProcessingStatus::WaitingForNetwork状态,并在重试前安排一次探测src/tui/app/tui_lifecycle.rs:100-103。
重载交接检测
当服务器执行热重载时(例如通过 selfdev 工具),会留下一个标记。客户端通过检测该标记来区分服务器崩溃和计划内的升级。
- 交接检测:
reload_handoff_active函数会检查磁盘上是否存在重载标记src/tui/app/remote/reconnect.rs:33。 - 标记过期:标记仅在创建时间不超过
RELOAD_MARKER_MAX_AGE(30 秒)时才被视为有效src/tui/app/remote.rs:57。 - 最终化:一旦新的服务器实例启动完成,会调用
finalize_reload_reconnect从之前的实例恢复 UI 状态src/tui/app/remote/reconnect.rs:32。
远程生命周期数据流
下图展示了 TUI 连接状态与底层协议及服务器实体之间的映射关系。
图:远程连接状态机
来源:src/tui/app/remote/reconnect.rs:31-36、src/tui/app/remote.rs:57-63、src/tui/app/remote/server_events.rs:6-41、src/tui/app/tui_lifecycle.rs:145-155。
Niri 风格的工作区导航
jcode 实现了受 Niri 平铺窗口管理器启发的水平工作区模型。每个会话都被视为水平条带上的一个独立工作区。
导航逻辑
导航功能通过专门的处理器实现,这些处理器将按键映射到会话切换操作。
- 按键映射:
handle_workspace_navigation_key拦截工作区特定的按键绑定src/tui/app/remote.rs:41。 - 会话恢复:如果用户导航到客户端当前未激活的工作区,会调用
remote.resume_session来同步服务器端的焦点src/tui/app/remote.rs:83-84。 - 待处理恢复:系统使用
take_pending_resume_session处理由外部事件(如工作区客户端或追赶请求)触发的异步工作区切换src/tui/app/remote.rs:82-108。
工作区地图组件
WorkspaceMap 以概览形式呈现服务器会话状态。
- 会话跟踪:客户端跟踪
remote_session_id以高亮显示当前活动的工作区src/tui/app/state_ui.rs:49。 - 焦点交互:
note_client_focus和note_client_interaction通过将焦点会话 ID 记录到听写系统中,确保工作区地图反映用户的当前活动src/tui/app/state_ui.rs:55-76。
图:工作区导航与 UI 映射
来源:src/tui/app/remote.rs:41-125、src/tui/app/state_ui.rs:47-80。
RemoteDiffTracker 与事件同步
工具输出和状态变更的同步通过 ServerEvent 协议进行处理。
实现细节
- 事件分发:
handle_server_event函数将传入的协议消息(增量、工具启动、使用情况等)路由到特定的处理器src/tui/app/remote/server_events.rs:6-10。 - 工具状态:
ServerEvent::ToolDone更新客户端对文件变更和工具输出的视图src/tui/app/remote/server_events.rs:119-124。 - 交错处理:
send_interleave_now函数允许用户通过soft_interrupt在活跃的远程轮次中注入消息src/tui/app/remote/key_handling.rs:11-32。 - Token 累积:
ServerEvent::TokenUsage更新输入、输出和缓存性能的流式计数器src/tui/app/remote/server_events.rs:143-159。
重载后的状态恢复
当发生重载时,客户端必须通过 RestoredReloadInput 恢复其本地的"未发送"状态。
- 持久化:
save_input_for_reload将当前输入缓冲区、光标位置、待处理图片和排队消息序列化到~/.jcode/client-input-{session_id}src/tui/app/state_ui.rs:92-171。 - RestoredReloadInput:该结构体在交接期间保存输入缓冲区、光标位置和待处理图片
src/tui/app/state_ui.rs:6-25。 - 应用:
apply_restored_reload_input将保存的状态合并回活跃的App实例src/tui/app/tui_lifecycle.rs:6-30。 - 中断恢复:
recover_stranded_soft_interrupts确保未被旧服务器实例确认的待处理软中断作为常规后续操作重新排队src/tui/app/tui_lifecycle.rs:37-46。
| 组件 | 职责 | 文件引用 |
|---|---|---|
RemoteConnection | 底层协议传输和会话管理 | src/tui/backend.rs |
handle_server_event | ServerEvent 变体的主要分发器 | src/tui/app/remote/server_events.rs |
RestoredReloadInput | 服务器重载期间 UI 状态的容器 | src/tui/app/state_ui.rs |
soft_interrupt | 轮次中消息注入的协议方法 | src/tui/app/remote/key_handling.rs |
run_turn_interactive | 等待 API 时处理输入的本地循环 | src/tui/app/turn.rs:26 |
来源:src/tui/app/remote/server_events.rs:6-159、src/tui/app/tui_lifecycle.rs:6-67、src/tui/app/remote/key_handling.rs:11-32、src/tui/app/state_ui.rs:92-171。