From 6cf0edb31ecdff30d6db568b7310fb1b1f6cfaeb Mon Sep 17 00:00:00 2001 From: Fruktus Date: Fri, 7 Aug 2026 13:28:13 +0200 Subject: [PATCH] feat: add constant message identifiers These ids might be used to easily determine message type when used with database --- server/src/QRServer/common/messages.py | 68 ++++++++++++++++++ server/tests/test_messages.py | 95 +++++++++++++++++++++++++- 2 files changed, 160 insertions(+), 3 deletions(-) diff --git a/server/src/QRServer/common/messages.py b/server/src/QRServer/common/messages.py index 749814fa..2b33b8ab 100644 --- a/server/src/QRServer/common/messages.py +++ b/server/src/QRServer/common/messages.py @@ -10,6 +10,7 @@ class Message: + message_type_id: int args: list[str] prefix: Sequence[str | None] | None = None argc: list[int] | None = None @@ -66,6 +67,7 @@ class RequestMessage(Message): class DisconnectRequest(RequestMessage): + message_type_id = 0 prefix: list[str] = [''] argc = [1] @@ -75,6 +77,7 @@ def new(cls): class PolicyFileRequest(RequestMessage): + message_type_id = 1 prefix: list[str] = [''] argc = [1] @@ -84,6 +87,7 @@ def new(cls): class HelloLobbyRequest(RequestMessage): + message_type_id = 2 prefix: list[str] = [''] argc = [1] @@ -96,6 +100,7 @@ def get_swf_version(self): class JoinLobbyRequest(RequestMessage): + message_type_id = 3 prefix: list[str] = [''] argc = [3] @@ -111,6 +116,7 @@ def get_password(self): class HelloGameRequest(RequestMessage): + message_type_id = 4 prefix: list[str] = [''] argc = [1] @@ -120,6 +126,7 @@ def new(cls): class JoinGameRequest(RequestMessage): + message_type_id = 5 prefix: list[str] = [''] argc = [6] @@ -144,6 +151,7 @@ def get_password(self): class ServerRecentRequest(RequestMessage): + message_type_id = 6 prefix: list[str] = ['', ''] argc = [2] @@ -153,6 +161,7 @@ def new(cls): class ServerRankingRequest(RequestMessage): + message_type_id = 7 prefix: list[str] = ['', ''] argc = [4] @@ -173,6 +182,7 @@ def get_month(self) -> int: class ServerAliveRequest(RequestMessage): + message_type_id = 8 prefix: list[str] = ['', ''] argc = [2] @@ -182,6 +192,7 @@ def new(cls): class ServerPingRequest(RequestMessage): + message_type_id = 9 prefix: list[str] = ['', ''] argc = [2] @@ -191,6 +202,7 @@ def new(cls): class SetCommentRequest(RequestMessage): + message_type_id = 10 prefix: list[str] = ['', ''] argc = [4] @@ -206,6 +218,7 @@ def get_comment(self) -> str: class AddStatsRequest(RequestMessage): + message_type_id = 11 prefix: list[str] = ['', ''] argc = [7] @@ -253,6 +266,7 @@ def to_stats(self) -> MatchStats: class VoidScoreRequest(RequestMessage): + message_type_id = 12 prefix: list[str] = ['', ''] argc = [2] @@ -262,6 +276,7 @@ def new(cls): class NameTakenRequest(RequestMessage): + message_type_id = 13 prefix: list[str] = ['', ''] argc = [3] @@ -278,6 +293,7 @@ def get_name_to_check(self) -> str: class ChangePasswordRequest(RequestMessage): + message_type_id = 14 prefix: list[str] = ['', ''] argc = [3] @@ -302,6 +318,7 @@ class ResponseMessage(Message): class CrossDomainPolicyAllowAllResponse(ResponseMessage): + message_type_id = 15 prefix: list[str] = [''] argc = [1] @@ -311,6 +328,7 @@ def new(cls): class PlayerCountResponse(ResponseMessage): + message_type_id = 16 prefix: list[str] = ['', '', ''] argc = [4] @@ -320,6 +338,7 @@ def new(cls, player_count: int): class BroadcastCommentResponse(ResponseMessage): + message_type_id = 17 prefix: list[str] = ['', ''] argc = [4] @@ -329,6 +348,7 @@ def new(cls, who: int, comment: str): class OldSwfResponse(ResponseMessage): + message_type_id = 18 prefix: list[str] = ['', '', ''] argc = [3] @@ -338,6 +358,7 @@ def new(cls): class NameTakenResponse(ResponseMessage): + message_type_id = 19 prefix: list[str] = ['', '', ''] argc = [4] @@ -347,6 +368,7 @@ def new(cls, taken: bool): class ServerAliveResponse(ResponseMessage): + message_type_id = 20 prefix: list[str] = ['', '', ''] argc = [3] @@ -356,6 +378,7 @@ def new(cls): class LobbyDuplicateResponse(ResponseMessage): + message_type_id = 21 prefix: list[str] = ['', ''] argc = [2] @@ -365,6 +388,7 @@ def new(cls): class LobbyBadMemberResponse(ResponseMessage): + message_type_id = 22 prefix: list[str] = ['', ''] argc = [2] @@ -374,6 +398,7 @@ def new(cls): class LastLoggedResponse(ResponseMessage): + message_type_id = 23 prefix: list[str] = ['', '', ''] argc = [6] @@ -390,6 +415,7 @@ def __last_logged_minutes(time: datetime) -> int: class LastPlayedResponse(ResponseMessage): + message_type_id = 24 prefix: list[str] = ['', '', ''] argc = [18] @@ -423,6 +449,7 @@ def __serialize_entry(cls, entry: GameResultHistory | None) -> str: class ServerRankingThisMonthResponse(ResponseMessage): + message_type_id = 25 prefix: list[str] = ['', '', ''] argc = [-1] @@ -445,6 +472,7 @@ def __serialize_entry(cls, entry: RankingEntry) -> list[str]: class LobbyStateResponse(ResponseMessage): + message_type_id = 26 prefix: list[str] = [''] argc = [170] @@ -473,6 +501,7 @@ def __serialize_player(cls, player: LobbyPlayer | None) -> list[str]: class OpponentDeadResponse(ResponseMessage): + message_type_id = 27 prefix: list[str] = ['', '', ''] argc = [3] @@ -482,6 +511,7 @@ def new(cls): class VoidScoreResponse(ResponseMessage): + message_type_id = 28 prefix: list[str] = ['', '', ''] argc = [3] @@ -491,6 +521,7 @@ def new(cls): class NameTakenResponseNo(ResponseMessage): + message_type_id = 29 prefix: list[str] = ['', '', '', ''] argc = [4] @@ -500,6 +531,7 @@ def new(cls): class NameTakenResponseYes(ResponseMessage): + message_type_id = 30 prefix: list[str] = ['', '', '', ''] argc = [4] @@ -509,6 +541,7 @@ def new(cls): class ChangePasswordResponseOk(ResponseMessage): + message_type_id = 31 prefix: list[str] = ['', '', '', ''] argc = [4] @@ -522,6 +555,7 @@ def new(cls): ################################################################################ class UsePowerMessage(RequestMessage, ResponseMessage): + message_type_id = 32 prefix: list[str] = ['', ''] argc = [4, 5] @@ -549,6 +583,7 @@ def get_power_arg(self) -> str | None: class GameChatMessage(RequestMessage, ResponseMessage): + message_type_id = 33 prefix: list[str] = ['', ''] argc = [3] @@ -561,6 +596,7 @@ def get_text(self) -> str: class LobbyChatMessage(RequestMessage, ResponseMessage): + message_type_id = 34 prefix: list[str] = ['', ''] argc = [4] @@ -582,6 +618,7 @@ def get_text(self) -> str: class GrabPieceMessage(RequestMessage, ResponseMessage): + message_type_id = 35 prefix: list[str] = ['', ''] argc = [3] @@ -594,6 +631,7 @@ def get_piece(self) -> int: class ReleasePieceMessage(RequestMessage, ResponseMessage): + message_type_id = 36 prefix: list[str] = ['', ''] argc = [3] @@ -606,6 +644,7 @@ def get_piece(self) -> int: class SwitchPlayerMessage(RequestMessage, ResponseMessage): + message_type_id = 37 prefix: list[str] = ['', ''] argc = [3] @@ -618,6 +657,7 @@ def get_piece(self) -> int: class RecursiveDoneMessage(RequestMessage, ResponseMessage): + message_type_id = 38 prefix: list[str] = ['', ''] argc = [3] @@ -630,6 +670,7 @@ def get_piece(self) -> int: class SwitcherooMessage(RequestMessage, ResponseMessage): + message_type_id = 39 prefix: list[str] = ['', ''] argc = [6] @@ -646,6 +687,7 @@ def new(cls, piece: int, old_column: int, old_row: int, occupier: int): class RemoveOneWayWallMessage(RequestMessage, ResponseMessage): + message_type_id = 40 prefix: list[str] = ['', ''] argc = [4] @@ -662,6 +704,7 @@ def new(cls, wall: int, piece: int): class BankruptActionMessage(RequestMessage, ResponseMessage): + message_type_id = 41 prefix: list[str] = ['', ''] argc = [3] @@ -678,6 +721,7 @@ def new(cls, player_index: int): class RemovePlayerMessage(RequestMessage, ResponseMessage): + message_type_id = 42 prefix: list[str] = ['', ''] argc = [3] @@ -690,6 +734,7 @@ def get_piece(self) -> int: class PowerNoEffectMessage(RequestMessage, ResponseMessage): + message_type_id = 43 prefix: list[str] = ['', ''] argc = [3] @@ -702,6 +747,7 @@ def get_power_id(self) -> int: class NukeMessage(RequestMessage, ResponseMessage): + message_type_id = 44 prefix: list[str] = ['', ''] argc = [2] @@ -711,6 +757,7 @@ def new(cls): class JumpOnPieceMessage(RequestMessage, ResponseMessage): + message_type_id = 45 prefix: list[str] = ['', ''] argc = [4] @@ -726,6 +773,7 @@ def get_target_piece(self) -> int: class GetPowerSquareMessage(RequestMessage, ResponseMessage): + message_type_id = 46 prefix: list[str] = ['', ''] argc = [4] @@ -741,6 +789,7 @@ def get_player_piece(self) -> int: class SettingsLoadedMessage(RequestMessage, ResponseMessage): + message_type_id = 47 prefix: list[str] = ['', '', ''] argc = [4] @@ -753,6 +802,7 @@ def get_version(self) -> int: class AssignPowerSquareMessage(RequestMessage, ResponseMessage): + message_type_id = 48 prefix: list[str] = ['', ''] argc = [4] @@ -768,6 +818,7 @@ def get_piece(self) -> int: class AssignNextPowerCountMessage(RequestMessage, ResponseMessage): + message_type_id = 49 prefix: list[str] = ['', ''] argc = [3] @@ -780,6 +831,7 @@ def get_count(self) -> int: class NewGridCoordMessage(RequestMessage, ResponseMessage): + message_type_id = 50 prefix: list[str] = ['', ''] argc = [6] @@ -801,6 +853,7 @@ def get_step(self) -> int: class ResignMessage(RequestMessage, ResponseMessage): + message_type_id = 51 prefix: list[str] = ['', '', ''] argc = [3] @@ -810,6 +863,7 @@ def new(cls): class ChallengeMessage(RequestMessage, ResponseMessage): + message_type_id = 52 prefix: tuple[str, None, None, str] = ('', None, None, '') argc = [4] @@ -825,6 +879,7 @@ def get_challenger_idx(self) -> int: class ChallengeAuthMessage(RequestMessage, ResponseMessage): + message_type_id = 53 prefix: tuple[str, None, None, str] = ('', None, None, '') argc = [5] @@ -843,6 +898,7 @@ def get_auth(self) -> str: class SettingsReadyOffMessage(RequestMessage, ResponseMessage): + message_type_id = 54 prefix: list[str] = ['', '', ''] argc = [3] @@ -852,6 +908,7 @@ def new(cls): class SettingsArenaSizeMessage(RequestMessage, ResponseMessage): + message_type_id = 55 prefix: list[str] = ['', '', ''] argc = [4] @@ -872,6 +929,7 @@ def get_size(self) -> str: class SettingsSquadronSizeMessage(RequestMessage, ResponseMessage): + message_type_id = 56 prefix: list[str] = ['', '', ''] argc = [4] @@ -892,6 +950,7 @@ def get_size(self) -> str: class SettingsTimerMessage(RequestMessage, ResponseMessage): + message_type_id = 57 prefix: list[str] = ['', '', ''] argc = [4] @@ -912,6 +971,7 @@ def get_time(self) -> int: class SettingsTopBottomMessage(RequestMessage, ResponseMessage): + message_type_id = 58 prefix: list[str] = ['', '', ''] argc = [4] @@ -924,6 +984,7 @@ def is_top_bottom(self) -> bool: class SettingsColorMessage(RequestMessage, ResponseMessage): + message_type_id = 59 prefix: list[str] = ['', '', ''] argc = [5] @@ -939,6 +1000,7 @@ def get_text_color(self) -> str: class SettingsReadyOnMessage(RequestMessage, ResponseMessage): + message_type_id = 60 prefix: list[str] = ['', '', ''] argc = [7] @@ -960,6 +1022,7 @@ def get_text_color(self) -> str: class SettingsReadyOnAgainMessage(RequestMessage, ResponseMessage): + message_type_id = 61 prefix: list[str] = ['', '', ''] argc = [3] @@ -986,6 +1049,7 @@ def is_message_class(obj: Any) -> TypeGuard[type[Message]]: is_message_class, ) __message_classes: list[Type[Message]] = list(map(lambda member: member[1], __message_classes_full)) +__message_classes_mapping: dict[int, Type[Message]] = {msg.message_type_id: msg for msg in __message_classes} def _parse_data(data: str) -> Message | None: @@ -1015,3 +1079,7 @@ def _valid(args: list[str], prefix: Sequence[str | None] | None, argc: list[int] return False return True + + +def get_message_type_from_id(message_type_id: int) -> Type[Message] | None: + return __message_classes_mapping.get(message_type_id) diff --git a/server/tests/test_messages.py b/server/tests/test_messages.py index eace3740..70975cce 100644 --- a/server/tests/test_messages.py +++ b/server/tests/test_messages.py @@ -3,9 +3,98 @@ from QRServer.common import messages from QRServer.common.classes import GameResultHistory, RankingEntry -from QRServer.common.messages import HelloGameRequest, JoinGameRequest, GameChatMessage, ServerRecentRequest, \ - ServerRankingRequest, JoinLobbyRequest, LastPlayedResponse, ServerRankingThisMonthResponse, UsePowerMessage, \ - ChallengeMessage, ChallengeAuthMessage, SettingsReadyOnMessage, ResignMessage +from QRServer.common.messages import AddStatsRequest, AssignNextPowerCountMessage, AssignPowerSquareMessage, \ + BankruptActionMessage, BroadcastCommentResponse, ChangePasswordRequest, ChangePasswordResponseOk, \ + CrossDomainPolicyAllowAllResponse, DisconnectRequest, GetPowerSquareMessage, GrabPieceMessage, HelloGameRequest, \ + HelloLobbyRequest, JoinGameRequest, GameChatMessage, JumpOnPieceMessage, LastLoggedResponse, \ + LobbyBadMemberResponse, LobbyChatMessage, LobbyDuplicateResponse, LobbyStateResponse, NameTakenRequest, \ + NameTakenResponse, NameTakenResponseNo, NameTakenResponseYes, NewGridCoordMessage, NukeMessage, OldSwfResponse, \ + OpponentDeadResponse, PlayerCountResponse, PolicyFileRequest, PowerNoEffectMessage, RecursiveDoneMessage, \ + ReleasePieceMessage, RemoveOneWayWallMessage, RemovePlayerMessage, ServerAliveRequest, ServerAliveResponse, \ + ServerPingRequest, ServerRecentRequest, ServerRankingRequest, JoinLobbyRequest, LastPlayedResponse, \ + ServerRankingThisMonthResponse, SetCommentRequest, SettingsArenaSizeMessage, SettingsColorMessage, \ + SettingsLoadedMessage, SettingsReadyOffMessage, SettingsReadyOnAgainMessage, SettingsSquadronSizeMessage, \ + SettingsTimerMessage, SettingsTopBottomMessage, SwitchPlayerMessage, SwitcherooMessage, UsePowerMessage, \ + ChallengeMessage, ChallengeAuthMessage, SettingsReadyOnMessage, ResignMessage, VoidScoreRequest, VoidScoreResponse + + +class MessagesTest(unittest.TestCase): + def test_every_message_has_unique_id(self): + ids = set() + for message in getattr(messages, "__message_classes"): + self.assertIsNotNone(message.message_type_id) + self.assertNotIn(message.message_type_id, ids) + ids.add(message.message_type_id) + + def test_every_message_has_mapping(self): + self.assertEqual(messages.get_message_type_from_id(0), DisconnectRequest) + self.assertEqual(messages.get_message_type_from_id(1), PolicyFileRequest) + self.assertEqual(messages.get_message_type_from_id(2), HelloLobbyRequest) + self.assertEqual(messages.get_message_type_from_id(3), JoinLobbyRequest) + self.assertEqual(messages.get_message_type_from_id(4), HelloGameRequest) + self.assertEqual(messages.get_message_type_from_id(5), JoinGameRequest) + self.assertEqual(messages.get_message_type_from_id(6), ServerRecentRequest) + self.assertEqual(messages.get_message_type_from_id(7), ServerRankingRequest) + self.assertEqual(messages.get_message_type_from_id(8), ServerAliveRequest) + self.assertEqual(messages.get_message_type_from_id(9), ServerPingRequest) + + self.assertEqual(messages.get_message_type_from_id(10), SetCommentRequest) + self.assertEqual(messages.get_message_type_from_id(11), AddStatsRequest) + self.assertEqual(messages.get_message_type_from_id(12), VoidScoreRequest) + self.assertEqual(messages.get_message_type_from_id(13), NameTakenRequest) + self.assertEqual(messages.get_message_type_from_id(14), ChangePasswordRequest) + self.assertEqual(messages.get_message_type_from_id(15), CrossDomainPolicyAllowAllResponse) + self.assertEqual(messages.get_message_type_from_id(16), PlayerCountResponse) + self.assertEqual(messages.get_message_type_from_id(17), BroadcastCommentResponse) + self.assertEqual(messages.get_message_type_from_id(18), OldSwfResponse) + self.assertEqual(messages.get_message_type_from_id(19), NameTakenResponse) + + self.assertEqual(messages.get_message_type_from_id(20), ServerAliveResponse) + self.assertEqual(messages.get_message_type_from_id(21), LobbyDuplicateResponse) + self.assertEqual(messages.get_message_type_from_id(22), LobbyBadMemberResponse) + self.assertEqual(messages.get_message_type_from_id(23), LastLoggedResponse) + self.assertEqual(messages.get_message_type_from_id(24), LastPlayedResponse) + self.assertEqual(messages.get_message_type_from_id(25), ServerRankingThisMonthResponse) + self.assertEqual(messages.get_message_type_from_id(26), LobbyStateResponse) + self.assertEqual(messages.get_message_type_from_id(27), OpponentDeadResponse) + self.assertEqual(messages.get_message_type_from_id(28), VoidScoreResponse) + self.assertEqual(messages.get_message_type_from_id(29), NameTakenResponseNo) + + self.assertEqual(messages.get_message_type_from_id(30), NameTakenResponseYes) + self.assertEqual(messages.get_message_type_from_id(31), ChangePasswordResponseOk) + self.assertEqual(messages.get_message_type_from_id(32), UsePowerMessage) + self.assertEqual(messages.get_message_type_from_id(33), GameChatMessage) + self.assertEqual(messages.get_message_type_from_id(34), LobbyChatMessage) + self.assertEqual(messages.get_message_type_from_id(35), GrabPieceMessage) + self.assertEqual(messages.get_message_type_from_id(36), ReleasePieceMessage) + self.assertEqual(messages.get_message_type_from_id(37), SwitchPlayerMessage) + self.assertEqual(messages.get_message_type_from_id(38), RecursiveDoneMessage) + self.assertEqual(messages.get_message_type_from_id(39), SwitcherooMessage) + + self.assertEqual(messages.get_message_type_from_id(40), RemoveOneWayWallMessage) + self.assertEqual(messages.get_message_type_from_id(41), BankruptActionMessage) + self.assertEqual(messages.get_message_type_from_id(42), RemovePlayerMessage) + self.assertEqual(messages.get_message_type_from_id(43), PowerNoEffectMessage) + self.assertEqual(messages.get_message_type_from_id(44), NukeMessage) + self.assertEqual(messages.get_message_type_from_id(45), JumpOnPieceMessage) + self.assertEqual(messages.get_message_type_from_id(46), GetPowerSquareMessage) + self.assertEqual(messages.get_message_type_from_id(47), SettingsLoadedMessage) + self.assertEqual(messages.get_message_type_from_id(48), AssignPowerSquareMessage) + self.assertEqual(messages.get_message_type_from_id(49), AssignNextPowerCountMessage) + + self.assertEqual(messages.get_message_type_from_id(50), NewGridCoordMessage) + self.assertEqual(messages.get_message_type_from_id(51), ResignMessage) + self.assertEqual(messages.get_message_type_from_id(52), ChallengeMessage) + self.assertEqual(messages.get_message_type_from_id(53), ChallengeAuthMessage) + self.assertEqual(messages.get_message_type_from_id(54), SettingsReadyOffMessage) + self.assertEqual(messages.get_message_type_from_id(55), SettingsArenaSizeMessage) + self.assertEqual(messages.get_message_type_from_id(56), SettingsSquadronSizeMessage) + self.assertEqual(messages.get_message_type_from_id(57), SettingsTimerMessage) + self.assertEqual(messages.get_message_type_from_id(58), SettingsTopBottomMessage) + self.assertEqual(messages.get_message_type_from_id(59), SettingsColorMessage) + + self.assertEqual(messages.get_message_type_from_id(60), SettingsReadyOnMessage) + self.assertEqual(messages.get_message_type_from_id(61), SettingsReadyOnAgainMessage) class RequestMessagesTest(unittest.TestCase):