Skip to content

Commit b8da110

Browse files
committed
WIP: Add TypedDict definitions for all server messages
1 parent 32de866 commit b8da110

8 files changed

Lines changed: 433 additions & 21 deletions

File tree

server/lobbyconnection.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
from .rating_service import RatingService
6565
from .types import Address, GameLaunchOptions
6666
from .types.messages import client
67+
from .types.messages.server import ServerMessage
6768

6869

6970
def ice_only(func):
@@ -790,7 +791,7 @@ async def on_player_login(
790791
"me": self.player.to_dict(),
791792
"current_time": datetime_now().isoformat(),
792793

793-
# For backwards compatibility for old clients. For now.
794+
# DEPRECATED: Use attributes in `me` instead.
794795
"id": self.player.id,
795796
"login": username
796797
})
@@ -1426,14 +1427,14 @@ def write_warning(
14261427
if fatal:
14271428
asyncio.create_task(self.abort(message))
14281429

1429-
async def send(self, message):
1430+
async def send(self, message: ServerMessage) -> None:
14301431
"""Send a message and wait for it to be sent."""
14311432
assert self.protocol is not None
14321433

14331434
self.write(message)
14341435
await self.protocol.drain()
14351436

1436-
def write(self, message):
1437+
def write(self, message: ServerMessage) -> None:
14371438
"""Write a message into the send buffer."""
14381439
assert self.protocol is not None
14391440

server/matchmaker/matchmaker_queue.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from typing import TYPE_CHECKING, Any, Callable, ClassVar, Iterable, Optional
88

99
import server.metrics as metrics
10+
from server.types.messages.server import MatchmakerInfoQueue
1011

1112
from ..asyncio_extensions import SpinLock, synchronized
1213
from ..decorators import with_logger
@@ -282,7 +283,7 @@ def shutdown(self):
282283
self._is_running = False
283284
self.timer.cancel()
284285

285-
def to_dict(self):
286+
def to_dict(self) -> MatchmakerInfoQueue:
286287
"""
287288
Return a fuzzy representation of the searches currently in the queue
288289
"""

server/players.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from .factions import Faction
1111
from .protocol import DisconnectedError
1212
from .rating import Leaderboard, PlayerRatings, RatingType
13+
from .types.messages.server import PlayerInfoPlayer, ServerMessage
1314
from .weakattr import WeakAttribute
1415

1516
if TYPE_CHECKING:
@@ -112,7 +113,7 @@ def is_admin(self) -> bool:
112113
def is_moderator(self) -> bool:
113114
return "faf_moderators_global" in self.user_groups
114115

115-
async def send_message(self, message: dict) -> None:
116+
async def send_message(self, message: ServerMessage) -> None:
116117
"""
117118
Try to send a message to this player.
118119
@@ -124,7 +125,7 @@ async def send_message(self, message: dict) -> None:
124125

125126
await self.lobby_connection.send(message)
126127

127-
def write_message(self, message: dict) -> None:
128+
def write_message(self, message: ServerMessage) -> None:
128129
"""
129130
Try to queue a message to be sent to this player.
130131
@@ -136,7 +137,7 @@ def write_message(self, message: dict) -> None:
136137
with suppress(DisconnectedError):
137138
self.lobby_connection.write(message)
138139

139-
def to_dict(self) -> dict:
140+
def to_dict(self) -> PlayerInfoPlayer:
140141
"""
141142
Return a dictionary representing this player object
142143
"""

server/protocol/protocol.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import json
55
from abc import ABCMeta, abstractmethod
66
from asyncio import StreamReader, StreamWriter
7+
from collections.abc import Mapping, Sequence
8+
from typing import Any
79

810
import server.metrics as metrics
911

@@ -25,15 +27,15 @@ def __init__(self, reader: StreamReader, writer: StreamWriter):
2527

2628
@staticmethod
2729
@abstractmethod
28-
def encode_message(message: dict) -> bytes:
30+
def encode_message(message: Mapping[str, Any]) -> bytes:
2931
"""
3032
Encode a message as raw bytes. Can be used along with `*_raw` methods.
3133
"""
3234
pass # pragma: no cover
3335

3436
@staticmethod
3537
@abstractmethod
36-
def decode_message(data: bytes) -> dict:
38+
def decode_message(data: bytes) -> dict[str, Any]:
3739
"""
3840
Decode a message from raw bytes.
3941
"""
@@ -46,7 +48,7 @@ def is_connected(self) -> bool:
4648
return not self.writer.is_closing()
4749

4850
@abstractmethod
49-
async def read_message(self) -> dict:
51+
async def read_message(self) -> dict[str, Any]:
5052
"""
5153
Asynchronously read a message from the stream
5254
@@ -58,7 +60,7 @@ async def read_message(self) -> dict:
5860
"""
5961
pass # pragma: no cover
6062

61-
async def send_message(self, message: dict) -> None:
63+
async def send_message(self, message: Mapping[str, Any]) -> None:
6264
"""
6365
Send a single message in the form of a dictionary
6466
@@ -67,7 +69,7 @@ async def send_message(self, message: dict) -> None:
6769
"""
6870
await self.send_raw(self.encode_message(message))
6971

70-
async def send_messages(self, messages: list[dict]) -> None:
72+
async def send_messages(self, messages: Sequence[Mapping[str, Any]]) -> None:
7173
"""
7274
Send multiple messages in the form of a list of dictionaries.
7375
@@ -89,7 +91,7 @@ async def send_raw(self, data: bytes) -> None:
8991
self.write_raw(data)
9092
await self.drain()
9193

92-
def write_message(self, message: dict) -> None:
94+
def write_message(self, message: Mapping[str, Any]) -> None:
9395
"""
9496
Write a single message into the message buffer. Should be used when
9597
sending broadcasts or when sending messages that are triggered by
@@ -103,7 +105,7 @@ def write_message(self, message: dict) -> None:
103105

104106
self.write_raw(self.encode_message(message))
105107

106-
def write_messages(self, messages: list[dict]) -> None:
108+
def write_messages(self, messages: Sequence[Mapping[str, Any]]) -> None:
107109
"""
108110
Write multiple message into the message buffer.
109111

server/protocol/qdatastream.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
import logging
2525
import struct
2626
from asyncio import IncompleteReadError
27-
from typing import ClassVar
27+
from collections.abc import Mapping
28+
from typing import Any, ClassVar
2829

2930
from server.decorators import with_logger
3031

@@ -95,7 +96,7 @@ def pack_message(*args: str) -> bytes:
9596
return QDataStreamProtocol.pack_block(msg)
9697

9798
@staticmethod
98-
def encode_message(message: dict) -> bytes:
99+
def encode_message(message: Mapping[str, Any]) -> bytes:
99100
"""
100101
Encodes a python object as a block of QStrings
101102
"""
@@ -108,7 +109,7 @@ def encode_message(message: dict) -> bytes:
108109
return QDataStreamProtocol.pack_message(json_encoder.encode(message))
109110

110111
@staticmethod
111-
def decode_message(data: bytes) -> dict:
112+
def decode_message(data: bytes) -> dict[str, Any]:
112113
_, action = QDataStreamProtocol.read_qstring(data)
113114
if action in ("PING", "PONG"):
114115
return {"command": action.lower()}
@@ -128,7 +129,7 @@ def decode_message(data: bytes) -> dict:
128129
pass
129130
return message
130131

131-
async def read_message(self):
132+
async def read_message(self) -> dict[str, Any]:
132133
"""
133134
Read a message from the stream
134135

server/protocol/simple_json.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,22 @@
99
"""
1010

1111
import json
12+
from collections.abc import Mapping
13+
from typing import Any
1214

1315
from .protocol import DisconnectedError, Protocol, json_encoder
1416

1517

1618
class SimpleJsonProtocol(Protocol):
1719
@staticmethod
18-
def encode_message(message: dict) -> bytes:
20+
def encode_message(message: Mapping[str, Any]) -> bytes:
1921
return (json_encoder.encode(message) + "\n").encode()
2022

2123
@staticmethod
22-
def decode_message(data: bytes) -> dict:
24+
def decode_message(data: bytes) -> dict[str, Any]:
2325
return json.loads(data.strip())
2426

25-
async def read_message(self) -> dict:
27+
async def read_message(self) -> dict[str, Any]:
2628
line = await self.reader.readline()
2729
if not line:
2830
raise DisconnectedError()

server/types/messages/client.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,9 @@ class AvatarSelect(TypedDict):
213213
class CoopList(TypedDict):
214214
"""Request a list of available coop missions.
215215
216+
Responds with a `server.types.messages.server.CoopInfo` message for each
217+
coop mission.
218+
216219
**Example**
217220
```json
218221
{
@@ -430,6 +433,9 @@ class LeaveParty(TypedDict):
430433
class MatchmakerInfo(TypedDict):
431434
"""Request a list of available matchmaker queues.
432435
436+
Responds with a `server.types.messages.server.MatchmakerInfo` message
437+
describing the currently available matchmaker queues.
438+
433439
**Example**
434440
```json
435441
{

0 commit comments

Comments
 (0)