import asyncio
import json
import time
import websockets
# --- Configuration ---
WS_URL = "wss://your-websocket-url"
API_KEY = "your-api-key"
CHANNELS = ["fixtures", "scores"]
SIMULATE_DISCONNECT_AFTER_S = 5 # Disconnect after 5 seconds to trigger resume
# Resume state (must persist across reconnects)
server_epoch = None
replay_channels = set()
last_seen = {} # channel -> entryId
# --- Resume Cursor Logic ---
def get_resume_cursors():
if not last_seen or not replay_channels:
return {}
return {ch: eid for ch, eid in last_seen.items() if ch in replay_channels}
# --- WebSocket Connection ---
async def connect_once():
global server_epoch, replay_channels, last_seen
login = {
"type": "login",
"apiKey": API_KEY,
"channels": CHANNELS
}
if server_epoch:
login["serverEpoch"] = server_epoch
cursors = get_resume_cursors()
if cursors:
login["lastSeenId"] = cursors
print("[client] -> login:", login)
async with websockets.connect(WS_URL) as ws:
await ws.send(json.dumps(login))
disconnect_at = time.monotonic() + SIMULATE_DISCONNECT_AFTER_S
async for raw in ws:
if time.monotonic() >= disconnect_at:
print("[client] !! Simulating disconnect")
await ws.close()
return
msg = json.loads(raw)
# --- Resume Setup ---
if msg.get("type") == "login_ok":
resume = msg.get("resume", {})
server_epoch = resume.get("serverEpoch")
replay_channels = set(resume.get("replayChannels", []))
print(f"[client] <- login_ok (epoch: {server_epoch})")
continue
if msg.get("type") == "resume_complete":
print("[client] <- resume_complete")
continue
# --- Cursor Invalidation ---
if msg.get("type") in ("snapshot_required", "resync_required"):
for ch in msg.get("channels", []):
last_seen.pop(ch, None)
print("[client] <-", msg)
continue
# --- Data Message ---
ch = msg.get("channel")
eid = msg.get("entryId")
if ch and eid:
last_seen[ch] = eid
print("[client] <- data", ch, eid)
# --- Main Loop ---
async def main():
while True:
try:
await connect_once()
except Exception as e:
print("[client] connection error:", repr(e))
await asyncio.sleep(1)
if __name__ == "__main__":
asyncio.run(main())