From bf8124bb35892a2b0ba26a0892534e1e7fd5402a Mon Sep 17 00:00:00 2001 From: Baobhan Sith <80159437+Heavrnl@users.noreply.github.com> Date: Sat, 10 May 2025 09:06:57 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=8C=82=E8=B5=B7=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E4=B8=8B=E7=A6=81=E6=AD=A2=E8=87=AA=E5=8A=A8=E9=87=8D=E8=BF=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/composables/useWebSocketConnection.ts | 11 ++++- .../stores/session/actions/sessionActions.ts | 44 +++++++++++++------ 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/packages/frontend/src/composables/useWebSocketConnection.ts b/packages/frontend/src/composables/useWebSocketConnection.ts index 2286c52..8f61104 100644 --- a/packages/frontend/src/composables/useWebSocketConnection.ts +++ b/packages/frontend/src/composables/useWebSocketConnection.ts @@ -21,7 +21,7 @@ export function createWebSocketConnectionManager( sessionId: string, dbConnectionId: string, t: ReturnType['t'], - options?: { isResumeFlow?: boolean } + options?: { isResumeFlow?: boolean; getIsMarkedForSuspend?: () => boolean } // +++ 添加 getIsMarkedForSuspend 回调 +++ ) { // --- Instance State --- // 每个实例拥有独立的 WebSocket 对象、状态和消息处理器 @@ -33,6 +33,7 @@ export function createWebSocketConnectionManager( const messageHandlers = new Map>(); // 此实例的消息处理器注册表 const instanceSessionId = sessionId; // 保存会话 ID 用于日志 const instanceDbConnectionId = dbConnectionId; // 保存数据库连接 ID + const getIsMarkedForSuspend = options?.getIsMarkedForSuspend; // +++ 获取回调函数 +++ let reconnectAttempts = 0; // 重连尝试次数 const maxReconnectAttempts = 5; // 最大重连次数 let reconnectTimeoutId: ReturnType | null = null; // 重连定时器 ID @@ -80,6 +81,14 @@ export function createWebSocketConnectionManager( const scheduleReconnect = () => { if (intentionalDisconnect) return; // 如果是主动断开,则不重连 + // +++ 检查是否标记为待挂起 +++ + if (getIsMarkedForSuspend && getIsMarkedForSuspend()) { + console.log(`[WebSocket ${instanceSessionId}] 会话已标记为待挂起,不执行自动重连。`); + statusMessage.value = getStatusText('markedForSuspendNoReconnect'); // 可以为此添加新的i18n文本 + connectionStatus.value = 'disconnected'; // 保持断开状态或设为特定状态 + return; + } + if (reconnectAttempts >= maxReconnectAttempts) { console.log(`[WebSocket ${instanceSessionId}] 已达到最大重连次数 (${maxReconnectAttempts}),停止重连。`); statusMessage.value = getStatusText('reconnectFailed'); diff --git a/packages/frontend/src/stores/session/actions/sessionActions.ts b/packages/frontend/src/stores/session/actions/sessionActions.ts index 744d22c..0c419fd 100644 --- a/packages/frontend/src/stores/session/actions/sessionActions.ts +++ b/packages/frontend/src/stores/session/actions/sessionActions.ts @@ -44,12 +44,36 @@ export const openNewSession = ( // 1. 创建管理器实例 const isResume = !!existingSessionId; // 如果提供了 existingSessionId,则为恢复流程 + + // 稍后创建 wsManager,先创建 SessionState 对象的一部分 + const newSessionPartial: Omit & { wsManager?: WsManagerInstance } = { + sessionId: newSessionId, + connectionId: dbConnId, + connectionName: connInfo.name || connInfo.host, + editorTabs: ref([]), + activeEditorTabId: ref(null), + commandInputContent: ref(''), + isMarkedForSuspend: false, + disposables: [], + }; + const wsManager = createWebSocketConnectionManager( - newSessionId, + newSessionId, // 这个 sessionId 在 wsManager 内部使用,可能与 SessionState.sessionId 不同步(如果后者被后端更新) dbConnId, t, - { isResumeFlow: isResume } // 传递 isResumeFlow 选项 + { + isResumeFlow: isResume, + getIsMarkedForSuspend: () => { + // 直接从 newSessionPartial (它将成为完整的 SessionState 对象) 读取状态 + // 注意:如果 SessionState.sessionId 被后端更新,而 wsManager 内部的 sessionId (instanceSessionId) + // 没有相应更新并在 scheduleReconnect 中使用 instanceSessionId 来识别日志,可能会有轻微不一致。 + // 但对于 isMarkedForSuspend 的判断是准确的。 + return !!newSessionPartial.isMarkedForSuspend; + } + } ); + newSessionPartial.wsManager = wsManager; // 将 wsManager 添加回部分对象 + const sshTerminalDeps: SshTerminalDependencies = { sendMessage: wsManager.sendMessage, onMessage: wsManager.onMessage, @@ -68,22 +92,16 @@ export const openNewSession = ( }; const dockerManager = createDockerManager(newSessionId, dockerManagerDeps, { t }); - // 2. 创建 SessionState 对象 + // 2. 完成 SessionState 对象 const newSession: SessionState = { - sessionId: newSessionId, - connectionId: dbConnId, - connectionName: connInfo.name || connInfo.host, - wsManager: wsManager, - sftpManagers: new Map(), // 初始化 Map + ...newSessionPartial, // 包含 sessionId, connectionId, connectionName, wsManager, editorTabs, etc. + wsManager: wsManager, // 确保 wsManager 被正确赋值 + sftpManagers: new Map(), terminalManager: terminalManager, statusMonitorManager: statusMonitorManager, dockerManager: dockerManager, - editorTabs: ref([]), - activeEditorTabId: ref(null), - commandInputContent: ref(''), - isMarkedForSuspend: false, // +++ 初始化 isMarkedForSuspend状态 +++ - disposables: [], // 初始化 disposables 数组 }; + // newSession.isMarkedForSuspend 已经在 newSessionPartial 中初始化为 false // 3. 添加到 Map 并激活 const newSessionsMap = new Map(sessions.value);