Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue/#786 send player update on disconnect #832

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions server/player_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,11 @@ async def _fetch_player_ratings(self, player, conn):

def remove_player(self, player: Player):
if player.id in self._players:
# This signals that the player is now disconnected
del player.lobby_connection
del self._players[player.id]
metrics.players_online.set(len(self._players))
self.mark_dirty(player)

async def has_permission_role(self, player: Player, role_name: str) -> bool:
async with self._db.acquire() as conn:
Expand Down
56 changes: 28 additions & 28 deletions server/players.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,37 +130,37 @@ def write_message(self, message: dict) -> None:
with suppress(DisconnectedError):
self.lobby_connection.write(message)

def to_dict(self):
def to_dict(self) -> dict:
"""
Return a dictionary representing this player object
"""

def filter_none(t):
_, v = t
return v is not None

return dict(
filter(
filter_none, (
("id", self.id),
("login", self.login),
("avatar", self.avatar),
("country", self.country),
("clan", self.clan),
("ratings", {
rating_type: {
"rating": self.ratings[rating_type],
"number_of_games": self.game_count[rating_type]
}
for rating_type in self.ratings
}),
# Deprecated
("global_rating", self.ratings[RatingType.GLOBAL]),
("ladder_rating", self.ratings[RatingType.LADDER_1V1]),
("number_of_games", self.game_count[RatingType.GLOBAL]),
)
)
)
assert self.state is not None and self.state.value is not None

cmd = {
"id": self.id,
"login": self.login,
"avatar": self.avatar,
"country": self.country,
"clan": self.clan,
# NOTE: We are only sending an 'offline' state for now to signal to
# the client when a player disconnects. However, this could be
# expanded in the future to expose more of the internal state
# tracking to the client to make the UI for showing players in game
# more correct.
"state": None if self.lobby_connection else "offline",
"ratings": {
rating_type: {
"rating": self.ratings[rating_type],
"number_of_games": self.game_count[rating_type]
}
for rating_type in self.ratings
},
# DEPRECATED: Use ratings instead
"global_rating": self.ratings[RatingType.GLOBAL],
"ladder_rating": self.ratings[RatingType.LADDER_1V1],
"number_of_games": self.game_count[RatingType.GLOBAL],
}
return {k: v for k, v in cmd.items() if v is not None}

def __str__(self) -> str:
return (f"Player({self.login}, {self.id}, "
Expand Down
21 changes: 18 additions & 3 deletions tests/integration_tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ async def test_drain(
assert "Graceful shutdown period ended! 1 games are still live!" in caplog.messages


@fast_forward(5)
@fast_forward(15)
async def test_player_info_broadcast(lobby_server):
p1 = await connect_client(lobby_server)
p2 = await connect_client(lobby_server)
Expand All @@ -350,8 +350,23 @@ async def test_player_info_broadcast(lobby_server):
await perform_login(p2, ("Rhiza", "puff_the_magic_dragon"))

await read_until(
p2, lambda m: "player_info" in m.values()
and any(map(lambda d: d["login"] == "test", m["players"]))
p2,
lambda m: (
m["command"] == "player_info"
and any(map(lambda d: d["login"] == "test", m["players"]))
)
)

await p1.close()
await read_until(
p2,
lambda m: (
m["command"] == "player_info"
and any(map(
lambda d: d["login"] == "test" and d.get("state") == "offline",
m["players"]
))
)
)


Expand Down
10 changes: 10 additions & 0 deletions tests/unit_tests/test_players.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ def test_serialize():
"id": 42,
"login": "Something",
"clan": "TOAST",
"state": "offline",
"ratings": {
"global": {
"rating": (1234, 68),
Expand All @@ -107,6 +108,15 @@ def test_serialize():
}


def test_serialize_state():
conn = mock.Mock()
p = Player(lobby_connection=conn)
assert "state" not in p.to_dict()

del p.lobby_connection
assert p.to_dict()["state"] == "offline"


async def test_send_message():
p = Player("Test")

Expand Down