From 6ef15c5e9db947f5aeaf63e8f93fa91da65d49a5 Mon Sep 17 00:00:00 2001 From: "Denis V. Dedkov" Date: Wed, 19 Apr 2023 11:32:43 +0200 Subject: [PATCH] Routes was moved to self class --- Dockerfile | 1 + beerlog-srv.py | 75 +++++++--------------------------------------- routes.py | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 64 deletions(-) create mode 100644 routes.py diff --git a/Dockerfile b/Dockerfile index 9e9832b..72394aa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,6 +4,7 @@ RUN pip install websockets WORKDIR /beerlog-srv COPY beerlog-srv.py . +COPY routes.py . COPY storage.py . ARG BEERLOG_PORT diff --git a/beerlog-srv.py b/beerlog-srv.py index 31ff397..ddeb88a 100644 --- a/beerlog-srv.py +++ b/beerlog-srv.py @@ -5,84 +5,31 @@ import websockets import json import sys import os -from storage import Storage +from routes import Routes + + +routes = Routes() -CONNECTIONS = set() -STORAGES = { "users": Storage("users") } class UserInfoProtocol(websockets.BasicAuthWebSocketServerProtocol): async def check_credentials(self, username, password): - all_users = storage("users").read() - self.user = all_users[username] if username in all_users else None + all_users = routes.users() + self.user = all_users.get(username, None) return self.user != None -def storage(name): - if not name in STORAGES: - STORAGES[name] = Storage(name) - return STORAGES[name] - -def _get_entity(event): - return event.get("entity", None) - -def _get_data(event): - return event.get("data", {}) - -async def add_entity(websocket, event): - name = _get_entity(event) - data = _get_data(event) - if name and data: - storage(name).create(data) - await broadcast(websocket, { "entity": name, "event": "created", "data": data }) - -async def get_entity(websocket, event): - name = _get_entity(event) - ts = _get_data(event).get("ts", 0) - data = storage(name).read(ts) - await websocket.send(json.dumps({ "entity": name, "event": "received", "data": data })) - -async def mod_entity(websocket, event): - name = _get_entity(event) - data = _get_data(event) - if name and data: - storage(name).update(data) - await broadcast(websocket, { "entity": name, "event": "modified", "data": data }) - -async def del_entity(websocket, event): - name = _get_entity(event) - entity_id = _get_data(event).get("id", None) - if storage(name).delete(entity_id): - await broadcast(websocket, { "entity": name, "event": "deleted", "data": entity_id }) - -async def describe(websocket, event): - connections = list(CONNECTIONS) - data = { c.user["id"]: connections.count(c) for c in connections } - await websocket.send(json.dumps({ "entity": "connections", "event": "described", "data": data })) - -async def broadcast(websocket, event): - websockets.broadcast(CONNECTIONS, json.dumps(event)) - -COMMANDS = { - "add": add_entity, - "get": get_entity, - "mod": mod_entity, - "del": del_entity, - "describe": describe - } async def handle(websocket): try: - CONNECTIONS.add(websocket) - await broadcast(websocket, { "event": "connected", "entity": "users", "data": websocket.user}) + await routes.add_connection(websocket) async for message in websocket: event = json.loads(message) print(event, file=sys.stderr) - handler = COMMANDS.get(event["action"], broadcast) - await handler(websocket, event) + await routes.call(event["action"], websocket, event) finally: - CONNECTIONS.remove(websocket) - await broadcast(websocket, { "event": "disconnected", "entity": "users", "data": websocket.user}) + await routes.remove_connection(websocket) + async def main(): port = os.environ.get("BEERLOG_PORT", 8000) @@ -91,5 +38,5 @@ async def main(): async with websockets.serve(handle, host, port, create_protocol=UserInfoProtocol): await asyncio.Future() -asyncio.run(main()) +asyncio.run(main()) diff --git a/routes.py b/routes.py new file mode 100644 index 0000000..150e44c --- /dev/null +++ b/routes.py @@ -0,0 +1,80 @@ +import websockets +import json + +from storage import Storage + +class Routes(): + __connections = set() + __storages = {} + + def __init__(self): + self.__commands = { + "add": self._add_entity, + "get": self._get_entity, + "mod": self._mod_entity, + "del": self._del_entity, + "describe": self._describe + } + + def __storage(self, name): + if not name in self.__storages: + self.__storages[name] = Storage(name) + return self.__storages[name] + + def __get_entity(self, event): + return event.get("entity", None) + + def __get_data(self, event): + return event.get("data", {}) + + def __get_event(self, name, event, data): + return { "entity": name, "event": event, "data": data } + + async def _add_entity(self, websocket, event): + name = self.__get_entity(event) + data = self.__get_data(event) + if name and data: + self.__storage(name).create(data) + await broadcast(websocket, self.__get_event(name, "created", data)) + + async def _get_entity(self, websocket, event): + name = self.__get_entity(event) + ts = self.__get_data(event).get("ts", 0) + data = self.__storage(name).read(ts) + await websocket.send(json.dumps(self.__get_event(name, "received", data ))) + + async def _mod_entity(self, websocket, event): + name = self.__get_entity(event) + data = self.__get_data(event) + if name and data: + self.__storage(name).update(data) + await broadcast(websocket, self.__get_event(name, "modified", data)) + + async def _del_entity(self, websocket, event): + name = self.__get_entity(event) + entity_id = self.__get_data(event).get("id", None) + if self.__storage(name).delete(entity_id): + await broadcast(websocket, self.__get_event(name, "deleted", entity_id )) + + async def _describe(self, websocket, event): + connections = list(self.__connections) + data = { c.user["id"]: connections.count(c) for c in connections } + await websocket.send(json.dumps(self.__get_event("connections", "described", data))) + + async def _broadcast(self, _, event): + websockets.broadcast(self.__connections, json.dumps(event)) + + async def add_connection(self, connection): + self.__connections.add(connection) + await self._broadcast(connection, self.__get_event("users", "connected", connection.user)) + + async def remove_connection(self, connection): + self.__connections.remove(connection) + await self._broadcast(connection, self.__get_event("users", "disconnected", connection.user)) + + async def call(self, command, websocket, event): + handler = self.__commands.get(command, self._broadcast) + await handler(websocket, event) + + def users(self): + return self.__storage("users").read()