Refactor room participant and password handling

Replaces ORM object updates with SQLAlchemy update statements for participant and room records, improving efficiency. Enhances room password verification logic and request body parsing in add_user_to_room, adds debug logging, and simplifies error handling. Removes unused user_data parameter and streamlines participant removal.
This commit is contained in:
咕谷酱
2025-08-23 21:39:40 +08:00
committed by MingxuanGame
parent 8e6b462645
commit 403d395ccc

View File

@@ -6,7 +6,8 @@ from typing import Any, Dict, List
from fastapi import APIRouter, HTTPException, Request, status from fastapi import APIRouter, HTTPException, Request, status
from pydantic import BaseModel from pydantic import BaseModel
from sqlmodel import col, select from sqlmodel import col, select, desc
from sqlalchemy import update
from app.database.lazer_user import User from app.database.lazer_user import User
from app.database.playlists import Playlist as DBPlaylist from app.database.playlists import Playlist as DBPlaylist
@@ -234,49 +235,69 @@ async def _update_room_participant_count(db: Database, room_id: int) -> None:
) )
count = len(active_participants.all()) count = len(active_participants.all())
# Update room participant count # Update room participant count using SQLAlchemy update statement
room_result = await db.execute(select(Room).where(Room.id == room_id)) await db.execute(
room_obj = room_result.scalar_one_or_none() update(Room)
if room_obj: .where(col(Room.id) == room_id)
room_obj.participant_count = count .values(participant_count=count)
)
async def _verify_room_password(db: Database, room_id: int, provided_password: str | None) -> None: async def _verify_room_password(db: Database, room_id: int, provided_password: str | None) -> None:
"""Verify room password if required.""" """Verify room password if required."""
room_result = await db.execute( room_result = await db.execute(
select(Room.password).where(Room.id == room_id) select(Room).where(col(Room.id) == room_id)
) )
room_password = room_result.scalar_one_or_none() room = room_result.scalar_one_or_none()
if room_password is None: if room is None:
print(f"Room {room_id} not found")
raise HTTPException( raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND, status_code=status.HTTP_404_NOT_FOUND,
detail="Room not found" detail="Room not found"
) )
if room_password and provided_password != room_password: print(f"Room {room_id} has password: {bool(room.password)}, provided: {bool(provided_password)}")
# If room has password but none provided
if room.password and not provided_password:
print(f"Room {room_id} requires password but none provided")
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Password required"
)
# If room has password and provided password doesn't match
if room.password and provided_password and provided_password != room.password:
print(f"Room {room_id} password mismatch")
raise HTTPException( raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN, status_code=status.HTTP_403_FORBIDDEN,
detail="Invalid password" detail="Invalid password"
) )
print(f"Room {room_id} password verification passed")
async def _add_or_update_participant(db: Database, room_id: int, user_id: int) -> None: async def _add_or_update_participant(db: Database, room_id: int, user_id: int) -> None:
"""Add a user as participant or update existing participation.""" """Add a user as participant or update existing participation."""
# Check if user already has a participation record
existing_result = await db.execute( existing_result = await db.execute(
select(RoomParticipatedUser).where( select(RoomParticipatedUser.id).where(
RoomParticipatedUser.room_id == room_id, RoomParticipatedUser.room_id == room_id,
RoomParticipatedUser.user_id == user_id RoomParticipatedUser.user_id == user_id
).order_by(desc(RoomParticipatedUser.joined_at))
) )
) existing_id = existing_result.scalar_one_or_none()
existing = existing_result.scalar_one_or_none()
if existing: if existing_id:
# Rejoin room # Update existing participation record using SQLAlchemy update
existing.left_at = None await db.execute(
existing.joined_at = utcnow() update(RoomParticipatedUser)
.where(col(RoomParticipatedUser.id) == existing_id)
.values(left_at=None, joined_at=utcnow())
)
else: else:
# New participant # Create new participation record
participant = RoomParticipatedUser(room_id=room_id, user_id=user_id) participant = RoomParticipatedUser(room_id=room_id, user_id=user_id)
db.add(participant) db.add(participant)
@@ -346,21 +367,33 @@ async def add_user_to_room(
room_id: int, room_id: int,
user_id: int, user_id: int,
db: Database, db: Database,
user_data: Dict[str, Any] | None = None,
timestamp: str = "", timestamp: str = "",
) -> Dict[str, Any]: ) -> Dict[str, Any]:
"""Add a user to a multiplayer room.""" """Add a user to a multiplayer room."""
try: #try:
# Verify request signature print(f"Adding user {user_id} to room {room_id}")
# Get request body and parse user_data
body = await request.body() body = await request.body()
user_data = None
if body:
try:
user_data = json.loads(body.decode('utf-8'))
print(f"Parsed user_data: {user_data}")
except json.JSONDecodeError:
print("Failed to parse user_data from request body")
user_data = None
# Verify request signature
if not verify_request_signature(request, timestamp, body): if not verify_request_signature(request, timestamp, body):
raise HTTPException( raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid request signature" detail="Invalid request signature"
) )
# Verify room password if provided # Verify room exists and check password
provided_password = user_data.get("password") if user_data else None provided_password = user_data.get("password") if user_data else None
print(f"Verifying room {room_id} with password: {provided_password}")
await _verify_room_password(db, room_id, provided_password) await _verify_room_password(db, room_id, provided_password)
# Add or update participant # Add or update participant
@@ -370,15 +403,17 @@ async def add_user_to_room(
await _update_room_participant_count(db, room_id) await _update_room_participant_count(db, room_id)
await db.commit() await db.commit()
print(f"Successfully added user {user_id} to room {room_id}")
return {"success": True} return {"success": True}
except HTTPException: """ except HTTPException:
raise raise
except Exception as e: except Exception as e:
print(f"Error adding user to room: {str(e)}")
raise HTTPException( raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Failed to add user to room: {str(e)}" detail=f"Failed to add user to room: {str(e)}"
) ) """
@router.delete("/multiplayer/rooms/{room_id}/users/{user_id}") @router.delete("/multiplayer/rooms/{room_id}/users/{user_id}")
@@ -399,18 +434,16 @@ async def remove_user_from_room(
detail="Invalid request signature" detail="Invalid request signature"
) )
# Mark user as left # Mark user as left using SQLAlchemy update statement
result = await db.execute( await db.execute(
select(RoomParticipatedUser).where( update(RoomParticipatedUser)
RoomParticipatedUser.room_id == room_id, .where(
RoomParticipatedUser.user_id == user_id, col(RoomParticipatedUser.room_id) == room_id,
col(RoomParticipatedUser.user_id) == user_id,
col(RoomParticipatedUser.left_at).is_(None) col(RoomParticipatedUser.left_at).is_(None)
) )
.values(left_at=utcnow())
) )
participation = result.scalar_one_or_none()
if participation:
participation.left_at = utcnow()
# Update participant count # Update participant count
await _update_room_participant_count(db, room_id) await _update_room_participant_count(db, room_id)