import asyncio import datetime import logging import time from threading import Thread from hopper.models.player import PlayerList from hopper.ws_server import WSServer from settings import settings class InactivityWatchdog(Thread): def __init__( self, players: PlayerList, ws_server: WSServer = None ) -> None: self.players = players self.ws_server = ws_server self.stopped = False super().__init__(daemon=True) def run(self) -> None: logging.info("Starting inactivity watchdog") while not self.stopped: self.cleanup_players() time.sleep(settings.inacivity_watchdog.TICK_INTERVAL) def cleanup_players(self) -> None: now = datetime.datetime.now() inactivity_threshold = now - datetime.timedelta( seconds=settings.inacivity_watchdog.INACIVITY_TIMEOUT ) kick_threshold = now - datetime.timedelta( seconds=settings.inacivity_watchdog.KICK_TIMEOUT ) send_game_dump = False for player in self.players: if ( player.can_be_deactivated and player.active and player.last_seen < inactivity_threshold ): player.active = False logging.info(f"Player {player} set as inactive") send_game_dump = True # safe remove from list n = 0 while n < len(self.players): player = self.players[n] if player.can_be_deactivated and player.last_seen < kick_threshold: self.players.pop(n) logging.info(f"Player {player} kicked out") send_game_dump = True else: n += 1 if send_game_dump: self.send_game_dump() def send_game_dump(self): logging.info("Sending WS game dump") asyncio.run(self.ws_server.send_game_dump()) def stop(self) -> None: self.stopped = True