nakama/moderation/backend-py/websocket_server.py

128 lines
3.4 KiB
Python

"""
WebSocket server for moderation chat
"""
import socketio
import logging
from typing import Dict, Set
logger = logging.getLogger(__name__)
# Create Socket.IO server
sio = socketio.AsyncServer(
async_mode='asgi',
cors_allowed_origins='*',
logger=False,
engineio_logger=False
)
# Track connected moderators
connected_moderators: Dict[str, Set[str]] = {} # {room: {sid1, sid2, ...}}
@sio.event
async def connect(sid, environ):
"""Handle client connection"""
logger.info(f"[WebSocket] Client connected: {sid}")
@sio.event
async def disconnect(sid):
"""Handle client disconnection"""
logger.info(f"[WebSocket] Client disconnected: {sid}")
# Remove from all rooms
for room, sids in connected_moderators.items():
if sid in sids:
sids.remove(sid)
await sio.emit('user_left', {'sid': sid}, room=room, skip_sid=sid)
@sio.event
async def join_moderation_chat(sid, data):
"""Join moderation chat room"""
try:
user_id = data.get('userId')
username = data.get('username')
if not user_id:
return
room = 'moderation_chat'
await sio.enter_room(sid, room)
if room not in connected_moderators:
connected_moderators[room] = set()
connected_moderators[room].add(sid)
logger.info(f"[WebSocket] {username} ({user_id}) joined moderation chat")
# Notify others
await sio.emit('user_joined', {
'userId': user_id,
'username': username,
'sid': sid
}, room=room, skip_sid=sid)
except Exception as e:
logger.error(f"[WebSocket] Error joining chat: {e}")
@sio.event
async def leave_moderation_chat(sid, data):
"""Leave moderation chat room"""
try:
room = 'moderation_chat'
await sio.leave_room(sid, room)
if room in connected_moderators and sid in connected_moderators[room]:
connected_moderators[room].remove(sid)
# Notify others
await sio.emit('user_left', {'sid': sid}, room=room, skip_sid=sid)
except Exception as e:
logger.error(f"[WebSocket] Error leaving chat: {e}")
@sio.event
async def moderation_message(sid, data):
"""Handle moderation chat message"""
try:
room = 'moderation_chat'
message_data = {
'userId': data.get('userId'),
'username': data.get('username'),
'message': data.get('message'),
'timestamp': data.get('timestamp')
}
# Broadcast to all in room
await sio.emit('moderation_message', message_data, room=room)
logger.info(f"[WebSocket] Message from {data.get('username')}: {data.get('message')[:50]}...")
except Exception as e:
logger.error(f"[WebSocket] Error sending message: {e}")
@sio.event
async def typing(sid, data):
"""Handle typing indicator"""
try:
room = 'moderation_chat'
await sio.emit('typing', {
'userId': data.get('userId'),
'username': data.get('username'),
'isTyping': data.get('isTyping', True)
}, room=room, skip_sid=sid)
except Exception as e:
logger.error(f"[WebSocket] Error handling typing: {e}")
def get_socketio_app():
"""Get Socket.IO ASGI app"""
return socketio.ASGIApp(sio)