refactor(signalr): remove SignalR server & msgpack_lazer_api
Maybe we can make `msgpack_lazer_api` independent?
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
# from app.signalr import signalr_router as signalr_router
|
||||
from .auth import router as auth_router
|
||||
from .fetcher import fetcher_router as fetcher_router
|
||||
from .file import file_router as file_router
|
||||
@@ -25,5 +24,4 @@ __all__ = [
|
||||
"private_router",
|
||||
"redirect_api_router",
|
||||
"redirect_router",
|
||||
# "signalr_router",
|
||||
]
|
||||
|
||||
@@ -15,7 +15,7 @@ from app.dependencies.database import Database, Redis
|
||||
from app.dependencies.fetcher import Fetcher
|
||||
from app.dependencies.storage import StorageService
|
||||
from app.log import log
|
||||
from app.models.multiplayer_hub import PlaylistItem as HubPlaylistItem
|
||||
from app.models.playlist import PlaylistItem
|
||||
from app.models.room import MatchType, QueueMode, RoomCategory, RoomStatus
|
||||
from app.utils import utcnow
|
||||
|
||||
@@ -216,7 +216,7 @@ async def _add_playlist_items(db: Database, room_id: int, room_data: dict[str, A
|
||||
|
||||
# Insert playlist items
|
||||
for item_data in items_raw:
|
||||
hub_item = HubPlaylistItem(
|
||||
playlist_item = PlaylistItem(
|
||||
id=-1, # Placeholder, will be assigned by add_to_db
|
||||
owner_id=item_data["owner_id"],
|
||||
ruleset_id=item_data["ruleset_id"],
|
||||
@@ -230,7 +230,7 @@ async def _add_playlist_items(db: Database, room_id: int, room_data: dict[str, A
|
||||
beatmap_checksum=item_data["beatmap_checksum"],
|
||||
star_rating=item_data["star_rating"],
|
||||
)
|
||||
await DBPlaylist.add_to_db(hub_item, room_id=room_id, session=db)
|
||||
await DBPlaylist.add_to_db(playlist_item, room_id=room_id, session=db)
|
||||
|
||||
|
||||
async def _add_host_as_participant(db: Database, room_id: int, host_user_id: int) -> None:
|
||||
|
||||
@@ -2,7 +2,6 @@ from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from collections.abc import Awaitable, Callable
|
||||
from datetime import timedelta
|
||||
from math import ceil
|
||||
import random
|
||||
import shlex
|
||||
@@ -10,27 +9,15 @@ import shlex
|
||||
from app.calculator import calculate_weighted_pp
|
||||
from app.const import BANCHOBOT_ID
|
||||
from app.database import ChatMessageResp
|
||||
from app.database.beatmap import Beatmap
|
||||
from app.database.chat import ChannelType, ChatChannel, ChatMessage, MessageType
|
||||
from app.database.score import Score, get_best_id
|
||||
from app.database.statistics import UserStatistics, get_rank
|
||||
from app.database.user import User
|
||||
from app.dependencies.fetcher import get_fetcher
|
||||
from app.exception import InvokeException
|
||||
from app.models.mods import APIMod, get_available_mods, mod_to_save
|
||||
from app.models.multiplayer_hub import (
|
||||
ChangeTeamRequest,
|
||||
ServerMultiplayerRoom,
|
||||
StartMatchCountdownRequest,
|
||||
)
|
||||
from app.models.room import MatchType, QueueMode, RoomStatus
|
||||
from app.models.mods import mod_to_save
|
||||
from app.models.score import GameMode
|
||||
from app.signalr.hub import MultiplayerHubs
|
||||
from app.signalr.hub.hub import Client
|
||||
|
||||
from .server import server
|
||||
|
||||
from httpx import HTTPError
|
||||
from sqlalchemy.orm import joinedload
|
||||
from sqlmodel import col, func, select
|
||||
from sqlmodel.ext.asyncio.session import AsyncSession
|
||||
@@ -216,352 +203,6 @@ PP: {statistics.pp:.2f}
|
||||
"""
|
||||
|
||||
|
||||
async def _mp_name(
|
||||
signalr_client: Client,
|
||||
room: ServerMultiplayerRoom,
|
||||
args: list[str],
|
||||
session: AsyncSession,
|
||||
) -> str:
|
||||
if len(args) < 1:
|
||||
return "Usage: !mp name <name>"
|
||||
|
||||
name = args[0]
|
||||
try:
|
||||
settings = room.room.settings.model_copy()
|
||||
settings.name = name
|
||||
await MultiplayerHubs.ChangeSettings(signalr_client, settings)
|
||||
return f"Room name has changed to {name}"
|
||||
except InvokeException as e:
|
||||
return e.message
|
||||
|
||||
|
||||
async def _mp_set(
|
||||
signalr_client: Client,
|
||||
room: ServerMultiplayerRoom,
|
||||
args: list[str],
|
||||
session: AsyncSession,
|
||||
) -> str:
|
||||
if len(args) < 1:
|
||||
return "Usage: !mp set <teammode> [<queuemode>]"
|
||||
|
||||
teammode = {"0": MatchType.HEAD_TO_HEAD, "2": MatchType.TEAM_VERSUS}.get(args[0])
|
||||
if not teammode:
|
||||
return "Invalid teammode. Use 0 for Head-to-Head or 2 for Team Versus."
|
||||
queuemode = (
|
||||
{
|
||||
"0": QueueMode.HOST_ONLY,
|
||||
"1": QueueMode.ALL_PLAYERS,
|
||||
"2": QueueMode.ALL_PLAYERS_ROUND_ROBIN,
|
||||
}.get(args[1])
|
||||
if len(args) >= 2
|
||||
else None
|
||||
)
|
||||
try:
|
||||
settings = room.room.settings.model_copy()
|
||||
settings.match_type = teammode
|
||||
if queuemode:
|
||||
settings.queue_mode = queuemode
|
||||
await MultiplayerHubs.ChangeSettings(signalr_client, settings)
|
||||
return f"Room setting 'teammode' has been changed to {teammode.name.lower()}"
|
||||
except InvokeException as e:
|
||||
return e.message
|
||||
|
||||
|
||||
async def _mp_host(
|
||||
signalr_client: Client,
|
||||
room: ServerMultiplayerRoom,
|
||||
args: list[str],
|
||||
session: AsyncSession,
|
||||
) -> str:
|
||||
if len(args) < 1:
|
||||
return "Usage: !mp host <username>"
|
||||
|
||||
username = args[0]
|
||||
user_id = (await session.exec(select(User.id).where(User.username == username))).first()
|
||||
if not user_id:
|
||||
return f"User '{username}' not found."
|
||||
|
||||
try:
|
||||
await MultiplayerHubs.TransferHost(signalr_client, user_id)
|
||||
return f"User '{username}' has been hosted in the room."
|
||||
except InvokeException as e:
|
||||
return e.message
|
||||
|
||||
|
||||
async def _mp_start(
|
||||
signalr_client: Client,
|
||||
room: ServerMultiplayerRoom,
|
||||
args: list[str],
|
||||
session: AsyncSession,
|
||||
) -> str:
|
||||
timer = None
|
||||
if len(args) >= 1 and args[0].isdigit():
|
||||
timer = int(args[0])
|
||||
|
||||
try:
|
||||
if timer is not None:
|
||||
await MultiplayerHubs.SendMatchRequest(
|
||||
signalr_client,
|
||||
StartMatchCountdownRequest(duration=timedelta(seconds=timer)),
|
||||
)
|
||||
return ""
|
||||
else:
|
||||
await MultiplayerHubs.StartMatch(signalr_client)
|
||||
return "Good luck! Enjoy game!"
|
||||
except InvokeException as e:
|
||||
return e.message
|
||||
|
||||
|
||||
async def _mp_abort(
|
||||
signalr_client: Client,
|
||||
room: ServerMultiplayerRoom,
|
||||
args: list[str],
|
||||
session: AsyncSession,
|
||||
) -> str:
|
||||
try:
|
||||
await MultiplayerHubs.AbortMatch(signalr_client)
|
||||
return "Match aborted."
|
||||
except InvokeException as e:
|
||||
return e.message
|
||||
|
||||
|
||||
async def _mp_team(
|
||||
signalr_client: Client,
|
||||
room: ServerMultiplayerRoom,
|
||||
args: list[str],
|
||||
session: AsyncSession,
|
||||
):
|
||||
if room.room.settings.match_type != MatchType.TEAM_VERSUS:
|
||||
return "This command is only available in Team Versus mode."
|
||||
|
||||
if len(args) < 2:
|
||||
return "Usage: !mp team <username> <colour>"
|
||||
|
||||
username = args[0]
|
||||
team = {"red": 0, "blue": 1}.get(args[1])
|
||||
if team is None:
|
||||
return "Invalid team colour. Use 'red' or 'blue'."
|
||||
|
||||
user_id = (await session.exec(select(User.id).where(User.username == username))).first()
|
||||
if not user_id:
|
||||
return f"User '{username}' not found."
|
||||
user_client = MultiplayerHubs.get_client_by_id(str(user_id))
|
||||
if not user_client:
|
||||
return f"User '{username}' is not in the room."
|
||||
assert room.room.host
|
||||
if user_client.user_id != signalr_client.user_id and room.room.host.user_id != signalr_client.user_id:
|
||||
return "You are not allowed to change other users' teams."
|
||||
|
||||
try:
|
||||
await MultiplayerHubs.SendMatchRequest(user_client, ChangeTeamRequest(team_id=team))
|
||||
return ""
|
||||
except InvokeException as e:
|
||||
return e.message
|
||||
|
||||
|
||||
async def _mp_password(
|
||||
signalr_client: Client,
|
||||
room: ServerMultiplayerRoom,
|
||||
args: list[str],
|
||||
session: AsyncSession,
|
||||
) -> str:
|
||||
password = ""
|
||||
if len(args) >= 1:
|
||||
password = args[0]
|
||||
|
||||
try:
|
||||
settings = room.room.settings.model_copy()
|
||||
settings.password = password
|
||||
await MultiplayerHubs.ChangeSettings(signalr_client, settings)
|
||||
return "Room password has been set."
|
||||
except InvokeException as e:
|
||||
return e.message
|
||||
|
||||
|
||||
async def _mp_kick(
|
||||
signalr_client: Client,
|
||||
room: ServerMultiplayerRoom,
|
||||
args: list[str],
|
||||
session: AsyncSession,
|
||||
) -> str:
|
||||
if len(args) < 1:
|
||||
return "Usage: !mp kick <username>"
|
||||
|
||||
username = args[0]
|
||||
user_id = (await session.exec(select(User.id).where(User.username == username))).first()
|
||||
if not user_id:
|
||||
return f"User '{username}' not found."
|
||||
|
||||
try:
|
||||
await MultiplayerHubs.KickUser(signalr_client, user_id)
|
||||
return f"User '{username}' has been kicked from the room."
|
||||
except InvokeException as e:
|
||||
return e.message
|
||||
|
||||
|
||||
async def _mp_map(
|
||||
signalr_client: Client,
|
||||
room: ServerMultiplayerRoom,
|
||||
args: list[str],
|
||||
session: AsyncSession,
|
||||
) -> str:
|
||||
if len(args) < 1:
|
||||
return "Usage: !mp map <mapid> [<playmode>]"
|
||||
|
||||
if room.status != RoomStatus.IDLE:
|
||||
return "Cannot change map while the game is running."
|
||||
|
||||
map_id = args[0]
|
||||
if not map_id.isdigit():
|
||||
return "Invalid map ID."
|
||||
map_id = int(map_id)
|
||||
playmode = GameMode.parse(args[1].upper()) if len(args) >= 2 else None
|
||||
if playmode not in (
|
||||
GameMode.OSU,
|
||||
GameMode.TAIKO,
|
||||
GameMode.FRUITS,
|
||||
GameMode.MANIA,
|
||||
None,
|
||||
):
|
||||
return "Invalid playmode."
|
||||
|
||||
try:
|
||||
beatmap = await Beatmap.get_or_fetch(session, await get_fetcher(), bid=map_id)
|
||||
if beatmap.mode != GameMode.OSU and playmode and playmode != beatmap.mode:
|
||||
return f"Cannot convert to {playmode.value}. Original mode is {beatmap.mode.value}."
|
||||
except HTTPError:
|
||||
return "Beatmap not found"
|
||||
|
||||
try:
|
||||
current_item = room.queue.current_item
|
||||
item = current_item.model_copy(deep=True)
|
||||
item.owner_id = signalr_client.user_id
|
||||
item.beatmap_checksum = beatmap.checksum
|
||||
item.required_mods = []
|
||||
item.allowed_mods = []
|
||||
item.freestyle = False
|
||||
item.beatmap_id = map_id
|
||||
if playmode is not None:
|
||||
item.ruleset_id = int(playmode)
|
||||
if item.expired:
|
||||
item.id = 0
|
||||
item.expired = False
|
||||
item.played_at = None
|
||||
await MultiplayerHubs.AddPlaylistItem(signalr_client, item)
|
||||
else:
|
||||
await MultiplayerHubs.EditPlaylistItem(signalr_client, item)
|
||||
return ""
|
||||
except InvokeException as e:
|
||||
return e.message
|
||||
|
||||
|
||||
async def _mp_mods(
|
||||
signalr_client: Client,
|
||||
room: ServerMultiplayerRoom,
|
||||
args: list[str],
|
||||
session: AsyncSession,
|
||||
) -> str:
|
||||
if len(args) < 1:
|
||||
return "Usage: !mp mods <mod1> [<mod2> ...]"
|
||||
|
||||
if room.status != RoomStatus.IDLE:
|
||||
return "Cannot change mods while the game is running."
|
||||
|
||||
required_mods = []
|
||||
allowed_mods = []
|
||||
freestyle = False
|
||||
freemod = False
|
||||
for arg in args:
|
||||
arg = arg.upper()
|
||||
if arg == "NONE":
|
||||
required_mods.clear()
|
||||
allowed_mods.clear()
|
||||
break
|
||||
elif arg == "FREESTYLE":
|
||||
freestyle = True
|
||||
elif arg == "FREEMOD":
|
||||
freemod = True
|
||||
elif arg.startswith("+"):
|
||||
mod = arg.removeprefix("+")
|
||||
if len(mod) != 2:
|
||||
return f"Invalid mod: {mod}."
|
||||
allowed_mods.append(APIMod(acronym=mod))
|
||||
else:
|
||||
if len(arg) != 2:
|
||||
return f"Invalid mod: {arg}."
|
||||
required_mods.append(APIMod(acronym=arg))
|
||||
|
||||
try:
|
||||
current_item = room.queue.current_item
|
||||
item = current_item.model_copy(deep=True)
|
||||
item.owner_id = signalr_client.user_id
|
||||
item.freestyle = freestyle
|
||||
if freestyle:
|
||||
item.allowed_mods = []
|
||||
elif freemod:
|
||||
item.allowed_mods = get_available_mods(current_item.ruleset_id, required_mods)
|
||||
else:
|
||||
item.allowed_mods = allowed_mods
|
||||
item.required_mods = required_mods
|
||||
if item.expired:
|
||||
item.id = 0
|
||||
item.expired = False
|
||||
item.played_at = None
|
||||
await MultiplayerHubs.AddPlaylistItem(signalr_client, item)
|
||||
else:
|
||||
await MultiplayerHubs.EditPlaylistItem(signalr_client, item)
|
||||
return ""
|
||||
except InvokeException as e:
|
||||
return e.message
|
||||
|
||||
|
||||
_MP_COMMANDS = {
|
||||
"name": _mp_name,
|
||||
"set": _mp_set,
|
||||
"host": _mp_host,
|
||||
"start": _mp_start,
|
||||
"abort": _mp_abort,
|
||||
"map": _mp_map,
|
||||
"mods": _mp_mods,
|
||||
"kick": _mp_kick,
|
||||
"password": _mp_password,
|
||||
"team": _mp_team,
|
||||
}
|
||||
_MP_HELP = """!mp name <name>
|
||||
!mp set <teammode> [<queuemode>]
|
||||
!mp host <host>
|
||||
!mp start [<timer>]
|
||||
!mp abort
|
||||
!mp map <map> [<playmode>]
|
||||
!mp mods <mod1> [<mod2> ...]
|
||||
!mp kick <user>
|
||||
!mp password [<password>]
|
||||
!mp team <user> <team:red|blue>"""
|
||||
|
||||
|
||||
@bot.command("mp")
|
||||
async def _mp(user: User, args: list[str], session: AsyncSession, channel: ChatChannel):
|
||||
if not channel.name.startswith("room_"):
|
||||
return
|
||||
|
||||
room_id = int(channel.name[5:])
|
||||
room = MultiplayerHubs.rooms.get(room_id)
|
||||
if not room:
|
||||
return
|
||||
signalr_client = MultiplayerHubs.get_client_by_id(str(user.id))
|
||||
if not signalr_client:
|
||||
return
|
||||
|
||||
if len(args) < 1:
|
||||
return f"Usage: !mp <{'|'.join(_MP_COMMANDS.keys())}> [args]"
|
||||
|
||||
command = args[0].lower()
|
||||
if command not in _MP_COMMANDS:
|
||||
return f"No such command: {command}"
|
||||
|
||||
return await _MP_COMMANDS[command](signalr_client, room, args[1:], session)
|
||||
|
||||
|
||||
async def _score(
|
||||
user_id: int,
|
||||
session: AsyncSession,
|
||||
|
||||
@@ -16,7 +16,6 @@ from app.dependencies.database import Database, Redis
|
||||
from app.dependencies.user import ClientUser, get_current_user
|
||||
from app.models.room import RoomCategory, RoomStatus
|
||||
from app.service.room import create_playlist_room_from_api
|
||||
from app.signalr.hub import MultiplayerHubs
|
||||
from app.utils import utcnow
|
||||
|
||||
from .router import router
|
||||
@@ -391,14 +390,12 @@ async def get_room_events(
|
||||
first_event_id = min(first_event_id, event.id)
|
||||
last_event_id = max(last_event_id, event.id)
|
||||
|
||||
if room := MultiplayerHubs.rooms.get(room_id):
|
||||
current_playlist_item_id = room.queue.current_item.id
|
||||
room_resp = await RoomResp.from_hub(room)
|
||||
else:
|
||||
room = (await db.exec(select(Room).where(Room.id == room_id))).first()
|
||||
if room is None:
|
||||
raise HTTPException(404, "Room not found")
|
||||
room_resp = await RoomResp.from_db(room, db)
|
||||
room = (await db.exec(select(Room).where(Room.id == room_id))).first()
|
||||
if room is None:
|
||||
raise HTTPException(404, "Room not found")
|
||||
room_resp = await RoomResp.from_db(room, db)
|
||||
if room.category == RoomCategory.REALTIME and room_resp.current_playlist_item:
|
||||
current_playlist_item_id = room_resp.current_playlist_item.id
|
||||
|
||||
users = await db.exec(select(User).where(col(User.id).in_(user_ids)))
|
||||
user_resps = [await UserResp.from_db(user, db) for user in users]
|
||||
|
||||
Reference in New Issue
Block a user