feat: tolerate disconnects/allow for soft reconnects

This commit is contained in:
2026-02-19 15:55:56 -05:00
Unverified
parent aef1585764
commit c754b2ec72
7 changed files with 299 additions and 63 deletions

View File

@@ -1,14 +1,22 @@
import asyncio
import websockets
from websockets.exceptions import ConnectionClosed
from wakepy import keep
DEFAULT_SERVER_URL = "wss://connect4.abunchofknowitalls.com"
RECONNECT_INTERVAL_SECONDS = 5
RECONNECT_TIMEOUT_SECONDS = 60
MAX_RECONNECT_ATTEMPTS = (
(RECONNECT_TIMEOUT_SECONDS + RECONNECT_INTERVAL_SECONDS - 1)
// RECONNECT_INTERVAL_SECONDS
)
from agent import Agent
async def gameloop(socket):
player = Agent()
while True: # While game is active, continually anticipate messages
while not socket.closed: # While game is active, continually anticipate messages
message = (await socket.recv()).split(":") # Receive message from server
match message[0]:
@@ -37,19 +45,54 @@ async def gameloop(socket):
case "ERROR":
print(f"{message[0]}: {':'.join(message[1:])}")
await socket.close()
async def join_server(username, server_url):
async with websockets.connect(server_url, ping_interval=30, ping_timeout=30) as socket:
await socket.send(f"CONNECT:{username}")
await gameloop(socket)
reconnecting = False
reconnect_deadline = None
reconnect_attempt = 0
while True:
try:
async with websockets.connect(server_url, ping_interval=30, ping_timeout=30) as socket:
if reconnecting:
await socket.send(f"RECONNECT:{username}")
print("Reconnected to server.")
else:
await socket.send(f"CONNECT:{username}")
reconnect_deadline = None
reconnect_attempt = 0
await gameloop(socket)
except (ConnectionClosed, OSError) as error:
print(f"Connection lost ({error}).")
else:
print("Connection closed.")
now = asyncio.get_running_loop().time()
if reconnect_deadline is None:
reconnect_deadline = now + RECONNECT_TIMEOUT_SECONDS
print(f"Attempting to reconnect every {RECONNECT_INTERVAL_SECONDS} seconds for up to {RECONNECT_TIMEOUT_SECONDS} seconds...")
remaining = reconnect_deadline - now
if remaining <= 0:
print("Failed to reconnect within 60 seconds. Exiting.")
return
reconnecting = True
reconnect_attempt += 1
wait_time = min(RECONNECT_INTERVAL_SECONDS, remaining)
print(
f"Reconnect attempt {reconnect_attempt}/{MAX_RECONNECT_ATTEMPTS}: "
f"retrying in {wait_time:.0f}s "
f"({remaining:.0f}s remaining)."
)
await asyncio.sleep(wait_time)
if __name__ == "__main__":
server_url = (
input(f"Enter server address [{DEFAULT_SERVER_URL}]: ").strip()
or DEFAULT_SERVER_URL
)
username = input("Enter username: ")
asyncio.run(join_server(username, server_url))
with keep.presenting():
server_url = (
input(f"Enter server address [{DEFAULT_SERVER_URL}]: ").strip()
or DEFAULT_SERVER_URL
)
username = input("Enter username: ")
asyncio.run(join_server(username, server_url))