mirror of
https://github.com/AudebertAdrien/ft_transcendence.git
synced 2026-02-04 03:30:26 +01:00
380 lines
15 KiB
Python
380 lines
15 KiB
Python
import json
|
|
from channels.generic.websocket import AsyncWebsocketConsumer
|
|
from asgiref.sync import sync_to_async
|
|
from django.contrib.auth.models import User
|
|
from channels.db import database_sync_to_async
|
|
from .matchmaking import match_maker
|
|
from .tournament import tournament_match_maker
|
|
import logging
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
class GameConsumer(AsyncWebsocketConsumer):
|
|
async def connect(self):
|
|
try:
|
|
await self.accept()
|
|
self.game = None
|
|
logger.info("User connected via WebSocket")
|
|
except Exception as e:
|
|
logger.error(f"Error during WebSocket connection: {str(e)}")
|
|
|
|
async def receive(self, text_data):
|
|
try:
|
|
logger.debug(f"Received data: {text_data}")
|
|
data = json.loads(text_data)
|
|
message_type = data.get('type')
|
|
|
|
if message_type == 'authenticate':
|
|
await self.authenticate(data.get('token'))
|
|
elif message_type == 'authenticate2':
|
|
await self.authenticate2(data.get('token_1'), data.get('token_2'))
|
|
elif message_type == 'authenticate3':
|
|
await self.authenticate3(data.get('token'))
|
|
elif message_type == 'key_press':
|
|
if self.game:
|
|
await self.game.handle_key_press(self, data.get('key'))
|
|
else:
|
|
await match_maker.handle_key_press(self, data.get('key'))
|
|
else:
|
|
logger.warning(f"Received unknown message type: {message_type}")
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': 'Unknown message type'}))
|
|
except json.JSONDecodeError as e:
|
|
logger.error(f"JSON decode error: {str(e)} - Data received: {text_data}")
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': 'Invalid JSON format'}))
|
|
except Exception as e:
|
|
logger.error(f"Error in WebSocket receive: {str(e)}")
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': 'Internal server error'}))
|
|
|
|
async def authenticate(self, token):
|
|
if not token:
|
|
logger.error("Token is None, authentication cannot proceed")
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': 'Token is missing'}))
|
|
return
|
|
try:
|
|
user = await self.get_user_from_token(token)
|
|
if user:
|
|
self.user = user
|
|
await self.send(text_data=json.dumps({'type': 'authenticated'}))
|
|
logger.info(f"User {self.user} authenticated")
|
|
await self.join_waiting_room()
|
|
else:
|
|
logger.warning(f"Authentication failed for token: {token}")
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': 'Authentication failed'}))
|
|
except Exception as e:
|
|
logger.error(f"Error during authentication: {str(e)}")
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': 'Internal server error'}))
|
|
|
|
async def authenticate2(self, token_1, token_2):
|
|
try:
|
|
user = await self.get_user_from_token(token_1)
|
|
if user:
|
|
self.user = user
|
|
await self.send(text_data=json.dumps({'type': 'authenticated'}))
|
|
logger.info(f"User {self.user} authenticated with token_1")
|
|
|
|
user2 = await self.get_user_from_token2(token_2)
|
|
if user2:
|
|
self.user2 = user2
|
|
await self.send(text_data=json.dumps({'type': 'authenticated'}))
|
|
logger.info(f"User {self.user2} authenticated with token_2")
|
|
await match_maker.create_game(self, None, True)
|
|
else:
|
|
logger.warning(f"Authentication failed for token_2: {token_2}")
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': 'Authentication failed for user 2'}))
|
|
else:
|
|
logger.warning(f"Authentication failed for token_1: {token_1}")
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': 'Authentication failed for user 1'}))
|
|
except Exception as e:
|
|
logger.error(f"Error during dual authentication: {str(e)}")
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': 'Internal server error'}))
|
|
|
|
async def authenticate3(self, token):
|
|
try:
|
|
user = await self.get_user_from_token(token)
|
|
if user:
|
|
self.user = user
|
|
await self.send(text_data=json.dumps({'type': 'authenticated'}))
|
|
logger.info(f"User {self.user} authenticated for tournament")
|
|
await self.join_tournament_waiting_room()
|
|
else:
|
|
logger.warning(f"Authentication failed for token: {token}")
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': 'Authentication failed'}))
|
|
except Exception as e:
|
|
logger.error(f"Error during tournament authentication: {str(e)}")
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': 'Internal server error'}))
|
|
|
|
@database_sync_to_async
|
|
def get_user_from_token(self, token):
|
|
try:
|
|
user = User.objects.filter(auth_token=token).first()
|
|
logger.debug(f"User found: {user} for token: {token}")
|
|
return user
|
|
except User.DoesNotExist:
|
|
logger.warning(f"User not found for token: {token}")
|
|
return None
|
|
|
|
@database_sync_to_async
|
|
def get_user_from_token2(self, token):
|
|
try:
|
|
user2 = User.objects.filter(auth_token=token).first()
|
|
logger.debug(f"User2 found: {user2} for token: {token}")
|
|
return user2
|
|
except User.DoesNotExist:
|
|
logger.warning(f"User not found for token_2: {token}")
|
|
return None
|
|
|
|
async def join_waiting_room(self):
|
|
logger.info("Joining waiting room")
|
|
await self.send(text_data=json.dumps({'type': 'waiting_room'}))
|
|
await match_maker.add_player(self)
|
|
|
|
async def join_tournament_waiting_room(self):
|
|
logger.info("Joining tournament waiting room")
|
|
await tournament_match_maker.add_player(self)
|
|
|
|
async def disconnect(self, close_code):
|
|
try:
|
|
if self.game:
|
|
await self.game.end_game(disconnected_player=self)
|
|
await match_maker.remove_player(self)
|
|
await tournament_match_maker.remove_player(self)
|
|
logger.info(f"User {self.user.username if hasattr(self, 'user') else 'Unknown'} disconnected")
|
|
except Exception as e:
|
|
logger.error(f"Error during WebSocket disconnection: {str(e)}")
|
|
|
|
async def set_game(self, game):
|
|
logger.info(f"Setting game: {game}")
|
|
self.game = game
|
|
###############################CHAT############################################
|
|
class ChatConsumer(AsyncWebsocketConsumer):
|
|
groups = {}
|
|
|
|
async def connect(self):
|
|
try:
|
|
# Récupérer le nom de la room
|
|
self.room_group_name = self.scope['url_route']['kwargs']['room_name']
|
|
|
|
# Accepter la connexion WebSocket
|
|
await self.accept()
|
|
|
|
logger.info(f"Connexion au WebSocket de chat dans la room {self.room_group_name}")
|
|
|
|
# Ajouter l'utilisateur au groupe en mémoire
|
|
if self.room_group_name not in self.groups:
|
|
self.groups[self.room_group_name] = []
|
|
self.groups[self.room_group_name].append(self.channel_name)
|
|
|
|
logger.info(f"User {self.channel_name} added to group {self.room_group_name}")
|
|
|
|
except Exception as e:
|
|
logger.error(f"Erreur lors de la connexion WebSocket: {str(e)}")
|
|
|
|
|
|
async def disconnect(self, close_code):
|
|
try:
|
|
# Retirer l'utilisateur du groupe en mémoire
|
|
if self.room_group_name in self.groups:
|
|
self.groups[self.room_group_name].remove(self.channel_name)
|
|
if not self.groups[self.room_group_name]:
|
|
del self.groups[self.room_group_name]
|
|
|
|
await self.send_group_message(
|
|
self.room_group_name,
|
|
{
|
|
'type': 'chat_message',
|
|
'message': f'{self.user.username if hasattr(self, "user") else "Unknown"} a quitté le chat',
|
|
'username': self.user.username if hasattr(self, "user") else "Unknown",
|
|
'room': self.room_group_name
|
|
}
|
|
)
|
|
logger.info(f"{self.user.username if hasattr(self, 'user') else 'Unknown'} déconnecté du WebSocket de chat dans la room {self.room_group_name}")
|
|
except Exception as e:
|
|
logger.error(f"Erreur lors de la déconnexion WebSocket du chat: {str(e)}")
|
|
|
|
async def receive(self, text_data):
|
|
try:
|
|
data = json.loads(text_data)
|
|
message_type = data.get('type')
|
|
username = data.get('username').strip().lower() # Normalisation du nom d'utilisateur
|
|
|
|
# Log pour vérifier que le username est bien reçu
|
|
logger.info(f"Message reçu avec username: {username}")
|
|
if not username:
|
|
logger.error(f"Username missing in message: {data}")
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': 'Username is missing'}))
|
|
return
|
|
|
|
# Gestion des types de messages
|
|
if message_type == 'authenticate':
|
|
await self.authenticate(data.get('token'), username)
|
|
|
|
elif message_type == 'chat_message':
|
|
if 'message' not in data:
|
|
logger.error(f"Format de message incorrect : {data}")
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': 'Format de message incorrect'}))
|
|
return
|
|
|
|
message = data['message']
|
|
|
|
# Envoyer le message à tous les autres utilisateurs de la room
|
|
await self.send_group_message(
|
|
self.room_group_name,
|
|
{
|
|
'type': 'chat_message',
|
|
'message': message,
|
|
'username': username,
|
|
'room': self.room_group_name
|
|
}
|
|
)
|
|
|
|
# Gestion de la commande /b pour bloquer un utilisateur
|
|
elif message_type == 'block_user':
|
|
target_user = data.get('target_user').strip().lower()
|
|
if target_user == username:
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': 'You cannot block yourself'}))
|
|
else:
|
|
await self.handle_block_user(data)
|
|
|
|
# Gestion de la commande /i pour inviter un utilisateur
|
|
elif message_type == 'invite_user':
|
|
target_user = data.get('target_user').strip().lower()
|
|
if target_user == username:
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': 'You cannot invite yourself'}))
|
|
else:
|
|
await self.handle_invite_user(data)
|
|
|
|
else:
|
|
logger.warning(f"Unhandled message type: {message_type}")
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': 'Unhandled message type'}))
|
|
|
|
except json.JSONDecodeError as e:
|
|
logger.error(f"Erreur de décodage JSON : {str(e)} - Données reçues : {text_data}")
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': 'Format JSON invalide'}))
|
|
except Exception as e:
|
|
logger.error(f"Erreur lors de la réception du message du chat: {str(e)}")
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': 'Erreur interne du serveur'}))
|
|
|
|
async def handle_block_user(self, data):
|
|
username = data['username'].strip().lower() # Normalisation du nom d'utilisateur
|
|
target_user = data['target_user'].strip().lower()
|
|
|
|
# Utiliser self.room_group_name pour vérifier que l'utilisateur ciblé est bien dans la bonne room
|
|
if target_user not in self.groups.get(self.room_group_name, []):
|
|
logger.error(f"Target user {target_user} does not exist in room {self.room_group_name}")
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': f'Target user {target_user} not found in room {self.room_group_name}'}))
|
|
return
|
|
|
|
logger.info(f"Block request: {username} wants to block {target_user} in room {self.room_group_name}")
|
|
|
|
if target_user == username:
|
|
logger.warning(f"Block attempt failed: {username} tried to block themselves")
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': 'You cannot block yourself'}))
|
|
else:
|
|
logger.info(f"{username} successfully blocked {target_user}")
|
|
await self.send(text_data=json.dumps({'type': 'success', 'message': f'You have blocked {target_user} in room {self.room_group_name}'}))
|
|
|
|
async def handle_invite_user(self, data):
|
|
username = data['username'].strip().lower()
|
|
target_user = data['target_user'].strip().lower()
|
|
|
|
# Utiliser self.room_group_name pour inviter l'utilisateur dans la room active
|
|
room = self.room_group_name
|
|
|
|
# Vérification que le joueur à inviter est dans la room
|
|
if target_user not in self.groups.get(room, []):
|
|
logger.error(f"Target user {target_user} does not exist in room {room}")
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': f'Target user {target_user} not found in room {room}'}))
|
|
return
|
|
|
|
logger.info(f"Invitation request: {username} wants to invite {target_user} to a quick match in room {room}")
|
|
|
|
if target_user == username:
|
|
logger.warning(f"Invite attempt failed: {username} tried to invite themselves")
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': 'You cannot invite yourself'}))
|
|
else:
|
|
logger.info(f"{username} successfully sent an invitation to {target_user} in room {room}")
|
|
await self.send_group_message(room, {
|
|
'type': 'invite',
|
|
'message': f'{username} invited {target_user} to a quick match',
|
|
'username': username,
|
|
'target_user': target_user
|
|
})
|
|
await self.send(text_data=json.dumps({'type': 'success', 'message': f'Invitation sent to {target_user} in room {room}'}))
|
|
|
|
|
|
async def authenticate(self, token, username):
|
|
if not token:
|
|
logger.error("Token is None, authentication cannot proceed")
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': 'Token is missing'}))
|
|
return
|
|
try:
|
|
user = await self.get_user_from_token(token)
|
|
if user:
|
|
self.user = user
|
|
logger.info(f"User {username} authenticated successfully with token: {token}")
|
|
|
|
# Envoyer un message d'authentification réussie au client
|
|
await self.send(text_data=json.dumps({'type': 'authenticated', 'username': username}))
|
|
|
|
# Envoyer le message de bienvenue après l'authentification réussie
|
|
await self.send_group_message(
|
|
self.room_group_name,
|
|
{
|
|
'username': username,
|
|
'room': self.room_group_name,
|
|
'type': 'chat_message',
|
|
'message': f' a rejoint le chat {self.room_group_name}',
|
|
}
|
|
)
|
|
else:
|
|
logger.warning(f"Authentication failed for token: {token}")
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': 'Authentication failed'}))
|
|
except Exception as e:
|
|
logger.error(f"Error during authentication: {str(e)}")
|
|
await self.send(text_data=json.dumps({'type': 'error', 'message': 'Internal server error'}))
|
|
|
|
@sync_to_async
|
|
def get_user_from_token(self, token):
|
|
try:
|
|
user = User.objects.filter(auth_token=token).first()
|
|
logger.debug(f"User found: {user} for token: {token}")
|
|
return user
|
|
except User.DoesNotExist:
|
|
logger.warning(f"User not found for token: {token}")
|
|
return None
|
|
|
|
async def send_group_message(self, group_name, message):
|
|
# Utilisation de self.room_group_name pour s'assurer que la bonne room est utilisée
|
|
group_name = self.room_group_name # Utilisation explicite de self.room_group_name
|
|
|
|
if group_name in self.groups:
|
|
logger.debug(f"Sending message to group {group_name}: {message}")
|
|
for channel_name in self.groups[group_name]:
|
|
try:
|
|
await self.channel_layer.send(channel_name, {
|
|
'type': 'chat_message',
|
|
'message': message['message'],
|
|
'username': message['username'],
|
|
'room': message['room']
|
|
})
|
|
logger.debug(f"Message sent to {channel_name} in room {message['room']}: {message}")
|
|
except Exception as e:
|
|
logger.error(f"Failed to send message to {channel_name} in room {group_name}: {str(e)}")
|
|
else:
|
|
logger.error(f"Group {group_name} does not exist, unable to send message")
|
|
|
|
async def chat_message(self, event):
|
|
message = event['message']
|
|
username = event.get('username', 'Anonyme')
|
|
room = event.get('room', 'unknown')
|
|
|
|
# Log pour vérifier le username avant envoi
|
|
logger.info(f"Sending chat message from username: {username} in room: {room}")
|
|
|
|
# Envoyer le message au WebSocket
|
|
await self.send(text_data=json.dumps({
|
|
'type': 'chat_message',
|
|
'message': f'{username}: {message}',
|
|
'room': room
|
|
}))
|