from fastapi import WebSocket from typing import List, Dict, Any import json import asyncio from datetime import datetime from models import CreateOrderRequest, Drink class WebSocketManager: def __init__(self): self.active_connections: List[WebSocket] = [] self.db = None # Wird später gesetzt def set_database(self, database): """Setzt die Datenbank-Referenz (Dependency Injection).""" self.db = database async def connect(self, websocket: WebSocket): """Neue WebSocket-Verbindung hinzufügen.""" await websocket.accept() self.active_connections.append(websocket) print(f"WebSocket verbunden. Aktive Verbindungen: {len(self.active_connections)}") def disconnect(self, websocket: WebSocket): """WebSocket-Verbindung entfernen.""" if websocket in self.active_connections: self.active_connections.remove(websocket) print(f"WebSocket getrennt. Aktive Verbindungen: {len(self.active_connections)}") async def broadcast(self, message: Dict[str, Any]): """Nachricht an alle verbundenen Clients senden.""" if not self.active_connections: return # Nachricht als JSON serialisieren message_json = json.dumps(message, default=str) # An alle verbundenen Clients senden disconnected = [] for connection in self.active_connections: try: await connection.send_text(message_json) except Exception as e: print(f"Fehler beim Senden an WebSocket: {e}") disconnected.append(connection) # Getrennte Verbindungen entfernen for connection in disconnected: self.disconnect(connection) async def send_to_client(self, websocket: WebSocket, message: Dict[str, Any]): """Nachricht an einen spezifischen Client senden.""" try: message_json = json.dumps(message, default=str) await websocket.send_text(message_json) except Exception as e: print(f"Fehler beim Senden an WebSocket: {e}") self.disconnect(websocket) async def handle_create_order(self, websocket: WebSocket, data: Dict[str, Any]): """Behandelt eine Bestellungsanfrage über WebSocket.""" try: # Validierung der Anfrage if "drinks" not in data or not data["drinks"]: await self.send_to_client(websocket, { "type": "order_created_response", "success": False, "error": "Mindestens ein Getränk muss bestellt werden", "timestamp": datetime.now().isoformat() }) return # Drinks aus der Anfrage erstellen drinks = [] for drink_data in data["drinks"]: drink = Drink( drink_type=drink_data["drink_type"], mate_type=drink_data["mate_type"], quantity=drink_data["quantity"], notes=drink_data.get("notes", "") ) drinks.append(drink) # Bestellung in der Datenbank erstellen if self.db: order = await self.db.create_order(drinks) # Erfolgsantwort an den Client senden await self.send_to_client(websocket, { "type": "order_created_response", "success": True, "order": order.model_dump(), "timestamp": datetime.now().isoformat() }) else: await self.send_to_client(websocket, { "type": "order_created_response", "success": False, "error": "Datenbank nicht verfügbar", "timestamp": datetime.now().isoformat() }) except Exception as e: print(f"Fehler beim Erstellen der Bestellung über WebSocket: {e}") await self.send_to_client(websocket, { "type": "order_created_response", "success": False, "error": f"Fehler beim Erstellen der Bestellung: {str(e)}", "timestamp": datetime.now().isoformat() }) async def handle_get_all_orders(self, websocket: WebSocket): """Sendet alle Bestellungen an den anfragenden Client.""" try: if self.db: orders = self.db.get_all_orders() await self.send_to_client(websocket, { "type": "all_orders", "orders": [order.model_dump() for order in orders], "timestamp": datetime.now().isoformat() }) else: await self.send_to_client(websocket, { "type": "all_orders", "orders": [], "error": "Datenbank nicht verfügbar", "timestamp": datetime.now().isoformat() }) except Exception as e: print(f"Fehler beim Abrufen aller Bestellungen: {e}") await self.send_to_client(websocket, { "type": "all_orders", "orders": [], "error": f"Fehler beim Abrufen der Bestellungen: {str(e)}", "timestamp": datetime.now().isoformat() }) async def handle_delete_order(self, websocket: WebSocket, data: Dict[str, Any]): """Behandelt eine Bestelllöschung über WebSocket.""" try: # Validierung der Anfrage if "order_id" not in data or not data["order_id"]: await self.send_to_client(websocket, { "type": "order_deleted_response", "success": False, "error": "Order ID ist erforderlich", "timestamp": datetime.now().isoformat() }) return order_id = data["order_id"] # Bestellung in der Datenbank löschen if self.db: success = await self.db.delete_order(order_id) if success: # Erfolgsantwort an den Client senden await self.send_to_client(websocket, { "type": "order_deleted_response", "success": True, "message": f"Bestellung {order_id} wurde erfolgreich gelöscht", "timestamp": datetime.now().isoformat() }) else: await self.send_to_client(websocket, { "type": "order_deleted_response", "success": False, "error": "Bestellung nicht gefunden", "timestamp": datetime.now().isoformat() }) else: await self.send_to_client(websocket, { "type": "order_deleted_response", "success": False, "error": "Datenbank nicht verfügbar", "timestamp": datetime.now().isoformat() }) except Exception as e: print(f"Fehler beim Löschen der Bestellung über WebSocket: {e}") await self.send_to_client(websocket, { "type": "order_deleted_response", "success": False, "error": f"Fehler beim Löschen der Bestellung: {str(e)}", "timestamp": datetime.now().isoformat() }) async def broadcast_order_created(self, order: Dict[str, Any]): """Broadcast für neue Bestellung.""" message = { "type": "order_created", "timestamp": datetime.now().isoformat(), "order": order } await self.broadcast(message) async def broadcast_order_deleted(self, order_id: str): """Broadcast für gelöschte Bestellung.""" message = { "type": "order_deleted", "timestamp": datetime.now().isoformat(), "order_id": order_id } await self.broadcast(message) async def broadcast_all_orders(self, orders: List[Dict[str, Any]]): """Broadcast für alle Bestellungen (z.B. bei initialer Verbindung).""" message = { "type": "all_orders", "timestamp": datetime.now().isoformat(), "orders": orders } await self.broadcast(message) # Globale WebSocket-Manager-Instanz websocket_manager = WebSocketManager()