import asyncio import datetime import logging import time from threading import Thread from hopper.models.player import PlayerList from hopper.ws_client import ws_send_game_state from settings import settings class InactivityWatchdog(Thread): def __init__(self, players: PlayerList, *args, **kwargs) -> None: self.players = players self.stopped = False super().__init__(*args, **kwargs) 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_state = 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_state = 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_state = True else: n += 1 if send_game_state: self.send_game_state() def send_game_state(self): logging.info("Sending WS game state") asyncio.run(ws_send_game_state()) def stop(self) -> None: self.stopped = True