From 5dda7af184504990fade3cbed914e18dd99dc1ab Mon Sep 17 00:00:00 2001 From: Sebastian Lohff Date: Sun, 13 Apr 2025 20:07:06 +0200 Subject: [PATCH] CW server: send out messages in parallel We now send out messages to all participants at the same time (or more or less, as asyncio permits). To not fail in case we can't send the message to one player, we ignore send-exceptions in these occasions and hope that the `for data in self.websocket` in _handle_client() will throw an error and kick the client out of our game. --- signalsrv/signalsrv.py | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/signalsrv/signalsrv.py b/signalsrv/signalsrv.py index 67d79f8..3635a90 100644 --- a/signalsrv/signalsrv.py +++ b/signalsrv/signalsrv.py @@ -124,8 +124,7 @@ class Client: print("FREQ", self.curr_freq, freq, self.freqs) await self._send(type="join", freq=self.curr_freq, self_id=self.id, other_players=[c.id for c in self._others(freq)]) - for other in self._others(freq): - await other._send(type="player-joined", player=self.id) + await self._send_to_group(self._others(freq), type="player-joined", player=self.id) async def _handle_morse_state(self, data): if not self.curr_freq: @@ -136,16 +135,16 @@ class Client: await self._send_error("No state key with type bool in data") return - for other in self._others(self.curr_freq): - await other._send(type="morse-state", state=data["state"], from_player=self.id) + await self._send_to_group(self._others(self.curr_freq), + type="morse-state", state=data["state"], from_player=self.id) async def _leave_room(self): if not self.curr_freq: self._send_error("You are not on a frequency") return - for other in self._others(self.curr_freq): - await other._send(type="player-left", player=self.id) + await self._send_to_group(self._others(self.curr_freq), + type="player-left", player=self.id) try: self.freqs[self.curr_freq].remove(self) except ValueError: @@ -162,10 +161,20 @@ class Client: def _others(self, freq): return [c for c in self.freqs[freq] if c.id != self.id] - async def _send(self, **kwargs): + async def _send(self, ignore_exceptions=False, **kwargs): data = json.dumps(kwargs).encode() print(f" --> sending out to {self.client}: {data}") - await self.websocket.send(json.dumps(kwargs).encode() + b"\n") + try: + await self.websocket.send(json.dumps(kwargs).encode() + b"\n") + except Exception as e: + print(f"Error sending data to {self.client}: {e}") + if not ignore_exceptions: + raise + + async def _send_to_group(self, group, **kwargs): + async with asyncio.TaskGroup() as tg: + for member in group: + tg.create_task(member._send(ignore_exceptions=True, **kwargs)) async def _send_error(self, msg: str): await self._send(type="error", message=msg)