# chat/consumers.py import json from uuid import uuid4 from channels.generic.websocket import AsyncWebsocketConsumer from channels.db import database_sync_to_async from users.serializers import UserSerializer from .models import Room class RoomConsumer(AsyncWebsocketConsumer): async def connect(self): self.room_id = self.scope['url_route']['kwargs']['room_id'] self.waiter = None self.clientId = str(uuid4()) self.waiter = False self.waiter_code = None self.user = None try: self.room = await self.get_room() await self.accept() await self.send(json.dumps({'type': 'connect', "clientId": self.clientId})) except: await self.close() async def receive(self, text_data): text_data_json = json.loads(text_data) type = text_data_json['data']['type'] if type == "login": participants = await self.get_participants() if self.scope['user'].is_anonymous: nick = text_data_json['data']['nick'] else: nick = self.scope['user'].username if len(nick) == 0: await self.send(json.dumps({'type': 'loginResponse', "error": "USER_INPUT", "description": "Pseudo non valide"})) return if nick in list(map(lambda p: p['nick'], participants)) and self.scope['user'].is_anonymous: await self.send(json.dumps({'type': 'loginResponse', "error": "USER_INPUT", "description": "Pseudo déjà utilisé"})) return elif len(nick) > 30: await self.send(json.dumps({'type': 'loginResponse', "error": "USER_INPUT", "description": "Pseudo trop long"})) return else: if self.room.private == True: waiter = await self.add_waiter_db(nick, self.scope['user'].is_anonymous == False, None if self.scope['user'].is_anonymous else self.scope['user'].id_code) if waiter != None: self.waiter = True self.waiter_code = waiter['code'] await self.send(json.dumps({'type': "waitingRoom", "nick": nick, 'id_code': self.room_id})) await self.channel_layer.group_add(f'waiter__{waiter["code"]}', self.channel_name) await self.channel_layer.group_send(f'owner__{self.room_id}', {"type": "add_waiter", "code": waiter['code'], "nick": waiter['nick'], "status": waiter['status']}) else: await self.send(json.dumps({'type': 'loginResponse', "error": "USER_INPUT", "description": "Pseudo déjà utilisé"})) else: await self.channel_layer.group_add(self.room_id, self.channel_name) if self.scope['user'].is_anonymous: new_participant = await self.add_participant(nick, self.clientId) self.user = new_participant else: new_participant = await self.add_user(self.scope['user'].id_code) self.user = new_participant await self.send(json.dumps({'type': "roomJoined", "clientId": new_participant['clientId'], 'id_code': self.room_id, 'identity': new_participant})) await self.channel_layer.group_send(self.room_id, {'type': 'join.event', "nick": nick, "owner": False, "online": True, "code": ""}) await self.channel_layer.group_send(f'owner__{self.room_id}', {'type': 'join.event', "nick": nick, "owner": False, "online": True, "code": new_participant['code']}) elif type == "acceptParticipant": code = text_data_json['data']['code'] nick = text_data_json['data']['nick'] status = text_data_json['data']['status'] self.waiter = False if status == 'anonymous': new_participant = await self.add_participant(nick, str(uuid4())) else: new_participant = await self.add_user(code) await self.del_waiter_db(code) await self.channel_layer.group_send(f'waiter__{code}', {"type": "accept_room", 'id_code': self.room_id, 'code': new_participant['code']}) elif type == "refusedParticipant": code = text_data_json['data']['code'] await self.del_waiter_db(code) await self.channel_layer.group_send(f'waiter__{code}', {"type": "refused_participant"}) elif type == "logAcceptedWaiter": code = text_data_json['data']['code'] participants = await self.get_participants() if not self.scope['user'].is_anonymous: await self.channel_layer.group_discard(f'waiter__{code}', self.channel_name) await self.channel_layer.group_add(self.room_id, self.channel_name) self.clientId = self.scope['user'].clientId self.user = { 'nick': self.scope['user'].username, 'code': self.scope['user'].id_code, 'clientId':self.scope['user'].clientId, "owner": False} #à continuer dsl self.waiter = False self.waiter_code = None await self.send(json.dumps({'type': "roomJoined", "clientId": self.clientId, 'id_code': self.room_id, 'identity': self.user})) await self.channel_layer.group_send(self.room_id, {"type": "join.event", "nick": self.user['nick'], "owner": False, "online": True, "code": ''}) await self.channel_layer.group_send(f'owner__{self.room_id}', {"type": "join.event", "nick": self.user['nick'], "owner": False, "online": True, "code": self.user['code']}) elif code in list(map(lambda p: p['code'], participants)): participant = list( filter(lambda p: p['code'] == code, participants))[0] await self.channel_layer.group_discard(f'waiter__{code}', self.channel_name) self.clientId = participant['clientId'] await self.channel_layer.group_add(self.room_id, self.channel_name) self.user = participant self.waiter = False self.waiter_code = None await self.send(json.dumps({'type': "roomJoined", "clientId": self.clientId, 'id_code': self.room_id, 'identity': participant})) await self.channel_layer.group_send(self.room_id, {"type": "join.event", "nick": participant['nick'], "owner": False, "online": True, "code": ''}) await self.channel_layer.group_send(f'owner__{self.room_id}', {"type": "join.event", "nick": participant['nick'], "owner": False, "online": True, "code": participant['code']}) elif type == 'relogin': if not self.scope['user'].is_anonymous: userInRoom = await self.userInRoom() if not userInRoom: await self.send(json.dumps({"type": "reloginError"})) else: isOwner = self.scope['user'].clientId == self.room.owner[ 'clientId'] and self.scope['user'].id_code == self.room.owner['code'] self.clientId = self.scope['user'].clientId if isOwner: await self.channel_layer.group_add(f'owner__{self.room_id}', self.channel_name) else: await self.channel_layer.group_add(self.room_id, self.channel_name) self.user = { 'nick': self.scope['user'].username, 'code': self.scope['user'].id_code, 'clientId': self.scope['user'].clientId, "owner": False} await self.connect_participant() await self.channel_layer.group_send(self.room_id, {"type": "reconnect.event", 'nick': self.user['nick']}) await self.channel_layer.group_send(f'owner__{self.room_id}', {"type": "reconnect.event", 'nick': self.user['nick']}) else: code = text_data_json['data']['code'] participants = await self.get_participants() if code in list(map(lambda p: p['code'], participants)): participant = list( filter(lambda p: p['code'] == code, participants))[0] self.clientId = participant['clientId'] if participant['clientId'] == self.room.owner['clientId'] and participant['code'] == self.room.owner['code']: await self.channel_layer.group_add(f'owner__{self.room_id}', self.channel_name) else: await self.channel_layer.group_add(self.room_id, self.channel_name) participant['online'] = True self.user = participant await self.connect_participant() await self.send(json.dumps({'type': "reloged", "clientId": self.clientId, 'id_code': self.room_id, 'identity': participant})) await self.channel_layer.group_send(self.room_id, {"type": "reconnect.event", 'nick': self.user['nick']}) await self.channel_layer.group_send(f'owner__{self.room_id}', {"type": "reconnect.event", 'nick': self.user['nick']}) else: await self.send(json.dumps({"type": "reloginError"})) elif type == "reconnect": client = text_data_json['data']['clientId'] if not self.scope['user'].is_anonymous: userInRoom = await self.userInRoom() if not userInRoom: await self.send(json.dumps({"type": "reconnectError", 'id_code': self.room_id})) else: isOwner = self.scope['user'].clientId == self.room.owner[ 'clientId'] and self.scope['user'].id_code == self.room.owner['code'] if isOwner: await self.channel_layer.group_add(f'owner__{self.room_id}', self.channel_name) else: await self.channel_layer.group_add(self.room_id, self.channel_name) self.user = { 'code': self.scope['user'].id_code, 'nick': self.scope['user'].username, "clientId": self.scope['user'].clientId, 'online': True, 'owner': self.scope['user'].clientId == self.room.owner['clientId'] and self.scope['user'].id_code == self.room.owner['code']} await self.connect_participant() self.clientId = self.scope['user'].clientId await self.send(json.dumps({'type': "reconnected", "clientId": self.scope['user'].clientId, 'id_code': self.room_id, 'identity': self.user})) await self.channel_layer.group_send(self.room_id, {"type": "reconnect.event", 'nick': self.user['nick']}) await self.channel_layer.group_send(f'owner__{self.room_id}', {"type": "reconnect.event", 'nick': self.user['nick']}) else: participants = await self.get_participants() if client in list(map(lambda p: p['clientId'], participants)): self.clientId = client participant = list( filter(lambda p: p['clientId'] == client, participants))[0] if participant['clientId'] == self.room.owner['clientId'] and participant['code'] == self.room.owner['code']: await self.channel_layer.group_add(f'owner__{self.room_id}', self.channel_name) else: await self.channel_layer.group_add(self.room_id, self.channel_name) participant['online'] = True self.user = participant await self.connect_participant() await self.send(json.dumps({'type': "reconnected", "clientId": client, 'id_code': self.room_id, 'identity': participant})) await self.channel_layer.group_send(self.room_id, {"type": "reconnect.event", 'nick': self.user['nick']}) await self.channel_layer.group_send(f'owner__{self.room_id}', {"type": "reconnect.event", 'nick': self.user['nick']}) else: await self.send(json.dumps({"type": "reconnectError", 'id_code': self.room_id})) elif type == 'ban': code = text_data_json['data']["code"] nick = text_data_json['data']["nick"] status = text_data_json['data']["status"] if status == 'anonymous': await self.del_participant(code) else: await self.del_user(code) await self.channel_layer.group_send(self.room_id, {'type': "ban_participant", "code": code, "nick": nick}) await self.channel_layer.group_send(f'owner__{self.room_id}', {'type': "ban_participant", "code": code, "nick": nick}) elif type == 'leave': code = text_data_json['data']["code"] nick = text_data_json['data']["nick"] clientId = text_data_json['data']["clientId"] status = 'anonymous' if len(code) == 6 else 'user' if status == 'anonymous': participants = await self.get_participants() participant = [p for p in participants if p['code'] == code] if len(participant) == 0: pass else: if clientId == participant[0]['clientId']: await self.del_participant(code) await self.channel_layer.group_send(self.room_id, {'type': "ban_participant", "code": code, "nick": nick}) await self.channel_layer.group_send(f'owner__{self.room_id}', {'type': "ban_participant", "code": code, "nick": nick}) else: user = await self.get_user(code) if self.scope['user'] == user: await self.del_user(code) await self.channel_layer.group_send(self.room_id, {'type': "ban_participant", "code": code, "nick": nick}) await self.channel_layer.group_send(f'owner__{self.room_id}', {'type': "ban_participant", "code": code, "nick": nick}) async def join_event(self, event): await self.send(json.dumps({'type': 'joined', 'nick': event['nick'], "owner": event['owner'], "online": event['online'], "code": event["code"]})) async def accept_room(self, event): await self.send(json.dumps({'type': 'accept_room', 'id_code': self.room_id, 'code': event["code"]})) async def accept_waiter(self, event): await self.send(json.dumps({'type': 'joined', 'nick': event['nick'], "owner": event['owner'], "online": event['online'], "code": event["code"]})) async def add_waiter(self, event): await self.send(json.dumps({'type': 'add_waiter', 'nick': event['nick'], "code": event["code"], "status": event['status']})) async def new_parcours(self, event): await self.send(json.dumps({'type': "add_parcours", "parcours": event['parcours']})) async def refused_participant(self, event): await self.send(json.dumps({"type": "refused"})) async def ban_participant(self, event): await self.send(json.dumps({"type": "banned", 'nick': event['nick'], "code": event["code"]})) @database_sync_to_async def get_participants(self): return Room.objects.filter(id_code=self.room_id)[0].anonymousMembers @database_sync_to_async def get_users(self): return [UserSerializer(u).data for u in Room.objects.filter(id_code=self.room_id)[0].userMembers.all()] @database_sync_to_async def get_user(self, code): return Room.objects.filter(id_code=self.room_id)[0].userMembers.get(id_code = code) @database_sync_to_async def get_room(self): return Room.objects.filter(id_code=self.room_id)[0] @database_sync_to_async def add_participant(self, new, id): return Room.objects.add_participant(self.room_id, new, id, False, True) @database_sync_to_async def add_user(self, code): return Room.objects.add_user(self.room_id, code, False, True) @database_sync_to_async def del_participant(self, code): return Room.objects.del_participant(self.room_id, code) @database_sync_to_async def del_user(self, code): return Room.objects.del_user(self.room_id, code) @database_sync_to_async def add_waiter_db(self, new, isUser, code): return Room.objects.add_waiter(self.room_id, new, isUser, code) @database_sync_to_async def del_waiter_db(self, code): return Room.objects.del_waiter(self.room_id, code) @database_sync_to_async def disconnect_participant(self): if self.scope['user'].is_anonymous: return Room.objects.disconnect(self.room_id, self.user['code']) else: return Room.objects.disconnect(self.room_id, self.scope['user'].id_code) @database_sync_to_async def connect_participant(self): return Room.objects.connect(self.room_id, self.user['code']) @database_sync_to_async def userInRoom(self): if self.scope['user'].is_anonymous: return None return len(self.scope['user'].room_set.filter( id_code=self.room.id_code)) != 0 async def disconnect(self, close_code): if self.waiter == False and self.user != None: await self.disconnect_participant() await self.channel_layer.group_discard(self.room_id, self.channel_name) await self.channel_layer.group_send(self.room_id, {"type": "disconnect.event", "nick": self.user['nick']}) await self.channel_layer.group_send(f'owner__{self.room_id}', {"type": "disconnect.event", "nick": self.user['nick']}) elif self.waiter == True and self.waiter_code != None: await self.del_waiter_db(self.waiter_code) await self.channel_layer.group_send(f'owner__{self.room_id}', {'type': "del_waiter", "code": self.waiter_code}) await self.channel_layer.group_discard(f'waiter__{self.waiter_code}', self.channel_name) async def disconnect_event(self, event): await self.send(json.dumps({'type': 'disconnect_participant', "nick": event['nick']})) async def room_deleted(self, event): await self.send(json.dumps({'type': 'room_deleted'})) async def reconnect_event(self, event): await self.send(json.dumps({'type': 'reconnect_participant', "nick": event['nick']})) async def del_waiter(self, event): await self.send(json.dumps({"type": 'del_waiter', "code": event['code']})) async def challenge_parcours(self, event): await self.send(json.dumps({**event})) async def delete_parcours(self, event): await self.send(json.dumps({**event})) async def edit_parcours(self, event): await self.send(json.dumps({**event}))