from __future__ import annotations from channels.generic.websocket import WebsocketConsumer from django.contrib.auth.models import User from django.db.models import QuerySet from django.utils.translation import gettext as _ from profiles.models import ProfileModel from profiles.serializers.ProfileSerializer import ProfileSerializer from .models import TournamentModel import json class TournamentMember: def __init__(self, socket: TournamentWebConsumer, room: TournamentRoom, is_participating: bool = False) -> None: self._socket: TournamentWebConsumer = socket self._room: TournamentRoom = room self.is_participating: bool = is_participating def send(self, detail: str, data: dict = {}): data_to_send: dict = {"detail": detail} data_to_send.update(data) self._socket.send(json.dumps(data_to_send)) def send_error(self, error_message: str, data: dict = {}): data_to_send: dict = {"error_message": error_message} data_to_send.update(data) self.send("error", data_to_send) def _receive_participating(self, data: dict) -> None: is_participating: bool | None = data.get("is_participating") if (is_participating is None): self.send_error(_("Missing is_participating statement.")) return self._room.set_participation() def receive(self, data: dict): if self.is_participating == False: return detail: str | None = data.get("detail") if (detail is None): return match(detail): case "update_particapating": self._receive_participating() case _: print("bozo_send") class TournamentRoomManager: def __init__(self): self._room_list: list[TournamentRoom] = [] def get(self, tournament: TournamentModel) -> TournamentRoom: for room in self._room_list: if room._model is tournament: return room room: TournamentRoom = TournamentRoom(self, tournament) self._room_list.append(room) return room def remove(self, room: TournamentRoom) -> None: self._room_list.remove(room) class TournamentRoom: def __init__(self, room_manager: TournamentRoomManager, tournament: TournamentModel): self._room_manager: TournamentRoomManager = room_manager self._member_list: list[TournamentMember] = [] self._model: TournamentModel = tournament def join(self, socket: TournamentWebConsumer) -> TournamentMember: member: TournamentMember = TournamentMember(socket, self) self._member_list.append(member) return member def leave(self, member: TournamentMember) -> None: # Delete room if nobody connected, no cringe memory leak if (len(self._member_list) == 1): self._room_manager.remove(self) return self._member_list.remove(member) self.set_participation(member, False) def broadcast(self, detail: str, data: dict, excludes: list[TournamentMember] = []) -> None: member_list: list[TournamentMember] = [member for member in self._member_list if member not in excludes] for member in member_list: member.send(detail, data) def get_participants(self) -> list[TournamentMember]: return [member for member in self._member_list if member.is_participating] def set_participation(self, member: TournamentMember, is_participating: bool) -> None: if (self._model.started): return if (member.is_participating == is_participating): return if (is_participating == True): self.broadcast("add_participant", {"profile", ProfileSerializer(member._socket.user.profilemodel).data}) else: self.broadcast("del_participant", {"profile", ProfileSerializer(member._socket.user.profilemodel).data}) member.is_participating = is_participating tournament_manager: TournamentRoomManager = TournamentRoomManager() class TournamentWebConsumer(WebsocketConsumer): def connect(self): self.user: User = self.scope["user"] if (not self.user.is_authenticated): return tournament_id: int = int(self.scope['url_route']['kwargs']['tournament_id']) query: QuerySet = TournamentModel.objects.filter(pk=tournament_id) if (not query.exists()): return tournament: TournamentModel = query[0] self.room = tournament_manager.get(tournament) self.member: TournamentMember = self.room.join(self) self.accept() def receive(self, text_data: str = None, bytes_data: bytes = None): user: User = self.scope["user"] if (user != self.user): return data: dict = json.loads(text_data) self.member.receive(data) def disconnect(self, close_code): self.room.leave(self.member) super().disconnect(close_code) # proutman à encore frappé