Sebastiankay commited on
Commit
88363ea
·
verified ·
1 Parent(s): 4989987

Update server.py

Browse files
Files changed (1) hide show
  1. server.py +108 -11
server.py CHANGED
@@ -1,12 +1,12 @@
1
- from fastapi import FastAPI, Request, WebSocket, WebSocketDisconnect, status
2
  from fastapi.middleware.cors import CORSMiddleware
3
- from fastapi.responses import HTMLResponse
4
  from fastapi.staticfiles import StaticFiles
5
  from fastapi.templating import Jinja2Templates
6
  import json
7
  import asyncio
8
  import uvicorn
9
- from typing import Dict, Set
10
  import logging
11
 
12
  # Logging konfigurieren
@@ -49,11 +49,23 @@ async def get_map_by_normalized_name(request: Request, normalized_name: str):
49
  return templates.TemplateResponse("map.html", {"request": request, "maps": filtered_maps})
50
 
51
 
 
 
 
 
 
 
 
 
 
 
52
  class ConnectionManager:
53
  def __init__(self):
54
  self.groups: Dict[str, Set[WebSocket]] = {}
55
  self.connections: Dict[WebSocket, str] = {}
 
56
  self.message_stats = {"total_sent": 0, "total_received": 0}
 
57
 
58
  async def connect(self, websocket: WebSocket):
59
  await websocket.accept()
@@ -65,7 +77,15 @@ class ConnectionManager:
65
  self.remove_from_group(websocket, group_name)
66
  logger.info(f"Client disconnected from group '{group_name}'")
67
 
68
- async def join_group(self, websocket: WebSocket, group_name: str):
 
 
 
 
 
 
 
 
69
  # Remove from previous group if exists
70
  if websocket in self.connections:
71
  old_group = self.connections[websocket]
@@ -74,24 +94,53 @@ class ConnectionManager:
74
  # Add to new group
75
  if group_name not in self.groups:
76
  self.groups[group_name] = set()
 
 
 
77
  self.groups[group_name].add(websocket)
78
  self.connections[websocket] = group_name
79
- logger.info(f"Client joined group '{group_name}' (Total groups: {len(self.groups)})")
 
 
 
 
 
 
 
 
 
 
 
 
 
80
 
81
  def remove_from_group(self, websocket: WebSocket, group_name: str):
82
  if group_name in self.groups and websocket in self.groups[group_name]:
83
  self.groups[group_name].remove(websocket)
84
- if not self.groups[group_name]: # Leere Gruppen entfernen
 
 
 
 
 
85
  del self.groups[group_name]
 
 
86
  logger.info(f"Group '{group_name}' deleted (no members)")
87
 
88
  if websocket in self.connections:
89
  del self.connections[websocket]
 
 
90
 
91
- async def broadcast_to_group(self, message: str, group_name: str):
92
  if group_name in self.groups:
93
  disconnected = set()
94
  for connection in self.groups[group_name].copy(): # Kopie für sichere Iteration
 
 
 
 
95
  try:
96
  await connection.send_text(message)
97
  self.message_stats["total_sent"] += 1
@@ -104,7 +153,31 @@ class ConnectionManager:
104
  self.disconnect(conn)
105
 
106
  def get_stats(self):
107
- return {"active_groups": len(self.groups), "total_connections": len(self.connections), **self.message_stats}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
 
109
 
110
  manager = ConnectionManager()
@@ -124,10 +197,24 @@ async def websocket_endpoint(websocket: WebSocket):
124
  # Handle join messages
125
  if message.get("type") == "join":
126
  group_name = message.get("group")
 
127
  if group_name:
128
- await manager.join_group(websocket, group_name)
129
  # Bestätigungsmessage
130
- await websocket.send_text(json.dumps({"type": "joined", "group": group_name, "message": f"Erfolgreich Gruppe '{group_name}' beigetreten"}))
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  else:
132
  error_msg = {"type": "error", "message": "Missing group name in join request"}
133
  await websocket.send_text(json.dumps(error_msg))
@@ -165,5 +252,15 @@ async def health_check():
165
  return {"status": "healthy", "websocket_stats": manager.get_stats()}
166
 
167
 
 
 
 
 
 
 
 
 
 
 
168
  if __name__ == "__main__":
169
- uvicorn.run(app, host="0.0.0.0", port=8000, log_level="info")
 
1
+ from fastapi import FastAPI, Request, WebSocket, WebSocketDisconnect, status, HTTPException
2
  from fastapi.middleware.cors import CORSMiddleware
3
+ from fastapi.responses import HTMLResponse, JSONResponse
4
  from fastapi.staticfiles import StaticFiles
5
  from fastapi.templating import Jinja2Templates
6
  import json
7
  import asyncio
8
  import uvicorn
9
+ from typing import Dict, Set, Optional, Any
10
  import logging
11
 
12
  # Logging konfigurieren
 
49
  return templates.TemplateResponse("map.html", {"request": request, "maps": filtered_maps})
50
 
51
 
52
+ # Neuer API-Endpunkt für Map-Daten
53
+ @app.get("/api/map/{map_name}")
54
+ async def get_map_data(map_name: str):
55
+ """API-Endpunkt zum Abrufen von Kartendaten"""
56
+ map_entry = maps_data.get(map_name)
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]] = {}
65
  self.connections: Dict[WebSocket, str] = {}
66
+ self.client_types: Dict[WebSocket, str] = {} # Neue Speicherung für Client-Typen
67
  self.message_stats = {"total_sent": 0, "total_received": 0}
68
+ self.group_leaders: Dict[str, WebSocket] = {} # Speichert den ersten Client jeder Gruppe
69
 
70
  async def connect(self, websocket: WebSocket):
71
  await websocket.accept()
 
77
  self.remove_from_group(websocket, group_name)
78
  logger.info(f"Client disconnected from group '{group_name}'")
79
 
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
87
+ client_type: Typ des Clients ("monitor" oder "web")
88
+ """
89
  # Remove from previous group if exists
90
  if websocket in self.connections:
91
  old_group = self.connections[websocket]
 
94
  # Add to new group
95
  if group_name not in self.groups:
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
 
117
  def remove_from_group(self, websocket: WebSocket, group_name: str):
118
  if group_name in self.groups and websocket in self.groups[group_name]:
119
  self.groups[group_name].remove(websocket)
120
+ # Wenn der Gruppenleiter sich trennt, wähle einen neuen
121
+ if self.group_leaders.get(group_name) == websocket and self.groups[group_name]:
122
+ # Wähle den nächsten Client als neuen Leiter
123
+ self.group_leaders[group_name] = next(iter(self.groups[group_name]))
124
+ logger.info(f"Neuer Gruppenleiter für '{group_name}' gewählt")
125
+ elif not self.groups[group_name]: # Leere Gruppen entfernen
126
  del self.groups[group_name]
127
+ if group_name in self.group_leaders:
128
+ del self.group_leaders[group_name]
129
  logger.info(f"Group '{group_name}' deleted (no members)")
130
 
131
  if websocket in self.connections:
132
  del self.connections[websocket]
133
+ if websocket in self.client_types:
134
+ del self.client_types[websocket]
135
 
136
+ async def broadcast_to_group(self, message: str, group_name: str, exclude: Optional[WebSocket] = None):
137
  if group_name in self.groups:
138
  disconnected = set()
139
  for connection in self.groups[group_name].copy(): # Kopie für sichere Iteration
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 {
157
+ "active_groups": len(self.groups),
158
+ "total_connections": len(self.connections),
159
+ **self.message_stats
160
+ }
161
+
162
+ def get_group_info(self, group_name: str) -> Dict[str, Any]:
163
+ """Gibt Informationen über eine Gruppe zurück"""
164
+ if group_name not in self.groups:
165
+ return {"group": group_name, "members": 0, "clients": []}
166
+
167
+ members = []
168
+ for ws in self.groups[group_name]:
169
+ client_type = self.client_types.get(ws, "unknown")
170
+ is_leader = (self.group_leaders.get(group_name) == ws)
171
+ members.append({
172
+ "client_type": client_type,
173
+ "is_leader": is_leader
174
+ })
175
+
176
+ return {
177
+ "group": group_name,
178
+ "members": len(members),
179
+ "clients": members
180
+ }
181
 
182
 
183
  manager = ConnectionManager()
 
197
  # Handle join messages
198
  if message.get("type") == "join":
199
  group_name = message.get("group")
200
+ client_type = message.get("client_type", "web") # Standard: web
201
  if group_name:
202
+ join_info = await manager.join_group(websocket, group_name, client_type)
203
  # Bestätigungsmessage
204
+ await websocket.send_text(json.dumps(join_info))
205
+
206
+ # Benachrichtige andere Gruppenmitglieder über neuen Client
207
+ notification = {
208
+ "type": "client_joined",
209
+ "group": group_name,
210
+ "client_type": client_type,
211
+ "message": f"Neuer {client_type}-Client ist der Gruppe beigetreten"
212
+ }
213
+ await manager.broadcast_to_group(
214
+ json.dumps(notification),
215
+ group_name,
216
+ exclude=websocket # Sende nicht an den neu verbundenen Client
217
+ )
218
  else:
219
  error_msg = {"type": "error", "message": "Missing group name in join request"}
220
  await websocket.send_text(json.dumps(error_msg))
 
252
  return {"status": "healthy", "websocket_stats": manager.get_stats()}
253
 
254
 
255
+ # Neuer Endpoint für Gruppeninformationen
256
+ @app.get("/api/group/{group_name}")
257
+ async def get_group_info(group_name: str):
258
+ """API-Endpunkt zum Abrufen von Gruppeninformationen"""
259
+ group_info = manager.get_group_info(group_name)
260
+ if group_info["members"] == 0:
261
+ raise HTTPException(status_code=404, detail="Group not found")
262
+ return JSONResponse(content=group_info)
263
+
264
+
265
  if __name__ == "__main__":
266
+ uvicorn.run(app, host="0.0.0.0", port=8000, log_level="info")