83 lines
3.0 KiB
Python
83 lines
3.0 KiB
Python
import asyncio
|
|
import json
|
|
import websockets
|
|
import socket
|
|
|
|
SESSIONS = {}
|
|
STOP = None
|
|
|
|
async def handler(ws):
|
|
session_id = None
|
|
try:
|
|
async for msg in ws:
|
|
try:
|
|
data = json.loads(msg)
|
|
except Exception:
|
|
continue
|
|
t = data.get('type')
|
|
if t == 'join':
|
|
session_id = data.get('sessionId') or 'default'
|
|
SESSIONS.setdefault(session_id, set()).add(ws)
|
|
await ws.send(json.dumps({'type':'joined','sessionId':session_id}))
|
|
elif t == 'state':
|
|
sid = data.get('sessionId') or session_id or 'default'
|
|
payload = data.get('payload')
|
|
for peer in list(SESSIONS.get(sid, set())):
|
|
if peer is not ws:
|
|
try:
|
|
await peer.send(json.dumps({'type':'state','payload':payload}))
|
|
except Exception:
|
|
pass
|
|
elif t in ('whoami','detect_ip'):
|
|
# Determine the host's primary LAN IP without external calls
|
|
ip = '127.0.0.1'
|
|
try:
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
s.connect(('8.8.8.8', 80))
|
|
ip = s.getsockname()[0]
|
|
s.close()
|
|
except Exception:
|
|
ip = socket.gethostbyname(socket.gethostname())
|
|
try:
|
|
await ws.send(json.dumps({'type':'detect_ip','ip': ip}))
|
|
except Exception:
|
|
pass
|
|
elif t == 'shutdown':
|
|
try:
|
|
ra = ws.remote_address[0] if ws.remote_address else None
|
|
except Exception:
|
|
ra = None
|
|
local_ip = '127.0.0.1'
|
|
try:
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
s.connect(('8.8.8.8', 80))
|
|
local_ip = s.getsockname()[0]
|
|
s.close()
|
|
except Exception:
|
|
try:
|
|
local_ip = socket.gethostbyname(socket.gethostname())
|
|
except Exception:
|
|
local_ip = '127.0.0.1'
|
|
if ra in ('127.0.0.1', '::1', local_ip):
|
|
try:
|
|
await ws.send(json.dumps({'type':'shutdown_ack'}))
|
|
except Exception:
|
|
pass
|
|
if STOP and not STOP.done():
|
|
STOP.set_result(True)
|
|
elif t == 'ping':
|
|
await ws.send(json.dumps({'type':'pong'}))
|
|
finally:
|
|
if session_id and ws in SESSIONS.get(session_id, set()):
|
|
SESSIONS[session_id].discard(ws)
|
|
|
|
async def main():
|
|
global STOP
|
|
STOP = asyncio.Future()
|
|
print('Starting BLS relay on ws://0.0.0.0:8787')
|
|
async with websockets.serve(handler, '0.0.0.0', 8787, ping_interval=20, ping_timeout=20):
|
|
await STOP
|
|
|
|
if __name__ == '__main__':
|
|
asyncio.run(main())
|