dedc3b4183
- Full FastAPI backend with JWT auth, file management, processing pipeline, memory CRUD, barcode mappings, config management, cloud sync - Vue 3 + Element Plus frontend with dashboard, task history, HTTP logs, memory editor, barcode editor, config editor, sync page - HTTP request logging middleware with SQLite persistence - Task history tracking with progress and retry support - File metadata recording for upload/download operations - WebAuth section in config.ini for bcrypt password storage - Bug fix: logs.py count query returns tuple not dict Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
48 lines
1.3 KiB
Python
48 lines
1.3 KiB
Python
"""WebSocket endpoint for real-time task progress."""
|
|
|
|
from fastapi import APIRouter, WebSocket, WebSocketDisconnect, Query
|
|
from ..auth.jwt_handler import decode_token
|
|
from jose import JWTError
|
|
|
|
router = APIRouter(tags=["websocket"])
|
|
|
|
|
|
@router.websocket("/ws/task/{task_id}")
|
|
async def task_websocket(
|
|
websocket: WebSocket,
|
|
task_id: str,
|
|
token: str = Query(...),
|
|
):
|
|
"""WebSocket for real-time task progress updates."""
|
|
try:
|
|
payload = decode_token(token)
|
|
username = payload.get("sub")
|
|
if not username:
|
|
await websocket.close(code=4001, reason="Invalid token")
|
|
return
|
|
except (JWTError, Exception):
|
|
await websocket.close(code=4001, reason="Invalid token")
|
|
return
|
|
|
|
await websocket.accept()
|
|
|
|
tm = websocket.app.state.task_manager
|
|
task = tm.get_task(task_id)
|
|
if not task:
|
|
await websocket.send_json({"error": "任务不存在"})
|
|
await websocket.close()
|
|
return
|
|
|
|
tm.subscribe(task_id, websocket)
|
|
await websocket.send_json(task.to_dict())
|
|
|
|
try:
|
|
while True:
|
|
data = await websocket.receive_text()
|
|
if data == "ping":
|
|
await websocket.send_text("pong")
|
|
except WebSocketDisconnect:
|
|
tm.unsubscribe(task_id, websocket)
|
|
except Exception:
|
|
tm.unsubscribe(task_id, websocket)
|