feat: переработка NetwrokMessage и EventMapper

This commit is contained in:
2026-08-25 01:50:45 +03:00
parent b1132715e1
commit 4533789432
+34 -40
View File
@@ -1,7 +1,8 @@
import json import json
import logging
from dataclasses import asdict, dataclass, field from dataclasses import asdict, dataclass, field
from enum import StrEnum, auto from enum import StrEnum, auto
from typing import Any from typing import Any, Optional
from uuid_extensions import uuid7str from uuid_extensions import uuid7str
@@ -16,6 +17,8 @@ from ..state_machines.session.events import (
SetterMoveEvent, SetterMoveEvent,
) )
logger = logging.getLogger(__name__)
class SessionMessageKind(StrEnum): class SessionMessageKind(StrEnum):
PLAYER_HELLO = auto() PLAYER_HELLO = auto()
@@ -42,6 +45,14 @@ KIND_TO_EVENT_MAP = {
} }
def serializer(obj: Any) -> Any:
if isinstance(obj, StrEnum):
return obj.value
raise TypeError(
f"Object of type {type(obj).__name__} is not JSON serializable"
)
@dataclass(frozen=True) @dataclass(frozen=True)
class NetworkMessage: class NetworkMessage:
kind: NetworkMessageKind kind: NetworkMessageKind
@@ -50,17 +61,22 @@ class NetworkMessage:
@classmethod @classmethod
def from_json(cls, json_str: str) -> "NetworkMessage": def from_json(cls, json_str: str) -> "NetworkMessage":
data = json.loads(json_str) try:
return cls( data = json.loads(json_str)
kind=NetworkMessageKind(data["kind"]), return cls(
payload=data.get("payload", {}), kind=NetworkMessageKind(data["kind"]),
id=data["id"], payload=data.get("payload", {}),
) id=data["id"],
)
except (KeyError, ValueError, json.JSONDecodeError) as err:
logger.error(
"Failed to deserialize NetworkMessage from JSON: %s", err
)
raise
def to_json(self) -> str: def to_json(self) -> str:
data = asdict(self) data = {"kind": self.kind.value, "payload": self.payload, "id": self.id}
data["kind"] = self.kind.value return json.dumps(data, ensure_ascii=False, default=serializer)
return json.dumps(data, ensure_ascii=False)
class EventMapper: class EventMapper:
@@ -70,9 +86,14 @@ class EventMapper:
kind = EVENT_TO_KIND_MAP.get(event_type) kind = EVENT_TO_KIND_MAP.get(event_type)
if not kind: if not kind:
raise ValueError(f"Event {event_type} not registered") logger.error(
"Attempted to serialize unregistered event: %s", event_type
)
raise ValueError(
f"Event {event_type} is not registered in EVENT_TO_KIND_MAP"
)
return NetworkMessage(kind=kind, payload=asdict(event)) return NetworkMessage(kind=kind, payload=event.to_payload())
@staticmethod @staticmethod
def from_message(message: NetworkMessage) -> Event | None: def from_message(message: NetworkMessage) -> Event | None:
@@ -82,33 +103,6 @@ class EventMapper:
return None return None
try: try:
payload = message.payload return event_cls.from_payload(message.payload)
player = Player(
name=payload["player"]["name"],
role=PlayerRole(payload["player"]["role"]),
)
match message.kind:
case NetworkMessageKind.PLAYER_HELLO:
return PlayerHelloEvent(player=player)
case NetworkMessageKind.SETTER_MOVED:
return SetterMoveEvent(
player=player,
direction=ArrowDirection(payload["direction"]),
)
case NetworkMessageKind.GUESSER_MOVED:
return GuesserMoveEvent(
player=player,
direction=ArrowDirection(payload["direction"]),
)
case NetworkMessageKind.SECRET_REVEALED:
return RevealSecretEvent(
player=player,
direction=ArrowDirection(payload["direction"]),
)
case NetworkMessageKind.NEXT_STEP_REQUESTED:
return NextStepRequestedEvent(player=player)
except (KeyError, ValueError, TypeError): except (KeyError, ValueError, TypeError):
return None return None