web-client/bff/ws_proxy.py
Markov 7185a50f57
Some checks failed
Deploy Web Client / deploy (push) Failing after 9s
v0.2.0: updated for new Tracker API
- api.ts: Member, Unified Message, Steps, new types
- ws.ts: auth.ok handling, project.subscribe, chat.send
- KanbanBoard: new statuses (backlog/todo/in_progress/in_review/done)
- TaskModal: steps checklist, comments (unified messages), member select
- ChatPanel: unified messages, WS events
- BFF: all new endpoints (members, messages, steps, task actions)
- BFF ws_proxy: token-based auth to tracker
2026-02-22 17:40:13 +01:00

73 lines
2.2 KiB
Python

"""WebSocket proxy: authenticated web users ↔ Tracker WS."""
import asyncio
import json
import logging
from fastapi import APIRouter, WebSocket, WebSocketDisconnect
import websockets
from auth import verify_token
from config import TRACKER_WS_URL, TRACKER_TOKEN
logger = logging.getLogger("bff.ws")
router = APIRouter()
@router.websocket("/ws")
async def ws_proxy(ws: WebSocket, token: str = ""):
# Authenticate user
if not token:
await ws.close(code=4001, reason="No token")
return
user = verify_token(token)
if not user:
await ws.close(code=4001, reason="Invalid token")
return
await ws.accept()
user_name = user.get("name", "unknown")
user_slug = user.get("sub", "admin")
logger.info("WS connected: %s (%s)", user_name, user_slug)
try:
async with websockets.connect(TRACKER_WS_URL) as tracker_ws:
# Send auth to tracker on behalf of user
auth_msg = json.dumps({
"type": "auth",
"token": TRACKER_TOKEN,
})
await tracker_ws.send(auth_msg)
# Wait for auth.ok
auth_resp = await tracker_ws.recv()
auth_data = json.loads(auth_resp)
if auth_data.get("type") != "auth.ok":
logger.error("Tracker auth failed: %s", auth_data)
await ws.close(code=4002, reason="Tracker auth failed")
return
# Forward auth.ok to client
await ws.send_text(auth_resp)
async def forward_to_tracker():
try:
while True:
data = await ws.receive_text()
await tracker_ws.send(data)
except WebSocketDisconnect:
pass
async def forward_to_client():
try:
async for msg in tracker_ws:
await ws.send_text(msg)
except Exception:
pass
await asyncio.gather(forward_to_tracker(), forward_to_client())
except Exception as e:
logger.error("WS proxy error: %s", e)
finally:
logger.info("WS disconnected: %s", user_name)