Fix IF session cleanup on failure and player disconnect

This commit is contained in:
Jared Miller 2026-02-09 16:11:28 -05:00
parent 8a8e3dd6e8
commit 6308248d14
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C
4 changed files with 11 additions and 2 deletions

View file

@ -39,9 +39,11 @@ async def cmd_play(player: Player, args: str) -> None:
try: try:
intro = await session.start() intro = await session.start()
except FileNotFoundError: except FileNotFoundError:
await session.stop()
await player.send("error: dfrotz not found. cannot play IF games.\r\n") await player.send("error: dfrotz not found. cannot play IF games.\r\n")
return return
except OSError as e: except OSError as e:
await session.stop()
await player.send(f"error starting game: {e}\r\n") await player.send(f"error starting game: {e}\r\n")
return return

View file

@ -42,10 +42,10 @@ class IFSession:
async def handle_input(self, text: str) -> IFResponse: async def handle_input(self, text: str) -> IFResponse:
"""Handle player input. Route to dfrotz or handle escape commands.""" """Handle player input. Route to dfrotz or handle escape commands."""
# Check for escape commands (:: prefix) # Check for escape commands (:: prefix)
if text == "::quit": if text.lower() == "::quit":
return IFResponse(output="", done=True) return IFResponse(output="", done=True)
if text == "::help": if text.lower() == "::help":
help_text = """escape commands: help_text = """escape commands:
::quit - exit the game ::quit - exit the game
::help - show this help""" ::help - show this help"""

View file

@ -353,6 +353,9 @@ async def shell(
if _writer.is_closing(): if _writer.is_closing():
break break
finally: finally:
# Clean up IF session if player was playing
if player.if_session:
await player.if_session.stop()
# Save player state on disconnect (if not already saved by quit command) # Save player state on disconnect (if not already saved by quit command)
if player_name in players: if player_name in players:
save_player(player) save_player(player)

View file

@ -95,6 +95,7 @@ async def test_play_handles_dfrotz_missing(player):
# Mock IFSession to raise FileNotFoundError on start # Mock IFSession to raise FileNotFoundError on start
mock_session = Mock() mock_session = Mock()
mock_session.start = AsyncMock(side_effect=FileNotFoundError()) mock_session.start = AsyncMock(side_effect=FileNotFoundError())
mock_session.stop = AsyncMock()
with patch("mudlib.commands.play.IFSession") as MockIFSession: with patch("mudlib.commands.play.IFSession") as MockIFSession:
MockIFSession.return_value = mock_session MockIFSession.return_value = mock_session
@ -114,3 +115,6 @@ async def test_play_handles_dfrotz_missing(player):
# Verify session was NOT attached # Verify session was NOT attached
assert player.if_session is None assert player.if_session is None
# Verify session.stop() was called
mock_session.stop.assert_called_once()