mirror of
https://github.com/Minidoracat/mcp-feedback-enhanced.git
synced 2025-07-27 02:22:26 +08:00
🐛 修復 WebSocket 狀態檢測導入錯誤 (#78)
This commit is contained in:
parent
de6838c79c
commit
5f9eb6a42e
@ -68,8 +68,8 @@ class DesktopApp:
|
|||||||
self.web_manager.start_server()
|
self.web_manager.start_server()
|
||||||
|
|
||||||
# 等待服務器啟動
|
# 等待服務器啟動
|
||||||
max_wait = 10 # 最多等待 10 秒
|
max_wait = 10.0 # 最多等待 10 秒
|
||||||
wait_count = 0
|
wait_count = 0.0
|
||||||
while wait_count < max_wait:
|
while wait_count < max_wait:
|
||||||
if (
|
if (
|
||||||
self.web_manager.server_thread
|
self.web_manager.server_thread
|
||||||
@ -221,7 +221,8 @@ class DesktopApp:
|
|||||||
# Windows 下隱藏控制台視窗
|
# Windows 下隱藏控制台視窗
|
||||||
creation_flags = 0
|
creation_flags = 0
|
||||||
if os.name == "nt":
|
if os.name == "nt":
|
||||||
creation_flags = subprocess.CREATE_NO_WINDOW
|
# CREATE_NO_WINDOW 只在 Windows 上存在
|
||||||
|
creation_flags = getattr(subprocess, "CREATE_NO_WINDOW", 0x08000000)
|
||||||
|
|
||||||
self.app_handle = subprocess.Popen(
|
self.app_handle = subprocess.Popen(
|
||||||
[str(tauri_exe)],
|
[str(tauri_exe)],
|
||||||
|
@ -331,7 +331,9 @@ class WebUIManager:
|
|||||||
|
|
||||||
# 如果有舊會話,處理狀態轉換和清理
|
# 如果有舊會話,處理狀態轉換和清理
|
||||||
if old_session:
|
if old_session:
|
||||||
debug_log(f"處理舊會話 {old_session.session_id} 的狀態轉換,當前狀態: {old_session.status.value}")
|
debug_log(
|
||||||
|
f"處理舊會話 {old_session.session_id} 的狀態轉換,當前狀態: {old_session.status.value}"
|
||||||
|
)
|
||||||
|
|
||||||
# 保存標籤頁狀態到全局
|
# 保存標籤頁狀態到全局
|
||||||
if hasattr(old_session, "active_tabs"):
|
if hasattr(old_session, "active_tabs"):
|
||||||
@ -339,14 +341,18 @@ class WebUIManager:
|
|||||||
|
|
||||||
# 如果舊會話是已提交狀態,進入下一步(已完成)
|
# 如果舊會話是已提交狀態,進入下一步(已完成)
|
||||||
if old_session.status == SessionStatus.FEEDBACK_SUBMITTED:
|
if old_session.status == SessionStatus.FEEDBACK_SUBMITTED:
|
||||||
debug_log(f"舊會話 {old_session.session_id} 進入下一步:已提交 → 已完成")
|
debug_log(
|
||||||
|
f"舊會話 {old_session.session_id} 進入下一步:已提交 → 已完成"
|
||||||
|
)
|
||||||
success = old_session.next_step("反饋已處理,會話完成")
|
success = old_session.next_step("反饋已處理,會話完成")
|
||||||
if success:
|
if success:
|
||||||
debug_log(f"✅ 舊會話 {old_session.session_id} 成功進入已完成狀態")
|
debug_log(f"✅ 舊會話 {old_session.session_id} 成功進入已完成狀態")
|
||||||
else:
|
else:
|
||||||
debug_log(f"❌ 舊會話 {old_session.session_id} 無法進入下一步")
|
debug_log(f"❌ 舊會話 {old_session.session_id} 無法進入下一步")
|
||||||
else:
|
else:
|
||||||
debug_log(f"舊會話 {old_session.session_id} 狀態為 {old_session.status.value},無需轉換")
|
debug_log(
|
||||||
|
f"舊會話 {old_session.session_id} 狀態為 {old_session.status.value},無需轉換"
|
||||||
|
)
|
||||||
|
|
||||||
# 確保舊會話仍在字典中(用於API獲取)
|
# 確保舊會話仍在字典中(用於API獲取)
|
||||||
if old_session.session_id in self.sessions:
|
if old_session.session_id in self.sessions:
|
||||||
@ -689,10 +695,6 @@ class WebUIManager:
|
|||||||
else:
|
else:
|
||||||
debug_log("沒有活躍的桌面應用程式實例")
|
debug_log("沒有活躍的桌面應用程式實例")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async def _safe_close_websocket(self, websocket):
|
async def _safe_close_websocket(self, websocket):
|
||||||
"""安全關閉 WebSocket 連接,避免事件循環衝突 - 僅在連接已轉移後調用"""
|
"""安全關閉 WebSocket 連接,避免事件循環衝突 - 僅在連接已轉移後調用"""
|
||||||
if not websocket:
|
if not websocket:
|
||||||
@ -736,8 +738,8 @@ class WebUIManager:
|
|||||||
"session_id": self.current_session.session_id,
|
"session_id": self.current_session.session_id,
|
||||||
"project_directory": self.current_session.project_directory,
|
"project_directory": self.current_session.project_directory,
|
||||||
"summary": self.current_session.summary,
|
"summary": self.current_session.summary,
|
||||||
"status": self.current_session.status.value
|
"status": self.current_session.status.value,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
# 發送刷新通知
|
# 發送刷新通知
|
||||||
@ -754,26 +756,61 @@ class WebUIManager:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
async def _check_active_tabs(self) -> bool:
|
async def _check_active_tabs(self) -> bool:
|
||||||
"""檢查是否有活躍標籤頁 - 檢查所有會話的WebSocket連接"""
|
"""檢查是否有活躍標籤頁 - 使用分層檢測機制"""
|
||||||
try:
|
try:
|
||||||
# 檢查當前會話的WebSocket連接
|
# 快速檢測層:檢查 WebSocket 物件是否存在
|
||||||
if self.current_session and self.current_session.websocket:
|
if not self.current_session or not self.current_session.websocket:
|
||||||
debug_log("檢測到當前會話的WebSocket連接")
|
debug_log("快速檢測:沒有當前會話或 WebSocket 連接")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 檢查心跳(如果有心跳記錄)
|
||||||
|
last_heartbeat = getattr(self.current_session, "last_heartbeat", None)
|
||||||
|
if last_heartbeat:
|
||||||
|
heartbeat_age = time.time() - last_heartbeat
|
||||||
|
if heartbeat_age > 10: # 超過 10 秒沒有心跳
|
||||||
|
debug_log(f"快速檢測:心跳超時 ({heartbeat_age:.1f}秒)")
|
||||||
|
# 可能連接已死,需要進一步檢測
|
||||||
|
else:
|
||||||
|
debug_log(f"快速檢測:心跳正常 ({heartbeat_age:.1f}秒前)")
|
||||||
|
return True # 心跳正常,認為連接活躍
|
||||||
|
|
||||||
|
# 準確檢測層:實際測試連接是否活著
|
||||||
|
try:
|
||||||
|
# 檢查 WebSocket 連接狀態
|
||||||
|
websocket = self.current_session.websocket
|
||||||
|
|
||||||
|
# 檢查連接是否已關閉
|
||||||
|
if hasattr(websocket, "client_state"):
|
||||||
|
try:
|
||||||
|
# 嘗試從 starlette 導入(FastAPI 基於 Starlette)
|
||||||
|
import starlette.websockets # type: ignore[import-not-found]
|
||||||
|
|
||||||
|
if hasattr(starlette.websockets, "WebSocketState"):
|
||||||
|
WebSocketState = starlette.websockets.WebSocketState
|
||||||
|
if websocket.client_state != WebSocketState.CONNECTED:
|
||||||
|
debug_log(
|
||||||
|
f"準確檢測:WebSocket 狀態不是 CONNECTED,而是 {websocket.client_state}"
|
||||||
|
)
|
||||||
|
# 清理死連接
|
||||||
|
self.current_session.websocket = None
|
||||||
|
return False
|
||||||
|
except ImportError:
|
||||||
|
# 如果導入失敗,使用替代方法
|
||||||
|
debug_log("無法導入 WebSocketState,使用替代方法檢測連接")
|
||||||
|
# 跳過狀態檢查,直接測試連接
|
||||||
|
|
||||||
|
# 如果連接看起來是活的,嘗試發送 ping(非阻塞)
|
||||||
|
# 注意:FastAPI WebSocket 沒有內建的 ping 方法,這裡使用自定義消息
|
||||||
|
await websocket.send_json({"type": "ping", "timestamp": time.time()})
|
||||||
|
debug_log("準確檢測:成功發送 ping 消息,連接是活躍的")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# 檢查其他會話的WebSocket連接
|
except Exception as e:
|
||||||
active_websockets = 0
|
debug_log(f"準確檢測:連接測試失敗 - {e}")
|
||||||
for session_id, session in self.sessions.items():
|
# 連接已死,清理它
|
||||||
if session.websocket:
|
if self.current_session:
|
||||||
active_websockets += 1
|
self.current_session.websocket = None
|
||||||
debug_log(f"檢測到會話 {session_id} 的WebSocket連接")
|
return False
|
||||||
|
|
||||||
if active_websockets > 0:
|
|
||||||
debug_log(f"檢測到 {active_websockets} 個活躍的WebSocket連接")
|
|
||||||
return True
|
|
||||||
|
|
||||||
debug_log("沒有檢測到任何活躍的WebSocket連接")
|
|
||||||
return False
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
debug_log(f"檢查活躍連接時發生錯誤:{e}")
|
debug_log(f"檢查活躍連接時發生錯誤:{e}")
|
||||||
|
@ -32,9 +32,11 @@ class SessionStatus(Enum):
|
|||||||
"""會話狀態枚舉 - 單向流轉設計"""
|
"""會話狀態枚舉 - 單向流轉設計"""
|
||||||
|
|
||||||
WAITING = "waiting" # 等待中
|
WAITING = "waiting" # 等待中
|
||||||
|
ACTIVE = "active" # 活躍狀態
|
||||||
FEEDBACK_SUBMITTED = "feedback_submitted" # 已提交反饋
|
FEEDBACK_SUBMITTED = "feedback_submitted" # 已提交反饋
|
||||||
COMPLETED = "completed" # 已完成
|
COMPLETED = "completed" # 已完成
|
||||||
ERROR = "error" # 錯誤(終態)
|
ERROR = "error" # 錯誤(終態)
|
||||||
|
TIMEOUT = "timeout" # 超時(終態)
|
||||||
EXPIRED = "expired" # 已過期(終態)
|
EXPIRED = "expired" # 已過期(終態)
|
||||||
|
|
||||||
|
|
||||||
@ -140,6 +142,7 @@ class WebFeedbackSession:
|
|||||||
# 統一使用 time.time() 以避免時間基準不一致
|
# 統一使用 time.time() 以避免時間基準不一致
|
||||||
self.created_at = time.time()
|
self.created_at = time.time()
|
||||||
self.last_activity = self.created_at
|
self.last_activity = self.created_at
|
||||||
|
self.last_heartbeat = None # 記錄最後一次心跳時間
|
||||||
|
|
||||||
# 新增:自動清理配置
|
# 新增:自動清理配置
|
||||||
self.auto_cleanup_delay = auto_cleanup_delay # 自動清理延遲時間(秒)
|
self.auto_cleanup_delay = auto_cleanup_delay # 自動清理延遲時間(秒)
|
||||||
@ -179,17 +182,21 @@ class WebFeedbackSession:
|
|||||||
|
|
||||||
# 定義狀態流轉路徑
|
# 定義狀態流轉路徑
|
||||||
next_status_map = {
|
next_status_map = {
|
||||||
SessionStatus.WAITING: SessionStatus.FEEDBACK_SUBMITTED,
|
SessionStatus.WAITING: SessionStatus.ACTIVE,
|
||||||
|
SessionStatus.ACTIVE: SessionStatus.FEEDBACK_SUBMITTED,
|
||||||
SessionStatus.FEEDBACK_SUBMITTED: SessionStatus.COMPLETED,
|
SessionStatus.FEEDBACK_SUBMITTED: SessionStatus.COMPLETED,
|
||||||
SessionStatus.COMPLETED: None, # 終態
|
SessionStatus.COMPLETED: None, # 終態
|
||||||
SessionStatus.ERROR: None, # 終態
|
SessionStatus.ERROR: None, # 終態
|
||||||
SessionStatus.EXPIRED: None # 終態
|
SessionStatus.TIMEOUT: None, # 終態
|
||||||
|
SessionStatus.EXPIRED: None, # 終態
|
||||||
}
|
}
|
||||||
|
|
||||||
next_status = next_status_map.get(self.status)
|
next_status = next_status_map.get(self.status)
|
||||||
|
|
||||||
if next_status is None:
|
if next_status is None:
|
||||||
debug_log(f"⚠️ 會話 {self.session_id} 已處於終態 {self.status.value},無法進入下一步")
|
debug_log(
|
||||||
|
f"⚠️ 會話 {self.session_id} 已處於終態 {self.status.value},無法進入下一步"
|
||||||
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# 執行狀態轉換
|
# 執行狀態轉換
|
||||||
@ -199,8 +206,9 @@ class WebFeedbackSession:
|
|||||||
else:
|
else:
|
||||||
# 默認消息
|
# 默認消息
|
||||||
default_messages = {
|
default_messages = {
|
||||||
|
SessionStatus.ACTIVE: "會話已啟動",
|
||||||
SessionStatus.FEEDBACK_SUBMITTED: "用戶已提交反饋",
|
SessionStatus.FEEDBACK_SUBMITTED: "用戶已提交反饋",
|
||||||
SessionStatus.COMPLETED: "會話已完成"
|
SessionStatus.COMPLETED: "會話已完成",
|
||||||
}
|
}
|
||||||
self.status_message = default_messages.get(next_status, "狀態已更新")
|
self.status_message = default_messages.get(next_status, "狀態已更新")
|
||||||
|
|
||||||
@ -245,7 +253,12 @@ class WebFeedbackSession:
|
|||||||
|
|
||||||
def is_terminal(self) -> bool:
|
def is_terminal(self) -> bool:
|
||||||
"""檢查是否處於終態"""
|
"""檢查是否處於終態"""
|
||||||
return self.status in [SessionStatus.COMPLETED, SessionStatus.ERROR, SessionStatus.EXPIRED]
|
return self.status in [
|
||||||
|
SessionStatus.COMPLETED,
|
||||||
|
SessionStatus.ERROR,
|
||||||
|
SessionStatus.TIMEOUT,
|
||||||
|
SessionStatus.EXPIRED,
|
||||||
|
]
|
||||||
|
|
||||||
def get_status_info(self) -> dict[str, Any]:
|
def get_status_info(self) -> dict[str, Any]:
|
||||||
"""獲取會話狀態信息"""
|
"""獲取會話狀態信息"""
|
||||||
@ -508,11 +521,13 @@ class WebFeedbackSession:
|
|||||||
"content": message_data.get("content", ""),
|
"content": message_data.get("content", ""),
|
||||||
"images": message_data.get("images", []),
|
"images": message_data.get("images", []),
|
||||||
"submission_method": message_data.get("submission_method", "manual"),
|
"submission_method": message_data.get("submission_method", "manual"),
|
||||||
"type": "feedback"
|
"type": "feedback",
|
||||||
}
|
}
|
||||||
|
|
||||||
self.user_messages.append(user_message)
|
self.user_messages.append(user_message)
|
||||||
debug_log(f"會話 {self.session_id} 添加用戶消息,總數: {len(self.user_messages)}")
|
debug_log(
|
||||||
|
f"會話 {self.session_id} 添加用戶消息,總數: {len(self.user_messages)}"
|
||||||
|
)
|
||||||
|
|
||||||
def _process_images(self, images: list[dict]) -> list[dict]:
|
def _process_images(self, images: list[dict]) -> list[dict]:
|
||||||
"""
|
"""
|
||||||
|
@ -176,7 +176,7 @@ def setup_routes(manager: "WebUIManager"):
|
|||||||
"feedback_completed": session.feedback_completed.is_set(),
|
"feedback_completed": session.feedback_completed.is_set(),
|
||||||
"has_websocket": session.websocket is not None,
|
"has_websocket": session.websocket is not None,
|
||||||
"is_current": session == manager.current_session,
|
"is_current": session == manager.current_session,
|
||||||
"user_messages": session.user_messages # 包含用戶消息記錄
|
"user_messages": session.user_messages, # 包含用戶消息記錄
|
||||||
}
|
}
|
||||||
sessions_data.append(session_info)
|
sessions_data.append(session_info)
|
||||||
|
|
||||||
@ -189,8 +189,7 @@ def setup_routes(manager: "WebUIManager"):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
debug_log(f"獲取所有會話狀態失敗: {e}")
|
debug_log(f"獲取所有會話狀態失敗: {e}")
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
status_code=500,
|
status_code=500, content={"error": f"獲取會話狀態失敗: {e!s}"}
|
||||||
content={"error": f"獲取會話狀態失敗: {e!s}"}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@manager.app.post("/api/add-user-message")
|
@manager.app.post("/api/add-user-message")
|
||||||
@ -201,22 +200,20 @@ def setup_routes(manager: "WebUIManager"):
|
|||||||
current_session = manager.get_current_session()
|
current_session = manager.get_current_session()
|
||||||
|
|
||||||
if not current_session:
|
if not current_session:
|
||||||
return JSONResponse(
|
return JSONResponse(status_code=404, content={"error": "沒有活躍會話"})
|
||||||
status_code=404,
|
|
||||||
content={"error": "沒有活躍會話"}
|
|
||||||
)
|
|
||||||
|
|
||||||
# 添加用戶消息到會話
|
# 添加用戶消息到會話
|
||||||
current_session.add_user_message(data)
|
current_session.add_user_message(data)
|
||||||
|
|
||||||
debug_log(f"用戶消息已添加到會話 {current_session.session_id}")
|
debug_log(f"用戶消息已添加到會話 {current_session.session_id}")
|
||||||
return JSONResponse(content={"status": "success", "message": "用戶消息已記錄"})
|
return JSONResponse(
|
||||||
|
content={"status": "success", "message": "用戶消息已記錄"}
|
||||||
|
)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
debug_log(f"添加用戶消息失敗: {e}")
|
debug_log(f"添加用戶消息失敗: {e}")
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
status_code=500,
|
status_code=500, content={"error": f"添加用戶消息失敗: {e!s}"}
|
||||||
content={"error": f"添加用戶消息失敗: {e!s}"}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@manager.app.websocket("/ws")
|
@manager.app.websocket("/ws")
|
||||||
@ -556,6 +553,10 @@ async def handle_websocket_message(manager: "WebUIManager", session, data: dict)
|
|||||||
|
|
||||||
elif message_type == "heartbeat":
|
elif message_type == "heartbeat":
|
||||||
# WebSocket 心跳處理(簡化版)
|
# WebSocket 心跳處理(簡化版)
|
||||||
|
# 更新心跳時間
|
||||||
|
session.last_heartbeat = time.time()
|
||||||
|
session.last_activity = time.time()
|
||||||
|
|
||||||
# 發送心跳回應
|
# 發送心跳回應
|
||||||
if session.websocket:
|
if session.websocket:
|
||||||
try:
|
try:
|
||||||
@ -575,6 +576,11 @@ async def handle_websocket_message(manager: "WebUIManager", session, data: dict)
|
|||||||
await session._cleanup_resources_on_timeout()
|
await session._cleanup_resources_on_timeout()
|
||||||
# 重構:不再自動停止服務器,保持服務器運行以支援持久性
|
# 重構:不再自動停止服務器,保持服務器運行以支援持久性
|
||||||
|
|
||||||
|
elif message_type == "pong":
|
||||||
|
# 處理來自前端的 pong 回應(用於連接檢測)
|
||||||
|
debug_log(f"收到 pong 回應,時間戳: {data.get('timestamp', 'N/A')}")
|
||||||
|
# 可以在這裡記錄延遲或更新連接狀態
|
||||||
|
|
||||||
else:
|
else:
|
||||||
debug_log(f"未知的消息類型: {message_type}")
|
debug_log(f"未知的消息類型: {message_type}")
|
||||||
|
|
||||||
|
@ -704,7 +704,7 @@
|
|||||||
|
|
||||||
// 檢查是否是新會話創建的通知
|
// 檢查是否是新會話創建的通知
|
||||||
if (data.action === 'new_session_created' || data.type === 'new_session_created') {
|
if (data.action === 'new_session_created' || data.type === 'new_session_created') {
|
||||||
console.log('🆕 檢測到新會話創建,完全刷新頁面以確保狀態同步');
|
console.log('🆕 檢測到新會話創建,局部更新頁面內容');
|
||||||
|
|
||||||
// 播放音效通知
|
// 播放音效通知
|
||||||
if (this.audioManager) {
|
if (this.audioManager) {
|
||||||
@ -713,28 +713,40 @@
|
|||||||
|
|
||||||
// 顯示新會話通知
|
// 顯示新會話通知
|
||||||
window.MCPFeedback.Utils.showMessage(
|
window.MCPFeedback.Utils.showMessage(
|
||||||
data.message || '新的 MCP 會話已創建,正在打開新窗口...',
|
data.message || '新的 MCP 會話已創建,正在更新內容...',
|
||||||
window.MCPFeedback.Utils.CONSTANTS.MESSAGE_SUCCESS
|
window.MCPFeedback.Utils.CONSTANTS.MESSAGE_SUCCESS
|
||||||
);
|
);
|
||||||
|
|
||||||
// 使用 window.open 打開新窗口並關閉當前窗口
|
// 局部更新頁面內容而非開啟新視窗
|
||||||
|
const self = this;
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
console.log('🔄 使用 window.open 打開新窗口');
|
console.log('🔄 執行局部更新頁面內容');
|
||||||
|
|
||||||
// 打開新窗口
|
// 1. 更新會話資訊
|
||||||
const newWindow = window.open(window.location.href, '_blank');
|
if (data.session_info) {
|
||||||
|
self.currentSessionId = data.session_info.session_id;
|
||||||
if (newWindow) {
|
console.log('📋 新會話 ID:', self.currentSessionId);
|
||||||
console.log('✅ 新窗口打開成功,關閉當前窗口');
|
|
||||||
// 短暫延遲後關閉當前窗口
|
|
||||||
setTimeout(function() {
|
|
||||||
window.close();
|
|
||||||
}, 500);
|
|
||||||
} else {
|
|
||||||
console.warn('❌ window.open 被阻止,回退到頁面刷新');
|
|
||||||
window.location.reload();
|
|
||||||
}
|
}
|
||||||
}, 1500);
|
|
||||||
|
// 2. 刷新頁面內容(AI 摘要、表單等)
|
||||||
|
self.refreshPageContent();
|
||||||
|
|
||||||
|
// 3. 重置表單狀態
|
||||||
|
self.clearFeedback();
|
||||||
|
|
||||||
|
// 4. 重置回饋狀態為等待中
|
||||||
|
if (self.uiManager) {
|
||||||
|
self.uiManager.setFeedbackState(
|
||||||
|
window.MCPFeedback.Utils.CONSTANTS.FEEDBACK_WAITING,
|
||||||
|
self.currentSessionId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 檢查並啟動自動提交
|
||||||
|
self.checkAndStartAutoSubmit();
|
||||||
|
|
||||||
|
console.log('✅ 局部更新完成,頁面已準備好接收新的回饋');
|
||||||
|
}, 500);
|
||||||
|
|
||||||
return; // 提前返回,不執行後續的局部更新邏輯
|
return; // 提前返回,不執行後續的局部更新邏輯
|
||||||
}
|
}
|
||||||
|
@ -269,6 +269,14 @@
|
|||||||
this.connectionMonitor.recordPong();
|
this.connectionMonitor.recordPong();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'ping':
|
||||||
|
// 處理來自伺服器的 ping 消息(用於連接檢測)
|
||||||
|
console.log('收到伺服器 ping,立即回應 pong');
|
||||||
|
this.send({
|
||||||
|
type: 'pong',
|
||||||
|
timestamp: data.timestamp
|
||||||
|
});
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// 其他訊息類型由外部處理
|
// 其他訊息類型由外部處理
|
||||||
break;
|
break;
|
||||||
|
@ -182,8 +182,8 @@ class TestWebFeedbackSessionCleanup:
|
|||||||
"""測試狀態更新重置定時器"""
|
"""測試狀態更新重置定時器"""
|
||||||
old_timer = self.session.cleanup_timer
|
old_timer = self.session.cleanup_timer
|
||||||
|
|
||||||
# 更新狀態為活躍
|
# 更新狀態為活躍 - 使用 next_step 方法
|
||||||
self.session.update_status(SessionStatus.ACTIVE, "測試活躍狀態")
|
self.session.next_step("測試活躍狀態")
|
||||||
|
|
||||||
# 檢查定時器是否被重置
|
# 檢查定時器是否被重置
|
||||||
assert self.session.cleanup_timer != old_timer
|
assert self.session.cleanup_timer != old_timer
|
||||||
|
@ -108,11 +108,16 @@ class TestWebFeedbackSession:
|
|||||||
# 測試初始狀態
|
# 測試初始狀態
|
||||||
assert session.status == SessionStatus.WAITING
|
assert session.status == SessionStatus.WAITING
|
||||||
|
|
||||||
# 測試狀態更新
|
# 測試狀態更新 - 使用 next_step 方法
|
||||||
session.update_status(SessionStatus.FEEDBACK_SUBMITTED, "已提交回饋")
|
# 首先進入 ACTIVE 狀態
|
||||||
|
result = session.next_step("會話已激活")
|
||||||
|
assert result is True
|
||||||
|
assert session.status == SessionStatus.ACTIVE
|
||||||
|
# 然後進入 FEEDBACK_SUBMITTED 狀態
|
||||||
|
result = session.next_step("已提交回饋") # type: ignore[unreachable]
|
||||||
|
assert result is True
|
||||||
assert session.status == SessionStatus.FEEDBACK_SUBMITTED
|
assert session.status == SessionStatus.FEEDBACK_SUBMITTED
|
||||||
# 修復 unreachable 錯誤 - 使用 type: ignore 註解
|
assert session.status_message == "已提交回饋"
|
||||||
assert session.status_message == "已提交回饋" # type: ignore[unreachable]
|
|
||||||
|
|
||||||
def test_session_age_and_idle_time(self, test_project_dir):
|
def test_session_age_and_idle_time(self, test_project_dir):
|
||||||
"""測試會話年齡和空閒時間"""
|
"""測試會話年齡和空閒時間"""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user