Update server.py
Browse files
server.py
CHANGED
|
@@ -5,7 +5,6 @@ from fastapi.responses import HTMLResponse, JSONResponse, FileResponse
|
|
| 5 |
from fastapi.staticfiles import StaticFiles
|
| 6 |
from fastapi.templating import Jinja2Templates
|
| 7 |
import json
|
| 8 |
-
import asyncio
|
| 9 |
import uvicorn
|
| 10 |
from typing import Dict, Set, Optional, Any
|
| 11 |
import logging
|
|
@@ -38,32 +37,16 @@ except FileNotFoundError:
|
|
| 38 |
maps_data = {}
|
| 39 |
|
| 40 |
|
| 41 |
-
#
|
| 42 |
-
STATIC_INDEX_PATH = os.path.join("static", "map.html")
|
| 43 |
-
|
| 44 |
-
@app.get("/", response_class=FileResponse) # <-- Geändert: FileResponse
|
| 45 |
async def read_index(request: Request):
|
| 46 |
-
|
| 47 |
-
if not os.path.exists(STATIC_INDEX_PATH):
|
| 48 |
-
# Fallback auf das Template, falls die statische Datei nicht existiert
|
| 49 |
-
# Du könntest auch einen HTTPException werfen, wenn die Datei obligatorisch ist
|
| 50 |
-
return templates.TemplateResponse("index.html", {"request": request, "maps": maps_data})
|
| 51 |
-
return STATIC_INDEX_PATH # <-- Geändert: Pfad zur Datei
|
| 52 |
-
|
| 53 |
-
@app.get("/map/{normalized_name}", response_class=FileResponse) # <-- Geändert: FileResponse
|
| 54 |
-
async def get_map_by_normalized_name(request: Request, normalized_name: str):
|
| 55 |
-
# Optional: Validierung, ob normalized_name prinzipiell gültig ist
|
| 56 |
-
# map_entry = maps_data.get(normalized_name)
|
| 57 |
-
# if not map_entry and normalized_name != "": # Entferne diese Zeile, da wir immer die SPA servieren
|
| 58 |
-
# raise HTTPException(status_code=404, detail="Map not found") # Entferne diese Zeile
|
| 59 |
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
return STATIC_INDEX_PATH # <-- Geändert: Immer die statische index.html zurückgeben
|
| 67 |
|
| 68 |
|
| 69 |
# Neuer API-Endpunkt für Map-Daten
|
|
@@ -74,7 +57,8 @@ async def get_map_data(map_name: str):
|
|
| 74 |
if not map_entry:
|
| 75 |
raise HTTPException(status_code=404, detail="Map not found")
|
| 76 |
return JSONResponse(content=map_entry)
|
| 77 |
-
|
|
|
|
| 78 |
class ConnectionManager:
|
| 79 |
def __init__(self):
|
| 80 |
self.groups: Dict[str, Set[WebSocket]] = {}
|
|
@@ -96,7 +80,7 @@ class ConnectionManager:
|
|
| 96 |
async def join_group(self, websocket: WebSocket, group_name: str, client_type: str = "web"):
|
| 97 |
"""
|
| 98 |
Client einer Gruppe hinzufügen
|
| 99 |
-
|
| 100 |
Args:
|
| 101 |
websocket: WebSocket-Verbindung
|
| 102 |
group_name: Name der Gruppe
|
|
@@ -112,21 +96,21 @@ class ConnectionManager:
|
|
| 112 |
self.groups[group_name] = set()
|
| 113 |
self.group_leaders[group_name] = websocket # Erster Client ist der Gruppenleiter
|
| 114 |
logger.info(f"Neue Gruppe '{group_name}' erstellt von {client_type}-Client")
|
| 115 |
-
|
| 116 |
self.groups[group_name].add(websocket)
|
| 117 |
self.connections[websocket] = group_name
|
| 118 |
self.client_types[websocket] = client_type # Speichere den Client-Typ
|
| 119 |
-
|
| 120 |
# Prüfe ob dies der erste Client in der Gruppe ist
|
| 121 |
-
is_first_client =
|
| 122 |
client_info = {
|
| 123 |
-
"type": "joined",
|
| 124 |
-
"group": group_name,
|
| 125 |
"client_type": client_type,
|
| 126 |
"is_first": is_first_client,
|
| 127 |
-
"message": f"Erfolgreich Gruppe '{group_name}' beigetreten als {client_type}-Client"
|
| 128 |
}
|
| 129 |
-
|
| 130 |
logger.info(f"Client ({client_type}) joined group '{group_name}' (First: {is_first_client})")
|
| 131 |
return client_info
|
| 132 |
|
|
@@ -156,7 +140,7 @@ class ConnectionManager:
|
|
| 156 |
# Optional: Nachricht an bestimmten Client ausschließen
|
| 157 |
if connection == exclude:
|
| 158 |
continue
|
| 159 |
-
|
| 160 |
try:
|
| 161 |
await connection.send_text(message)
|
| 162 |
self.message_stats["total_sent"] += 1
|
|
@@ -169,31 +153,20 @@ class ConnectionManager:
|
|
| 169 |
self.disconnect(conn)
|
| 170 |
|
| 171 |
def get_stats(self):
|
| 172 |
-
return {
|
| 173 |
-
"active_groups": len(self.groups),
|
| 174 |
-
"total_connections": len(self.connections),
|
| 175 |
-
**self.message_stats
|
| 176 |
-
}
|
| 177 |
|
| 178 |
def get_group_info(self, group_name: str) -> Dict[str, Any]:
|
| 179 |
"""Gibt Informationen über eine Gruppe zurück"""
|
| 180 |
if group_name not in self.groups:
|
| 181 |
return {"group": group_name, "members": 0, "clients": []}
|
| 182 |
-
|
| 183 |
members = []
|
| 184 |
for ws in self.groups[group_name]:
|
| 185 |
client_type = self.client_types.get(ws, "unknown")
|
| 186 |
-
is_leader =
|
| 187 |
-
members.append({
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
})
|
| 191 |
-
|
| 192 |
-
return {
|
| 193 |
-
"group": group_name,
|
| 194 |
-
"members": len(members),
|
| 195 |
-
"clients": members
|
| 196 |
-
}
|
| 197 |
|
| 198 |
|
| 199 |
manager = ConnectionManager()
|
|
@@ -218,19 +191,15 @@ async def websocket_endpoint(websocket: WebSocket):
|
|
| 218 |
join_info = await manager.join_group(websocket, group_name, client_type)
|
| 219 |
# Bestätigungsmessage
|
| 220 |
await websocket.send_text(json.dumps(join_info))
|
| 221 |
-
|
| 222 |
# Benachrichtige andere Gruppenmitglieder über neuen Client
|
| 223 |
notification = {
|
| 224 |
"type": "client_joined",
|
| 225 |
"group": group_name,
|
| 226 |
"client_type": client_type,
|
| 227 |
-
"message": f"Neuer {client_type}-Client ist der Gruppe beigetreten"
|
| 228 |
}
|
| 229 |
-
await manager.broadcast_to_group(
|
| 230 |
-
json.dumps(notification),
|
| 231 |
-
group_name,
|
| 232 |
-
exclude=websocket # Sende nicht an den neu verbundenen Client
|
| 233 |
-
)
|
| 234 |
else:
|
| 235 |
error_msg = {"type": "error", "message": "Missing group name in join request"}
|
| 236 |
await websocket.send_text(json.dumps(error_msg))
|
|
@@ -279,4 +248,4 @@ async def get_group_info(group_name: str):
|
|
| 279 |
|
| 280 |
|
| 281 |
if __name__ == "__main__":
|
| 282 |
-
uvicorn.run(app, host="0.0.0.0", port=8000, log_level="info")
|
|
|
|
| 5 |
from fastapi.staticfiles import StaticFiles
|
| 6 |
from fastapi.templating import Jinja2Templates
|
| 7 |
import json
|
|
|
|
| 8 |
import uvicorn
|
| 9 |
from typing import Dict, Set, Optional, Any
|
| 10 |
import logging
|
|
|
|
| 37 |
maps_data = {}
|
| 38 |
|
| 39 |
|
| 40 |
+
@app.get("/", response_class=FileResponse) # <-- Geändert: FileResponse
|
|
|
|
|
|
|
|
|
|
| 41 |
async def read_index(request: Request):
|
| 42 |
+
return templates.TemplateResponse("map.html", {"request": request, "maps": maps_data})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
|
| 44 |
+
|
| 45 |
+
@app.get("/map/{normalized_name}", response_class=FileResponse) # <-- Geändert: FileResponse
|
| 46 |
+
async def get_map_by_normalized_name(request: Request, normalized_name: str):
|
| 47 |
+
map_entry = maps_data.get(normalized_name)
|
| 48 |
+
filtered_maps = [map_entry] if map_entry else []
|
| 49 |
+
return templates.TemplateResponse("map.html", {"request": request, "maps": filtered_maps})
|
|
|
|
| 50 |
|
| 51 |
|
| 52 |
# Neuer API-Endpunkt für Map-Daten
|
|
|
|
| 57 |
if not map_entry:
|
| 58 |
raise HTTPException(status_code=404, detail="Map not found")
|
| 59 |
return JSONResponse(content=map_entry)
|
| 60 |
+
|
| 61 |
+
|
| 62 |
class ConnectionManager:
|
| 63 |
def __init__(self):
|
| 64 |
self.groups: Dict[str, Set[WebSocket]] = {}
|
|
|
|
| 80 |
async def join_group(self, websocket: WebSocket, group_name: str, client_type: str = "web"):
|
| 81 |
"""
|
| 82 |
Client einer Gruppe hinzufügen
|
| 83 |
+
|
| 84 |
Args:
|
| 85 |
websocket: WebSocket-Verbindung
|
| 86 |
group_name: Name der Gruppe
|
|
|
|
| 96 |
self.groups[group_name] = set()
|
| 97 |
self.group_leaders[group_name] = websocket # Erster Client ist der Gruppenleiter
|
| 98 |
logger.info(f"Neue Gruppe '{group_name}' erstellt von {client_type}-Client")
|
| 99 |
+
|
| 100 |
self.groups[group_name].add(websocket)
|
| 101 |
self.connections[websocket] = group_name
|
| 102 |
self.client_types[websocket] = client_type # Speichere den Client-Typ
|
| 103 |
+
|
| 104 |
# Prüfe ob dies der erste Client in der Gruppe ist
|
| 105 |
+
is_first_client = self.group_leaders.get(group_name) == websocket
|
| 106 |
client_info = {
|
| 107 |
+
"type": "joined",
|
| 108 |
+
"group": group_name,
|
| 109 |
"client_type": client_type,
|
| 110 |
"is_first": is_first_client,
|
| 111 |
+
"message": f"Erfolgreich Gruppe '{group_name}' beigetreten als {client_type}-Client",
|
| 112 |
}
|
| 113 |
+
|
| 114 |
logger.info(f"Client ({client_type}) joined group '{group_name}' (First: {is_first_client})")
|
| 115 |
return client_info
|
| 116 |
|
|
|
|
| 140 |
# Optional: Nachricht an bestimmten Client ausschließen
|
| 141 |
if connection == exclude:
|
| 142 |
continue
|
| 143 |
+
|
| 144 |
try:
|
| 145 |
await connection.send_text(message)
|
| 146 |
self.message_stats["total_sent"] += 1
|
|
|
|
| 153 |
self.disconnect(conn)
|
| 154 |
|
| 155 |
def get_stats(self):
|
| 156 |
+
return {"active_groups": len(self.groups), "total_connections": len(self.connections), **self.message_stats}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 157 |
|
| 158 |
def get_group_info(self, group_name: str) -> Dict[str, Any]:
|
| 159 |
"""Gibt Informationen über eine Gruppe zurück"""
|
| 160 |
if group_name not in self.groups:
|
| 161 |
return {"group": group_name, "members": 0, "clients": []}
|
| 162 |
+
|
| 163 |
members = []
|
| 164 |
for ws in self.groups[group_name]:
|
| 165 |
client_type = self.client_types.get(ws, "unknown")
|
| 166 |
+
is_leader = self.group_leaders.get(group_name) == ws
|
| 167 |
+
members.append({"client_type": client_type, "is_leader": is_leader})
|
| 168 |
+
|
| 169 |
+
return {"group": group_name, "members": len(members), "clients": members}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
|
| 171 |
|
| 172 |
manager = ConnectionManager()
|
|
|
|
| 191 |
join_info = await manager.join_group(websocket, group_name, client_type)
|
| 192 |
# Bestätigungsmessage
|
| 193 |
await websocket.send_text(json.dumps(join_info))
|
| 194 |
+
|
| 195 |
# Benachrichtige andere Gruppenmitglieder über neuen Client
|
| 196 |
notification = {
|
| 197 |
"type": "client_joined",
|
| 198 |
"group": group_name,
|
| 199 |
"client_type": client_type,
|
| 200 |
+
"message": f"Neuer {client_type}-Client ist der Gruppe beigetreten",
|
| 201 |
}
|
| 202 |
+
await manager.broadcast_to_group(json.dumps(notification), group_name, exclude=websocket) # Sende nicht an den neu verbundenen Client
|
|
|
|
|
|
|
|
|
|
|
|
|
| 203 |
else:
|
| 204 |
error_msg = {"type": "error", "message": "Missing group name in join request"}
|
| 205 |
await websocket.send_text(json.dumps(error_msg))
|
|
|
|
| 248 |
|
| 249 |
|
| 250 |
if __name__ == "__main__":
|
| 251 |
+
uvicorn.run(app, host="0.0.0.0", port=8000, log_level="info")
|