a
    %ßió  ã                   @   sT   d Z ddlmZ ddlmZmZ ddlZddlZddlZe 	e
¡ZG dd„ dƒZdS )zz
LRU cache for player records with auto-save on eviction.

Prevents unbounded memory growth by evicting inactive players.
é    )ÚOrderedDict)ÚOptionalÚCallableNc                   @   s¤   e Zd ZdZdeedœdd„Zedœdd	„Zed
dœdd„Z	eedœdd„Z
d
dœdd„Zd
dœdd„Zedœdd„Zedœdd„Zedœdd„Zedœdd„Zd
S )ÚPlayerCacheaW  
    LRU cache for player records.

    Features:
    - Automatic eviction of least-recently-used players
    - Never evicts connected players
    - Auto-save on eviction (optional)
    - Memory usage tracking

    Usage:
        cache = PlayerCache(max_size=100)
        cache.set("user123", player)
        player = cache.get("user123")
    éd   T)Úmax_sizeÚ	auto_savec                 C   s4   t ƒ | _|| _|| _d| _t d|› d|› �¡ dS )z·
        Initialize player cache.

        Args:
            max_size: Maximum number of players to keep in memory
            auto_save: Whether to auto-save evicted players
        Nz"PlayerCache initialized: max_size=z, auto_save=)r   Ú_cacheÚ	_max_sizeÚ
_auto_saveÚon_evictÚloggerÚinfo)Úselfr   r   © r   ú-/var/www/lichun.app/lichun/ws/player_cache.pyÚ__init__    s
    zPlayerCache.__init__)Úuser_idc                 C   s$   || j v r | j  |¡ | j | S dS )z¨
        Get player from cache (marks as recently used).

        Args:
            user_id: User ID

        Returns:
            playerClass instance or None
        N)r	   Úmove_to_end©r   r   r   r   r   Úget3   s    


zPlayerCache.getN)r   Úreturnc                 C   sJ   || j v r$| j  |¡ || j |< dS t| j ƒ| jkr<|  ¡  || j |< dS )z{
        Add player to cache.

        Args:
            user_id: User ID
            player: playerClass instance
        N)r	   r   Úlenr
   Ú
_evict_lru©r   r   Úplayerr   r   r   ÚsetC   s    	

zPlayerCache.setc                 C   s   || j v r| j |= dS dS )z™
        Remove player from cache.

        Args:
            user_id: User ID

        Returns:
            True if removed, False if not found
        TF)r	   r   r   r   r   ÚremoveX   s    

zPlayerCache.remove)r   c                 C   sŠ   t | j ¡ ƒD ]b\}}|jdkrt d|› d|jj› d�¡ | jrL|  	|¡ | j
rbt |  
|¡¡ | j|=  dS qt d| j› d�¡ dS )z3Evict least recently used player (unless connected)ÚdisconnectedzEvicting player from cache: z (ú)NzPlayerCache full (z) with all connected players)Úlistr	   ÚitemsÚ
connectionr   r   ÚcÚ	firstnamer   Ú_save_playerr   ÚasyncioÚcreate_taskÚwarningr
   r   r   r   r   r   g   s    

zPlayerCache._evict_lruc              
   C   s`   ddl m} zt ||ƒ¡ W n< tyZ } z$t d|j› d|› �¡ W Y d}~n
d}~0 0 dS )zSave player to database (async)r   )ÚsaveGameAsynczFailed to save evicted player z: N)Ú	functionsr)   r&   r'   Ú	Exceptionr   ÚerrorÚid)r   r   r)   Úer   r   r   r%   }   s
    zPlayerCache._save_playerc                 C   s
   t | jƒS )zGet current cache size)r   r	   ©r   r   r   r   Úsize†   s    zPlayerCache.sizec                 C   s   t | jƒ| jkS )zCheck if cache is full)r   r	   r
   r/   r   r   r   Úis_fullŠ   s    zPlayerCache.is_fullc                 C   s@   | j s
dS tt| j  ¡ ƒƒ}t |¡}|t| j ƒ d }|d S )zo
        Estimate memory usage of cached players.

        Returns:
            Estimated memory in MB
        g        é
   i   )r	   ÚnextÚiterÚvaluesÚsysÚ	getsizeofr   )r   Zsample_playerZsample_sizeZestimated_totalr   r   r   Úestimate_memory_mbŽ   s    
zPlayerCache.estimate_memory_mbc                 C   sT   t dd„ | j ¡ D ƒƒ}t| jƒ| }t| jƒ| j|||  ¡ t| jƒ| j d dœS )zGet cache statisticsc                 s   s   | ]}|j d krdV  qdS )Ú	connectedé   N)r"   )Ú.0Úpr   r   r   Ú	<genexpr>¤   ó    z(PlayerCache.get_stats.<locals>.<genexpr>r   )r0   r   r9   r   Ú	memory_mbZutilization)Úsumr	   r5   r   r
   r8   )r   r9   r   r   r   r   Ú	get_stats¢   s    úzPlayerCache.get_stats)r   T)Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚintÚboolr   Ústrr   r   r   r   r%   r0   r1   Úfloatr8   ÚdictrA   r   r   r   r   r      s      ýý	r   )rE   Úcollectionsr   Útypingr   r   r6   Úloggingr&   Ú	getLoggerrB   r   r   r   r   r   r   Ú<module>   s   
