-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.py
More file actions
83 lines (69 loc) · 2.43 KB
/
Copy pathserver.py
File metadata and controls
83 lines (69 loc) · 2.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
"""
FastAPI Server bridging FSW UDP telemetry into WebSockets.
Runs locally at port 3000.
"""
import asyncio
import json
import logging
import socket
from contextlib import asynccontextmanager
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
import uvicorn
@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup: Spin up the background UDP datalink task
task = asyncio.create_task(udp_listener())
yield
# Shutdown
task.cancel()
app = FastAPI(lifespan=lifespan)
# Mount the static web interface dashboard
app.mount("/static", StaticFiles(directory="web"), name="static")
active_clients = set()
@app.get("/")
async def root():
return FileResponse("web/index.html")
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
active_clients.add(websocket)
try:
while True:
# Keep pinging to maintain connection alive AND receive commands
msg = await websocket.receive_text()
try:
cmd_data = json.loads(msg)
with open("command.json", "w") as f:
json.dump(cmd_data, f)
except Exception:
pass
except WebSocketDisconnect:
active_clients.remove(websocket)
async def udp_listener():
"""Listens to the Physics engine UDP stream and mirrors to all WS clients."""
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('127.0.0.1', 5005))
sock.setblocking(False)
loop = asyncio.get_running_loop()
while True:
try:
data, _ = sock.recvfrom(65535)
packet = data.decode('utf-8')
# Broadcast to all connected clients
disconnected = set()
for client in list(active_clients):
try:
await client.send_text(packet)
except Exception:
disconnected.add(client)
for base_client in disconnected:
active_clients.discard(base_client)
except BlockingIOError:
await asyncio.sleep(0.01) # Poll rate
except Exception as e:
logging.error(f"UDP Link Error: {e}")
await asyncio.sleep(0.1)
if __name__ == "__main__":
uvicorn.run("server:app", host="0.0.0.0", port=8080, reload=True)