from __future__ import annotations from enum import IntEnum from typing import Annotated, ClassVar, Literal from app.models.signalr import SignalRMeta, SignalRUnionMessage, UserState from pydantic import BaseModel, Field class _UserActivity(SignalRUnionMessage): ... class ChoosingBeatmap(_UserActivity): union_type: ClassVar[Literal[11]] = 11 class _InGame(_UserActivity): beatmap_id: int beatmap_display_title: str ruleset_id: int ruleset_playing_verb: str class InSoloGame(_InGame): union_type: ClassVar[Literal[12]] = 12 class InMultiplayerGame(_InGame): union_type: ClassVar[Literal[23]] = 23 class SpectatingMultiplayerGame(_InGame): union_type: ClassVar[Literal[24]] = 24 class InPlaylistGame(_InGame): union_type: ClassVar[Literal[31]] = 31 class PlayingDailyChallenge(_InGame): union_type: ClassVar[Literal[52]] = 52 class EditingBeatmap(_UserActivity): union_type: ClassVar[Literal[41]] = 41 beatmap_id: int beatmap_display_title: str class TestingBeatmap(EditingBeatmap): union_type: ClassVar[Literal[43]] = 43 class ModdingBeatmap(EditingBeatmap): union_type: ClassVar[Literal[42]] = 42 class WatchingReplay(_UserActivity): union_type: ClassVar[Literal[13]] = 13 score_id: int player_name: str beatmap_id: int beatmap_display_title: str class SpectatingUser(WatchingReplay): union_type: ClassVar[Literal[14]] = 14 class SearchingForLobby(_UserActivity): union_type: ClassVar[Literal[21]] = 21 class InLobby(_UserActivity): union_type: ClassVar[Literal[22]] = 22 room_id: int room_name: str class InDailyChallengeLobby(_UserActivity): union_type: ClassVar[Literal[51]] = 51 UserActivity = ( ChoosingBeatmap | InSoloGame | WatchingReplay | SpectatingUser | SearchingForLobby | InLobby | InMultiplayerGame | SpectatingMultiplayerGame | InPlaylistGame | EditingBeatmap | ModdingBeatmap | TestingBeatmap | InDailyChallengeLobby ) class UserPresence(BaseModel): activity: Annotated[ UserActivity | None, Field(default=None), SignalRMeta(use_upper_case=True) ] status: Annotated[ OnlineStatus | None, Field(default=None), SignalRMeta(use_upper_case=True) ] @property def pushable(self) -> bool: return self.status is not None and self.status != OnlineStatus.OFFLINE @property def for_push(self) -> "UserPresence | None": return UserPresence( activity=self.activity, status=self.status, ) class MetadataClientState(UserPresence, UserState): ... class OnlineStatus(IntEnum): OFFLINE = 0 # 隐身 DO_NOT_DISTURB = 1 ONLINE = 2