Sebastiankay commited on
Commit
dc2d695
·
verified ·
1 Parent(s): 6b61fbf

Create server.py

Browse files
Files changed (1) hide show
  1. server.py +142 -0
server.py ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, Request, WebSocket, WebSocketDisconnect
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 uvicorn
8
+
9
+ app = FastAPI()
10
+
11
+ # Configure CORS
12
+ app.add_middleware(
13
+ CORSMiddleware,
14
+ allow_origins=["*"], # Allows all origins
15
+ allow_credentials=True,
16
+ allow_methods=["*"], # Allows all methods
17
+ allow_headers=["*"], # Allows all headers
18
+ )
19
+
20
+ # Serve static files from the "static" directory
21
+ app.mount("/static", StaticFiles(directory="static"), name="static")
22
+
23
+ # Set up Jinja2 templates
24
+ templates = Jinja2Templates(directory="templates")
25
+
26
+ with open("data.json", "r", encoding="utf8") as file:
27
+ maps_data = json.load(file)
28
+
29
+
30
+ @app.get("/", response_class=HTMLResponse)
31
+ async def read_index(request: Request):
32
+ return templates.TemplateResponse("index.html", {"request": request, "maps": maps_data})
33
+
34
+
35
+ @app.get("/map/{normalized_name}", response_class=HTMLResponse)
36
+ async def get_map_by_normalized_name(request: Request, normalized_name: str):
37
+ map_entry = maps_data.get(normalized_name)
38
+ if map_entry:
39
+ filtered_maps = [map_entry]
40
+ else:
41
+ filtered_maps = []
42
+ return templates.TemplateResponse("map.html", {"request": request, "maps": filtered_maps})
43
+
44
+
45
+ class ConnectionManager:
46
+ def __init__(self):
47
+ self.groups: dict[str, set[WebSocket]] = {}
48
+ self.connections: dict[WebSocket, str] = {}
49
+
50
+ async def connect(self, websocket: WebSocket):
51
+ await websocket.accept()
52
+
53
+ def disconnect(self, websocket: WebSocket):
54
+ if websocket in self.connections:
55
+ group_name = self.connections[websocket]
56
+ self.remove_from_group(websocket, group_name)
57
+
58
+ async def join_group(self, websocket: WebSocket, group_name: str):
59
+ # Remove from previous group if exists
60
+ if websocket in self.connections:
61
+ old_group = self.connections[websocket]
62
+ self.remove_from_group(websocket, old_group)
63
+
64
+ # Add to new group
65
+ if group_name not in self.groups:
66
+ self.groups[group_name] = set()
67
+ self.groups[group_name].add(websocket)
68
+ self.connections[websocket] = group_name
69
+ print(f"Client joined group '{group_name}'")
70
+
71
+ def remove_from_group(self, websocket: WebSocket, group_name: str):
72
+ if group_name in self.groups and websocket in self.groups[group_name]:
73
+ self.groups[group_name].remove(websocket)
74
+ if len(self.groups[group_name]) == 0:
75
+ del self.groups[group_name]
76
+ print(f"Group '{group_name}' deleted (no members)")
77
+ del self.connections[websocket]
78
+ print(f"Client removed from group '{group_name}'")
79
+
80
+ async def broadcast_to_group(self, message: str, group_name: str):
81
+ if group_name in self.groups:
82
+ for connection in self.groups[group_name]:
83
+ await connection.send_text(message)
84
+
85
+
86
+ manager = ConnectionManager()
87
+
88
+
89
+ @app.websocket("/ws")
90
+ async def websocket_endpoint(websocket: WebSocket):
91
+ await manager.connect(websocket)
92
+ try:
93
+ while True:
94
+ data = await websocket.receive_text()
95
+ try:
96
+ message = json.loads(data)
97
+ if message['type'] == 'join':
98
+ group_name = message['group']
99
+ await manager.join_group(websocket, group_name)
100
+ # Notify others in group about new member
101
+ notification = json.dumps({
102
+ "type": "system",
103
+ "message": "New member joined"
104
+ })
105
+ await manager.broadcast_to_group(notification, group_name)
106
+ elif message['type'] == 'message':
107
+ if websocket in manager.connections:
108
+ group_name = manager.connections[websocket]
109
+ await manager.broadcast_to_group(data, group_name)
110
+ else:
111
+ error = json.dumps({
112
+ "type": "error",
113
+ "message": "Join a group before sending messages"
114
+ })
115
+ await websocket.send_text(error)
116
+ except json.JSONDecodeError:
117
+ error = json.dumps({
118
+ "type": "error",
119
+ "message": "Invalid JSON format"
120
+ })
121
+ await websocket.send_text(error)
122
+ except KeyError:
123
+ error = json.dumps({
124
+ "type": "error",
125
+ "message": "Missing required fields in message"
126
+ })
127
+ await websocket.send_text(error)
128
+ except WebSocketDisconnect:
129
+ # Get group before disconnecting
130
+ group_name = manager.connections.get(websocket)
131
+ manager.disconnect(websocket)
132
+ # Notify group about disconnection
133
+ if group_name:
134
+ notification = json.dumps({
135
+ "type": "system",
136
+ "message": "A member has left"
137
+ })
138
+ await manager.broadcast_to_group(notification, group_name)
139
+
140
+
141
+ if __name__ == "__main__":
142
+ uvicorn.run(app, host="0.0.0.0", port=8000)