Compare commits

..

No commits in common. "2a0648bcd541866fb6a93a4584f4b533a9810d4d" and "0de9c11fc7ea8de5bed9312166ab6cdb15b50110" have entirely different histories.

1 changed files with 26 additions and 27 deletions

View File

@ -1,20 +1,18 @@
import asyncio import asyncio
import datetime
import json import json
import logging import logging
import re import re
from websockets.asyncio.connection import broadcast
from websockets.asyncio.server import serve from websockets.asyncio.server import serve
__VERSION__ = "0.0.1" __VERSION__ = "0.0.1"
logging.basicConfig( logging.basicConfig(
level=logging.INFO, level=logging.INFO,
format="%(asctime)s %(levelname)s %(message)s" format="%(asctime)s %(name)s %(levelname)s %(message)s"
) )
LOG = logging.getLogger()
class Client: class Client:
freqs = {} freqs = {}
@ -25,7 +23,7 @@ class Client:
self.curr_freq = None self.curr_freq = None
async def handle(self): async def handle(self):
LOG.info(">>> New client %s connected", self.client) print(f" >>> New client {self.client} connected")
exc = None exc = None
try: try:
await self._handle_client() await self._handle_client()
@ -33,7 +31,7 @@ class Client:
exc = e exc = e
finally: finally:
# FIXME: basically handle disconnect / leave from room # FIXME: basically handle disconnect / leave from room
LOG.info("<<< Client %s id %s disconnected: %s", self.client, self.id, exc) print(f" <<< Client {self.client} id {self.id} disconnected: {exc}")
if self.curr_freq: if self.curr_freq:
await self._leave_room() await self._leave_room()
@ -51,19 +49,18 @@ class Client:
async def _handle_client(self): async def _handle_client(self):
await self._send(type="hello", name="LobbySrv 3000", version=__VERSION__) await self._send(type="hello", name="LobbySrv 3000", version=__VERSION__)
async for data in self.websocket: async for data in self.websocket:
print(f" <-- client {self.client} sent {repr(data)}")
try: try:
data = json.loads(data) data = json.loads(data)
except json.JSONDecodeError: except json.JSONDecodeError:
self._send_error("Could not decode message, invalid json") self._send_error("Could not decode message, invalid json")
LOG.error("client %s sent broken data %s", self.client, repr(data))
continue continue
if not isinstance(data, dict) or "cmd" not in data: if not isinstance(data, dict) or "cmd" not in data:
await self._send_error("Invalid format in json") await self._send_error("Invalid format in json")
LOG.error("client %s sent broken data (no cmd key in data) %s", self.client, repr(data))
continue continue
LOG.info("client %s wrote: %s", self.client, data) print(f"{datetime.datetime.now()} {self.client} wrote:", data)
match data["cmd"]: match data["cmd"]:
case "quit": case "quit":
@ -127,7 +124,7 @@ class Client:
self.curr_freq = freq self.curr_freq = freq
self.freqs[freq].append(self) self.freqs[freq].append(self)
# FIXME: do we need locking here? # FIXME: do we need locking here?
LOG.debug("FREQ %s %s %s", self.curr_freq, freq, self.freqs) print("FREQ", self.curr_freq, freq, self.freqs)
await self._send(type="join", freq=self.curr_freq, self_id=self.id, await self._send(type="join", freq=self.curr_freq, self_id=self.id,
other_players=[c.id for c in self._others(freq)]) other_players=[c.id for c in self._others(freq)])
await self._send_to_group(self._others(freq), type="player-joined", player=self.id) await self._send_to_group(self._others(freq), type="player-joined", player=self.id)
@ -145,18 +142,19 @@ class Client:
type="morse-state", state=data["state"], from_player=self.id) type="morse-state", state=data["state"], from_player=self.id)
async def _leave_room(self): async def _leave_room(self):
if self.curr_freq: if not self.curr_freq:
await self._send_to_group(self._others(self.curr_freq), self._send_error("You are not on a frequency")
type="player-left", player=self.id) return
try:
self.freqs[self.curr_freq].remove(self) await self._send_to_group(self._others(self.curr_freq),
except ValueError: type="player-left", player=self.id)
LOG.warning("Player %s was not in freq %s", self.id, self.curr_freq) try:
if not self.freqs[self.curr_freq]: self.freqs[self.curr_freq].remove(self)
del self.freqs[self.curr_freq] except ValueError:
self.curr_freq = None print(f"Warning: Player {self.id} was not in freq {self.curr_freq}")
else: if not self.freqs[self.curr_freq]:
LOG.warning("Client %s is not on a frequency, sending a 'leave' nontheless", self.client) del self.freqs[self.curr_freq]
self.curr_freq = None
try: try:
await self._send(type="leave") await self._send(type="leave")
@ -168,17 +166,18 @@ class Client:
async def _send(self, ignore_exceptions=False, **kwargs): async def _send(self, ignore_exceptions=False, **kwargs):
data = json.dumps(kwargs).encode() data = json.dumps(kwargs).encode()
LOG.debug("--> sending out to %s: %s", self.client, data) print(f" --> sending out to {self.client}: {data}")
try: try:
await self.websocket.send(json.dumps(kwargs).encode() + b"\n") await self.websocket.send(json.dumps(kwargs).encode() + b"\n")
except Exception as e: except Exception as e:
LOG.error("Error sending data to %s: %s", self.client, e) print(f"Error sending data to {self.client}: {e}")
if not ignore_exceptions: if not ignore_exceptions:
raise raise
async def _send_to_group(self, group, **kwargs): async def _send_to_group(self, group, **kwargs):
LOG.info("broadcast() to %s clients: %s", len(group), kwargs) async with asyncio.TaskGroup() as tg:
broadcast([c.websocket for c in group], json.dumps(kwargs).encode() + b"\n") for member in group:
tg.create_task(member._send(ignore_exceptions=True, **kwargs))
async def _send_error(self, msg: str): async def _send_error(self, msg: str):
await self._send(type="error", message=msg) await self._send(type="error", message=msg)
@ -201,5 +200,5 @@ async def main():
if __name__ == "__main__": if __name__ == "__main__":
LOG.info("Starting server") print("Starting server")
asyncio.run(main()) asyncio.run(main())