|
|
|
import asyncio
|
|
|
|
import signal
|
|
|
|
import socketio
|
|
|
|
from aiohttp import web
|
|
|
|
|
|
|
|
SERVER_0_IP = "192.168.1.113"
|
|
|
|
FLASK_SERVER_PORT = 4999
|
|
|
|
HEARTBEAT_INTERVAL = 5
|
|
|
|
HEARTBEAT_TIMEOUT = 3
|
|
|
|
|
|
|
|
sio = socketio.AsyncServer(async_mode='aiohttp')
|
|
|
|
app = web.Application()
|
|
|
|
sio.attach(app)
|
|
|
|
|
|
|
|
servers = {}
|
|
|
|
|
|
|
|
async def available(request):
|
|
|
|
return web.json_response(servers)
|
|
|
|
|
|
|
|
app.router.add_get("/available", available)
|
|
|
|
|
|
|
|
@sio.event
|
|
|
|
async def connect(sid, environ):
|
|
|
|
print("I'm connected!", sid)
|
|
|
|
|
|
|
|
@sio.event
|
|
|
|
async def register(sid, data):
|
|
|
|
server_info = data
|
|
|
|
name = server_info["name"]
|
|
|
|
|
|
|
|
servers[name] = {"ip": server_info["ip"], "port": server_info["port"], "sid": sid}
|
|
|
|
print(servers)
|
|
|
|
|
|
|
|
@sio.event
|
|
|
|
async def disconnect(sid):
|
|
|
|
print("I'm disconnected!", sid)
|
|
|
|
for name, server in servers.items():
|
|
|
|
if server["sid"] == sid:
|
|
|
|
del servers[name]
|
|
|
|
break
|
|
|
|
|
|
|
|
async def heartbeat():
|
|
|
|
while True:
|
|
|
|
await asyncio.sleep(HEARTBEAT_INTERVAL)
|
|
|
|
server_values_copy = list(servers.values())
|
|
|
|
for server in server_values_copy:
|
|
|
|
sid = server["sid"]
|
|
|
|
try:
|
|
|
|
print(f"Sending heartbeat to {sid}...")
|
|
|
|
heartbeat_future = sio.emit("heartbeat", to=sid)
|
|
|
|
await asyncio.wait_for(heartbeat_future, timeout=HEARTBEAT_TIMEOUT)
|
|
|
|
except (asyncio.TimeoutError, socketio.exceptions.TimeoutError):
|
|
|
|
print(f"Server {sid} failed to respond to heartbeat.")
|
|
|
|
await sio.disconnect(sid)
|
|
|
|
|
|
|
|
def exit_handler(sig, frame):
|
|
|
|
print("Shutting down host...")
|
|
|
|
loop = asyncio.get_event_loop()
|
|
|
|
heartbeat_task.cancel()
|
|
|
|
loop.run_until_complete(loop.shutdown_asyncgens())
|
|
|
|
loop.stop()
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
signal.signal(signal.SIGINT, exit_handler)
|
|
|
|
signal.signal(signal.SIGTERM, exit_handler)
|
|
|
|
|
|
|
|
loop = asyncio.get_event_loop()
|
|
|
|
heartbeat_task = loop.create_task(heartbeat())
|
|
|
|
aiohttp_app = loop.create_task(web._run_app(app, host=SERVER_0_IP, port=FLASK_SERVER_PORT))
|
|
|
|
|
|
|
|
try:
|
|
|
|
loop.run_until_complete(asyncio.gather(heartbeat_task, aiohttp_app))
|
|
|
|
except asyncio.CancelledError:
|
|
|
|
pass
|
|
|
|
finally:
|
|
|
|
loop.run_until_complete(loop.shutdown_asyncgens())
|
|
|
|
loop.stop()
|