tschunkorder/backend/main.py

138 lines
No EOL
4.5 KiB
Python

from fastapi import FastAPI, HTTPException, WebSocket, WebSocketDisconnect, APIRouter
from typing import List
from models import CreateOrderRequest, Order, DrinkType, MateType
from database import db
from websocket_manager import websocket_manager
import json
app = FastAPI(
title="Tschunk Order API",
description="Eine RESTful API für Tschunk-Bestellungen mit WebSocket-Unterstützung",
version="1.0.0"
)
# API Router mit /api Prefix
api_router = APIRouter(prefix="/api")
# Datenbank-Referenz im WebSocketManager setzen
websocket_manager.set_database(db)
@app.websocket("/api/ws")
async def websocket_endpoint(websocket: WebSocket):
"""
WebSocket-Endpunkt für Echtzeit-Updates der Bestellungen.
Clients erhalten automatisch Updates bei:
- Neuen Bestellungen
- Gelöschten Bestellungen
Nachrichten-Formate:
- order_created: {"type": "order_created", "order": {...}}
- order_deleted: {"type": "order_deleted", "order_id": "..."}
- all_orders: {"type": "all_orders", "orders": [...]}
- create_order: {"type": "create_order", "drinks": [...]}
- get_all_orders: {"type": "get_all_orders"}
- delete_order: {"type": "delete_order", "order_id": "..."}
"""
await websocket_manager.connect(websocket)
try:
# Sende alle aktuellen Bestellungen beim Verbinden
all_orders = [order.model_dump() for order in db.get_all_orders()]
await websocket_manager.broadcast_all_orders(all_orders)
# Halte die Verbindung aufrecht und warte auf Nachrichten
while True:
# Warte auf Nachrichten vom Client
data = await websocket.receive_text()
try:
# Versuche JSON zu parsen
message = json.loads(data)
message_type = message.get("type")
if message_type == "ping":
await websocket.send_text("pong")
elif message_type == "create_order":
await websocket_manager.handle_create_order(websocket, message)
elif message_type == "get_all_orders":
await websocket_manager.handle_get_all_orders(websocket)
elif message_type == "delete_order":
await websocket_manager.handle_delete_order(websocket, message)
else:
print(f"Unbekannte Nachrichtenart: {message_type}")
except json.JSONDecodeError:
# Fallback für einfache Textnachrichten (z.B. "ping")
if data == "ping":
await websocket.send_text("pong")
else:
print(f"Ungültige JSON-Nachricht: {data}")
except WebSocketDisconnect:
websocket_manager.disconnect(websocket)
except Exception as e:
print(f"WebSocket-Fehler: {e}")
websocket_manager.disconnect(websocket)
@api_router.post("/orders", response_model=Order, status_code=201)
async def create_order(order_request: CreateOrderRequest):
"""
Erstellt eine neue Bestellung.
- **drinks**: Liste der Getränke mit Typ und Mate-Sorte
Alle verbundenen WebSocket-Clients erhalten automatisch ein Update.
"""
if not order_request.drinks:
raise HTTPException(status_code=400, detail="Mindestens ein Getränk muss bestellt werden")
order = await db.create_order(order_request.drinks)
return order
@api_router.get("/orders", response_model=List[Order])
async def get_all_orders():
"""
Gibt alle Bestellungen zurück.
"""
orders = db.get_all_orders()
return orders
@api_router.delete("/orders/{order_id}")
async def delete_order(order_id: str):
"""
Löscht eine spezifische Bestellung.
- **order_id**: ID der zu löschenden Bestellung
Alle verbundenen WebSocket-Clients erhalten automatisch ein Update.
"""
success = await db.delete_order(order_id)
if not success:
raise HTTPException(status_code=404, detail="Bestellung nicht gefunden")
return {"message": f"Bestellung {order_id} wurde erfolgreich gelöscht"}
@api_router.get("/drinks")
async def get_available_drinks():
"""
Gibt alle verfügbaren Getränketypen zurück.
"""
return {
"drink_types": [drink.value for drink in DrinkType],
"mate_types": [mate.value for mate in MateType]
}
# API Router zur App hinzufügen
app.include_router(api_router)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)