-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
239 additions
and
137 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,67 +1,30 @@ | ||
import asyncio | ||
import datetime as dt | ||
from typing import override | ||
|
||
from server.src.models.client import ClientManager | ||
from pydantic import BaseModel | ||
|
||
from server.src.models.client import ClientManager, Client, LoggerLike | ||
from server.src.models.request import Request | ||
from shared.schemas.actions import BroadcastMessagePayload, SendMessagePayload | ||
from shared.schemas.notifications import BroadcastMessageNotificationPayload, \ | ||
BroadcastMessageNotificationFrame, ErrorNotificationFrame, ErrorNotificationPayload | ||
|
||
|
||
async def broadcast_message_handler(request: Request) -> None: | ||
incoming_payload = BroadcastMessagePayload.model_validate(request.frame.payload) | ||
outgoing_payload = BroadcastMessageNotificationPayload( | ||
text=incoming_payload.text, | ||
sender=request.client.user.id, | ||
created_at=dt.datetime.now(dt.UTC), | ||
) | ||
frame = BroadcastMessageNotificationFrame(payload=outgoing_payload) | ||
clients = ClientManager.get_current() | ||
tasks = [client.send(frame) for client in clients.all()] | ||
await asyncio.gather(*tasks) | ||
request.logger.info("Message broadcasted successfully") | ||
|
||
|
||
async def send_message_handler(request: Request) -> None: | ||
incoming_payload = SendMessagePayload.model_validate(request.frame.payload) | ||
clients = ClientManager.get_current() | ||
client = clients.get(incoming_payload.to) | ||
if client is None: | ||
outgoing_payload = ErrorNotificationPayload( | ||
text=f"User '{incoming_payload.to}' not found", | ||
created_at=dt.datetime.now(dt.UTC), | ||
) | ||
await request.reply(ErrorNotificationFrame(payload=outgoing_payload)) | ||
request.logger.info("User '%s' not found", incoming_payload.to) | ||
else: | ||
outgoing_payload = BroadcastMessageNotificationPayload( | ||
text=incoming_payload.text, | ||
sender=request.client.user.id, | ||
created_at=dt.datetime.now(dt.UTC), | ||
) | ||
frame = BroadcastMessageNotificationFrame(payload=outgoing_payload) | ||
await client.send(frame) | ||
request.logger.info("Message sent to '%s'", incoming_payload.to) | ||
|
||
|
||
async def error_handler(request: Request, error: Exception) -> None: | ||
payload = ErrorNotificationPayload( | ||
text=f"Something went wrong: {error}", | ||
created_at=dt.datetime.now(dt.UTC), | ||
) | ||
frame = ErrorNotificationFrame(payload=payload) | ||
request.logger.exception("Error occurred while handling request") | ||
await request.reply(frame) | ||
|
||
|
||
async def logout_handler(request: Request) -> None: | ||
clients = ClientManager.get_current() | ||
await clients.drop(request.client) | ||
request.logger.info("Client '%s' dropped", request.client.user.id) | ||
|
||
|
||
async def unknown_action_handler(request: Request) -> None: | ||
payload = ErrorNotificationPayload(text=f"Unknown command", created_at=dt.datetime.now(dt.UTC)) | ||
frame = ErrorNotificationFrame(payload=payload) | ||
await request.reply(frame) | ||
request.logger.info("Unknown command received from '%s'", request.client.user.id) | ||
# async def error_handler(request: Request, error: Exception) -> None: | ||
# payload = ErrorNotificationPayload( | ||
# text=f"Something went wrong: {error}", | ||
# created_at=dt.datetime.now(dt.UTC), | ||
# ) | ||
# frame = ErrorNotificationFrame(payload=payload) | ||
# request.logger.exception("Error occurred while handling request") | ||
# await request.reply(frame) | ||
# | ||
# | ||
|
||
# | ||
# async def unknown_action_handler(request: Request) -> None: | ||
# payload = ErrorNotificationPayload(text=f"Unknown command", created_at=dt.datetime.now(dt.UTC)) | ||
# frame = ErrorNotificationFrame(payload=payload) | ||
# await request.reply(frame) | ||
# request.logger.info("Unknown command received from '%s'", request.client.user.id) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
from .base_handler import BaseHandler | ||
from .message_handler import SendMessageHandler | ||
from .broadcast_handler import BroadcastMessageHandler | ||
from .logout_handler import LogoutHandler | ||
from .unknown_handler import UnknownActionHandler | ||
from .error_handler import BaseErrorHandler |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
from pydantic import BaseModel | ||
|
||
from server.src.models.client import ClientManager, Client, LoggerLike | ||
|
||
|
||
class BaseHandler: | ||
clients: ClientManager = ClientManager.get_current() | ||
payload_validator: BaseModel | None = None | ||
|
||
def __init__(self, payload: dict, client: Client, logger: LoggerLike) -> None: | ||
self.payload = self._get_payload(payload) | ||
self.client = client | ||
self.logger = logger | ||
|
||
async def __call__(self, *args, **kwargs) -> None: | ||
self.logger.info(f"Handling request '{self.__class__.__name__}' from '{self.client.user.id}'...") | ||
await self.handle() | ||
self.logger.info(f"Request '{self.__class__.__name__}' from '{self.client.user.id}' handled successfully") | ||
|
||
def _get_payload(self, payload: dict) -> BaseModel | None: | ||
try: | ||
if self.payload_validator is not None: | ||
return self.payload_validator.model_validate(payload) | ||
return None | ||
except AttributeError as error: | ||
raise NotImplementedError(f"Payload validator is not defined for '{self.__class__.__name__}'") from error | ||
|
||
async def handle(self) -> None: | ||
raise NotImplementedError |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import asyncio | ||
import datetime as dt | ||
from typing import override | ||
|
||
from server.src.handlers.base_handler import BaseHandler | ||
from shared.schemas.actions import BroadcastMessagePayload | ||
from shared.schemas.notifications import BroadcastMessageNotificationPayload, \ | ||
BroadcastMessageNotificationFrame | ||
|
||
|
||
class BroadcastMessageHandler(BaseHandler): | ||
payload_validator = BroadcastMessagePayload | ||
|
||
@override | ||
async def handle(self) -> None: | ||
payload = BroadcastMessageNotificationPayload( | ||
text=self.payload.text, | ||
sender=self.client.user.id, | ||
created_at=dt.datetime.now(dt.UTC), | ||
) | ||
frame = BroadcastMessageNotificationFrame(payload=payload) | ||
tasks = [client.send(frame) for client in self.clients.all()] | ||
await asyncio.gather(*tasks) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import datetime as dt | ||
|
||
from server.src.models.client import ClientManager, Client, LoggerLike | ||
from shared.schemas.notifications import ErrorNotificationPayload, ErrorNotificationFrame | ||
|
||
|
||
class BaseErrorHandler: | ||
clients: ClientManager = ClientManager.get_current() | ||
|
||
def __init__(self, payload: dict, client: Client, error: Exception, logger: LoggerLike) -> None: | ||
self.payload = payload | ||
self.client = client | ||
self.logger = logger | ||
self.error = error | ||
|
||
async def __call__(self, *args, **kwargs) -> None: | ||
self.logger.info(f"Handling error from '{self.client.user.id}'...") | ||
await self.handle() | ||
self.logger.info(f"Error from '{self.client.user.id}' handled successfully") | ||
|
||
async def handle(self) -> None: | ||
payload = ErrorNotificationPayload( | ||
text=f"Something went wrong: {self.error}", | ||
created_at=dt.datetime.now(dt.UTC), | ||
) | ||
frame = ErrorNotificationFrame(payload=payload) | ||
await self.client.send(frame) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import asyncio | ||
import datetime as dt | ||
from typing import override | ||
|
||
from server.src.handlers.base_handler import BaseHandler | ||
from shared.schemas.actions import BroadcastMessagePayload | ||
from shared.schemas.notifications import BroadcastMessageNotificationPayload, \ | ||
BroadcastMessageNotificationFrame | ||
|
||
|
||
class LogoutHandler(BaseHandler): | ||
payload_validator = None | ||
|
||
@override | ||
async def handle(self) -> None: | ||
await self.clients.drop(self.client) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import datetime as dt | ||
from typing import override | ||
|
||
from server.src.handlers.base_handler import BaseHandler | ||
from server.src.models.client import Client | ||
from shared.schemas.actions import SendMessagePayload | ||
from shared.schemas.notifications import BroadcastMessageNotificationPayload, \ | ||
BroadcastMessageNotificationFrame, ErrorNotificationFrame, ErrorNotificationPayload | ||
|
||
|
||
class SendMessageHandler(BaseHandler): | ||
validator = SendMessagePayload | ||
|
||
@override | ||
async def handle(self) -> None: | ||
receiver = self.clients.get(self.payload.to) | ||
if receiver is None: | ||
await self._receiver_not_found() | ||
else: | ||
await self._send_message(receiver) | ||
|
||
async def _receiver_not_found(self) -> None: | ||
self.logger.info(f"User '{self.payload.to}' not found") | ||
payload = ErrorNotificationPayload( | ||
text=f"User '{self.payload.to}' not found", | ||
created_at=dt.datetime.now(dt.UTC), | ||
) | ||
frame = ErrorNotificationFrame(payload=payload) | ||
await self.client.send(frame) | ||
|
||
async def _send_message(self, client: Client) -> None: | ||
self.logger.info(f"Sending message to '{self.payload.to}'...") | ||
payload = BroadcastMessageNotificationPayload( | ||
text=self.payload.text, | ||
sender=self.client.user.id, | ||
created_at=dt.datetime.now(dt.UTC), | ||
) | ||
frame = BroadcastMessageNotificationFrame(payload=payload) | ||
await client.send(frame) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import datetime as dt | ||
from typing import override | ||
|
||
from pydantic import TypeAdapter | ||
|
||
from server.src.handlers.base_handler import BaseHandler | ||
from shared.schemas.notifications import ErrorNotificationFrame, ErrorNotificationPayload | ||
|
||
|
||
class UnknownActionHandler(BaseHandler): | ||
validator = TypeAdapter(dict) | ||
|
||
@override | ||
async def handle(self) -> None: | ||
payload = ErrorNotificationPayload(text=f"Unknown command", created_at=dt.datetime.now(dt.UTC)) | ||
frame = ErrorNotificationFrame(payload=payload) | ||
await self.client.send(frame) | ||
self.logger.info("Unknown command received from '%s'", self.client.user.id) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.