oedb-backend/wsgi_websocket.py

195 lines
7.6 KiB
Python
Raw Normal View History

2025-09-26 11:57:54 +02:00
#!/usr/bin/env python3
"""
Configuration uWSGI pour l'intégration des WebSockets avec OEDB
"""
import os
import sys
import json
import time
import asyncio
from oedb.utils.logging import logger
# Import l'application Falcon principale
sys.path.insert(0, os.path.dirname(__file__))
from backend import app
# Import le gestionnaire WebSocket
from oedb.resources.demo.websocket import WebSocketManager
# Créer une instance du gestionnaire WebSocket
ws_manager = WebSocketManager()
# Gestionnaire de WebSocket pour uWSGI
def websocket_handler(environ, start_response):
"""Gestionnaire pour les connexions WebSocket."""
path = environ.get('PATH_INFO', '')
# Vérifier si c'est une requête WebSocket et qu'elle est sur le bon chemin
if path == '/ws' and environ.get('HTTP_UPGRADE', '').lower() == 'websocket':
try:
# Importer uwsgi ici car il n'est disponible qu'à l'exécution dans l'environnement uWSGI
import uwsgi
# Passer la requête au gestionnaire de WebSocket uWSGI
uwsgi.websocket_handshake()
logger.info(f"Nouvelle connexion WebSocket établie")
client_id = id(environ)
# Simuler la fonction handle_connection pour ce client
try:
# Ajouter le client à la liste
with ws_manager.lock:
ws_manager.clients[client_id] = {
'websocket': environ, # Utiliser environ comme proxy
'username': None,
'position': None,
'last_seen': time.time(),
'show_only_to_friends': False,
}
# Envoyer la liste des utilisateurs connectés
users_list = []
with ws_manager.lock:
for client_info in ws_manager.clients.values():
if client_info.get('username'):
users_list.append({
'username': client_info['username'],
'timestamp': time.time()
})
# Envoyer la liste des utilisateurs
uwsgi.websocket_send(json.dumps({
'type': 'users',
'users': users_list
}).encode('utf-8'))
# Boucle de traitement des messages
while True:
msg = uwsgi.websocket_recv()
data = json.loads(msg.decode('utf-8'))
message_type = data.get('type')
if message_type == 'position':
# Traiter la mise à jour de position
username = data.get('username')
position = data.get('position')
timestamp = data.get('timestamp')
show_only_to_friends = data.get('showOnlyToFriends', False)
# Mettre à jour les informations du client
with ws_manager.lock:
if client_id in ws_manager.clients:
ws_manager.clients[client_id]['username'] = username
ws_manager.clients[client_id]['position'] = position
ws_manager.clients[client_id]['last_seen'] = time.time()
ws_manager.clients[client_id]['show_only_to_friends'] = show_only_to_friends
# Mettre à jour dans le dictionnaire des positions
ws_manager.positions[username] = {
'position': position,
'timestamp': timestamp,
'show_only_to_friends': show_only_to_friends
}
# Diffuser à tous les autres clients
broadcast_position(username, position, timestamp, show_only_to_friends)
elif message_type in ['pouet', 'friendRequest']:
# Rediriger ces messages vers les destinataires
handle_direct_message(data, message_type)
except Exception as e:
logger.error(f"Erreur WebSocket: {e}")
finally:
# Supprimer le client de la liste
with ws_manager.lock:
if client_id in ws_manager.clients:
username = ws_manager.clients[client_id].get('username')
if username and username in ws_manager.positions:
del ws_manager.positions[username]
del ws_manager.clients[client_id]
except Exception as e:
logger.error(f"Erreur de connexion WebSocket: {e}")
return ['500 Internal Server Error', [], [b'WebSocket Error']]
# Si ce n'est pas une requête WebSocket, passer à l'application WSGI
return app(environ, start_response)
# Fonctions utilitaires pour les WebSockets uWSGI
def broadcast_position(username, position, timestamp, show_only_to_friends):
"""Diffuse la position d'un utilisateur à tous les autres utilisateurs."""
import uwsgi
message = json.dumps({
'type': 'position',
'username': username,
'position': position,
'timestamp': timestamp,
'showOnlyToFriends': show_only_to_friends
}).encode('utf-8')
with ws_manager.lock:
for client_id, client_info in ws_manager.clients.items():
# Ne pas envoyer à l'utilisateur lui-même
if client_info.get('username') == username:
continue
try:
# Dans uWSGI, nous devons utiliser environ pour identifier le socket
if 'websocket' in client_info:
uwsgi.websocket_send(message)
except Exception as e:
logger.error(f"Erreur d'envoi de broadcast de position: {e}")
def handle_direct_message(data, message_type):
"""Traite un message direct (pouet ou demande d'ami)."""
import uwsgi
from_user = data.get('from')
to_user = data.get('to')
if not from_user or not to_user:
return
# Trouver le client destinataire
recipient_client_id = None
with ws_manager.lock:
for client_id, client_info in ws_manager.clients.items():
if client_info.get('username') == to_user:
recipient_client_id = client_id
break
if recipient_client_id and recipient_client_id in ws_manager.clients:
# Préparer le message selon le type
if message_type == 'pouet':
msg = json.dumps({
'type': 'pouet',
'from': from_user,
'timestamp': data.get('timestamp')
}).encode('utf-8')
logger.info(f"Pouet pouet envoyé de {from_user} à {to_user}")
elif message_type == 'friendRequest':
msg = json.dumps({
'type': 'friendRequest',
'from': from_user,
'timestamp': data.get('timestamp')
}).encode('utf-8')
logger.info(f"Demande d'ami envoyée de {from_user} à {to_user}")
# Envoyer le message
try:
uwsgi.websocket_send(msg)
except Exception as e:
logger.error(f"Erreur d'envoi de message direct: {e}")
# Appliquer le patch au démarrage
patch_websocket_manager()
# Application WSGI pour uWSGI
application = websocket_handler
# Remarque: Pour utiliser ce fichier, démarrez uWSGI avec:
# uwsgi --http :8080 --http-websockets --wsgi-file wsgi_websocket.py --async 100 --ugreen