feat(room): add POST /room API
This commit is contained in:
@@ -29,7 +29,7 @@ class RoomBase(SQLModel):
|
|||||||
name: str = Field(index=True)
|
name: str = Field(index=True)
|
||||||
category: RoomCategory = Field(default=RoomCategory.NORMAL, index=True)
|
category: RoomCategory = Field(default=RoomCategory.NORMAL, index=True)
|
||||||
duration: int | None = Field(default=None) # minutes
|
duration: int | None = Field(default=None) # minutes
|
||||||
starts_at: datetime = Field(
|
starts_at: datetime | None = Field(
|
||||||
sa_column=Column(
|
sa_column=Column(
|
||||||
DateTime(timezone=True),
|
DateTime(timezone=True),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -335,6 +335,58 @@ class MultiplayerRoom(BaseModel):
|
|||||||
active_countdowns: list[MultiplayerCountdown] = Field(default_factory=list)
|
active_countdowns: list[MultiplayerCountdown] = Field(default_factory=list)
|
||||||
channel_id: int
|
channel_id: int
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_db(cls, room) -> "MultiplayerRoom":
|
||||||
|
"""
|
||||||
|
将 Room (数据库模型) 转换为 MultiplayerRoom (业务模型)
|
||||||
|
"""
|
||||||
|
|
||||||
|
# 用户列表
|
||||||
|
users = [MultiplayerRoomUser(user_id=room.host_id)]
|
||||||
|
host_user = MultiplayerRoomUser(user_id=room.host_id)
|
||||||
|
# playlist 转换
|
||||||
|
playlist = []
|
||||||
|
if hasattr(room, "playlist"):
|
||||||
|
for item in room.playlist:
|
||||||
|
playlist.append(
|
||||||
|
PlaylistItem(
|
||||||
|
id=item.id,
|
||||||
|
owner_id=item.owner_id,
|
||||||
|
beatmap_id=item.beatmap_id,
|
||||||
|
beatmap_checksum=item.beatmap.checksum if item.beatmap else "",
|
||||||
|
ruleset_id=item.ruleset_id,
|
||||||
|
required_mods=item.required_mods,
|
||||||
|
allowed_mods=item.allowed_mods,
|
||||||
|
expired=item.expired,
|
||||||
|
playlist_order=item.playlist_order,
|
||||||
|
played_at=item.played_at,
|
||||||
|
star_rating=item.beatmap.difficulty_rating
|
||||||
|
if item.beatmap is not None
|
||||||
|
else 0.0,
|
||||||
|
freestyle=item.freestyle,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return cls(
|
||||||
|
room_id=room.id,
|
||||||
|
state=getattr(room, "state", MultiplayerRoomState.OPEN),
|
||||||
|
settings=MultiplayerRoomSettings(
|
||||||
|
name=room.name,
|
||||||
|
playlist_item_id=playlist[0].id if playlist else 0,
|
||||||
|
password=getattr(room, "password", ""),
|
||||||
|
match_type=room.type,
|
||||||
|
queue_mode=room.queue_mode,
|
||||||
|
auto_start_duration=timedelta(seconds=room.auto_start_duration),
|
||||||
|
auto_skip=room.auto_skip,
|
||||||
|
),
|
||||||
|
users=users,
|
||||||
|
host=host_user,
|
||||||
|
match_state=None,
|
||||||
|
playlist=playlist,
|
||||||
|
active_countdowns=[],
|
||||||
|
channel_id=getattr(room, "channel_id", 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class MultiplayerQueue:
|
class MultiplayerQueue:
|
||||||
def __init__(self, room: "ServerMultiplayerRoom"):
|
def __init__(self, room: "ServerMultiplayerRoom"):
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from datetime import UTC, datetime
|
||||||
|
from time import timezone
|
||||||
from typing import Literal
|
from typing import Literal
|
||||||
|
|
||||||
from app.database.lazer_user import User
|
from app.database.lazer_user import User
|
||||||
from app.database.room import RoomResp
|
from app.database.playlists import Playlist
|
||||||
|
from app.database.room import Room, RoomBase, RoomResp
|
||||||
from app.dependencies.database import get_db, get_redis
|
from app.dependencies.database import get_db, get_redis
|
||||||
from app.dependencies.fetcher import get_fetcher
|
from app.dependencies.fetcher import get_fetcher
|
||||||
from app.dependencies.user import get_current_user
|
from app.dependencies.user import get_current_user
|
||||||
from app.fetcher import Fetcher
|
from app.fetcher import Fetcher
|
||||||
|
from app.models.multiplayer_hub import MultiplayerRoom, ServerMultiplayerRoom
|
||||||
from app.models.room import RoomStatus
|
from app.models.room import RoomStatus
|
||||||
from app.signalr.hub import MultiplayerHubs
|
from app.signalr.hub import MultiplayerHubs
|
||||||
|
|
||||||
@@ -33,22 +37,68 @@ async def get_all_rooms(
|
|||||||
rooms = MultiplayerHubs.rooms.values()
|
rooms = MultiplayerHubs.rooms.values()
|
||||||
resp_list: list[RoomResp] = []
|
resp_list: list[RoomResp] = []
|
||||||
for room in rooms:
|
for room in rooms:
|
||||||
if category != "realtime": # 歌单模式的处理逻辑
|
if category == "realtime" and room.category != "normal":
|
||||||
if room.category == category:
|
continue
|
||||||
if mode == "owned":
|
elif category != room.category:
|
||||||
if (
|
continue
|
||||||
room.room.host.user_id if room.room.host is not None else 0
|
|
||||||
) != current_user.id:
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
if mode == "owned":
|
|
||||||
if (
|
|
||||||
room.room.host.user_id if room.room.host is not None else 0
|
|
||||||
) != current_user.id:
|
|
||||||
continue
|
|
||||||
if room.status != status:
|
|
||||||
continue
|
|
||||||
resp_list.append(await RoomResp.from_hub(room))
|
resp_list.append(await RoomResp.from_hub(room))
|
||||||
return resp_list
|
return resp_list
|
||||||
|
|
||||||
|
|
||||||
|
class APICreatedRoom(RoomResp):
|
||||||
|
error: str = ""
|
||||||
|
|
||||||
|
|
||||||
|
class APIUploadedRoom(RoomBase):
|
||||||
|
def to_room(self) -> Room:
|
||||||
|
"""
|
||||||
|
将 APIUploadedRoom 转换为 Room 对象,playlist 字段需单独处理。
|
||||||
|
"""
|
||||||
|
room_dict = self.model_dump()
|
||||||
|
room_dict.pop("playlist", None)
|
||||||
|
# host_id 已在字段中
|
||||||
|
return Room(**room_dict)
|
||||||
|
|
||||||
|
id: int | None
|
||||||
|
host_id: int | None = None
|
||||||
|
playlist: list[Playlist]
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/rooms", tags=["room"], response_model=APICreatedRoom)
|
||||||
|
async def create_room(
|
||||||
|
room: APIUploadedRoom,
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
current_user: User = Depends(get_current_user),
|
||||||
|
):
|
||||||
|
# db_room = Room.from_resp(room)
|
||||||
|
await db.refresh(current_user)
|
||||||
|
user_id = current_user.id
|
||||||
|
db_room = room.to_room()
|
||||||
|
db_room.host_id = current_user.id if current_user.id else 1
|
||||||
|
db.add(db_room)
|
||||||
|
await db.commit()
|
||||||
|
await db.refresh(db_room)
|
||||||
|
|
||||||
|
playlist: list[Playlist] = []
|
||||||
|
# 处理 APIUploadedRoom 里的 playlist 字段
|
||||||
|
for item in room.playlist:
|
||||||
|
# 确保 room_id 正确赋值
|
||||||
|
item.id = await Playlist.get_next_id_for_room(db_room.id, db)
|
||||||
|
item.room_id = db_room.id
|
||||||
|
item.owner_id = user_id if user_id else 1
|
||||||
|
db.add(item)
|
||||||
|
await db.commit()
|
||||||
|
await db.refresh(item)
|
||||||
|
playlist.append(item)
|
||||||
|
await db.refresh(db_room)
|
||||||
|
db_room.playlist = playlist
|
||||||
|
server_room = ServerMultiplayerRoom(
|
||||||
|
room=MultiplayerRoom.from_db(db_room),
|
||||||
|
category=db_room.category,
|
||||||
|
start_at=datetime.now(UTC),
|
||||||
|
hub=MultiplayerHubs,
|
||||||
|
)
|
||||||
|
MultiplayerHubs.rooms[db_room.id] = server_room
|
||||||
|
created_room = APICreatedRoom.model_validate(db_room)
|
||||||
|
created_room.error = ""
|
||||||
|
return created_room
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ class MultiplayerHub(Hub[MultiplayerClientState]):
|
|||||||
item = room.playlist[0]
|
item = room.playlist[0]
|
||||||
item.owner_id = client.user_id
|
item.owner_id = client.user_id
|
||||||
room.room_id = db_room.id
|
room.room_id = db_room.id
|
||||||
starts_at = db_room.starts_at
|
starts_at = db_room.starts_at or datetime.now(UTC)
|
||||||
await Playlist.add_to_db(item, db_room.id, session)
|
await Playlist.add_to_db(item, db_room.id, session)
|
||||||
server_room = ServerMultiplayerRoom(
|
server_room = ServerMultiplayerRoom(
|
||||||
room=room,
|
room=room,
|
||||||
|
|||||||
Reference in New Issue
Block a user