Neda/Back/domains/realtime/ws.py
2026-03-06 15:16:41 +03:30

111 lines
3.1 KiB
Python

from fastapi import APIRouter, WebSocket, WebSocketDisconnect
from core.websocket import get_ws_current_user
from domains.realtime.ws_manager import manager
from domains.realtime.presence_service import (
user_join_group,
user_leave_group,
list_online_users
)
from domains.realtime.speaker_service import (
request_speak,
stop_speaking,
current_speaker
)
from integrations.livekit.token_service import generate_join_token
from db.session import AsyncSessionLocal
router = APIRouter()
@router.websocket("/ws/groups/{group_id}")
async def group_ws(websocket: WebSocket, group_id: str):
user = await get_ws_current_user(websocket)
user_id = str(user.id)
# connect websocket
await manager.connect(group_id, websocket)
# add presence
await user_join_group(group_id, user_id)
# give listener token
listener_token = generate_join_token(
user_id=user_id,
group_id=group_id,
can_publish=False
)
await websocket.send_json({
"type": "livekit_token",
"token": listener_token
})
# broadcast updated presence
await manager.broadcast(
group_id,
{
"type": "presence",
"users": await list_online_users(group_id)
}
)
try:
while True:
data = await websocket.receive_json()
event = data.get("type")
# user wants to speak
if event == "request_speak":
async with AsyncSessionLocal() as db:
token = await request_speak(
db,
group_id,
user_id
)
if token:
await manager.broadcast(
group_id,
{
"type": "speaker",
"user_id": user_id
}
)
await websocket.send_json({
"type": "speaker_granted",
"token": token
})
else:
async with AsyncSessionLocal() as db:
speaker = await current_speaker(db, group_id)
await websocket.send_json({
"type": "speaker_busy",
"speaker": speaker
})
# user stops speaking
elif event == "stop_speak":
async with AsyncSessionLocal() as db:
await stop_speaking(db, group_id, user_id)
await manager.broadcast(
group_id,
{
"type": "speaker_released"
}
)
except WebSocketDisconnect:
manager.disconnect(group_id, websocket)
await user_leave_group(group_id, user_id)
await manager.broadcast(
group_id,
{
"type": "presence",
"users": await list_online_users(group_id)
}
)