§
    Ÿ¿j"  ã                  óx   — d Z ddlmZ ddlZddlmZ ddlmZmZm	Z	m
Z
mZmZ ddlmZmZmZ  G d„ d¦  «        ZdS )	zœ
Multi-Channel Policy, Rate Limiting, and Channel History Manager.
Enforces channel-specific gates (Level requirements, Cooldown token buckets, Anti-spam).
é    )ÚannotationsN)Údeque)ÚDequeÚDictÚListÚOptionalÚSetÚTuple)ÚChatChannelTypeÚChatMessageDTOÚSendChatRequestDTOc                  ó  — e Zd ZU dZdZdZdZej        dej	        dej
        dej        dej        d	ej        dej        d
ej        diZded<   d7d„Z	 	 	 	 	 d8d9d„Zd:d;d!„Zd<d"„Zd=d$„Zd>d(„Zd?d)„Zd7d*„Zd@d.„ZdAd0„ZdBd1„ZdCd5„Zd6S )DÚChannelManagerz—
    Manages channel routing rules, anti-spam rate limits, historical buffers,
    and persistent mute security states across all 8 chat channels.
    éd   é   é
   g      .@g      @g      $@g      à?gš™™™™™É?ç      @ç        zDict[ChatChannelType, float]Ú	COOLDOWNSÚreturnÚNonec                óL   — i | _         i | _        i | _        i | _        i | _        d S )N)Ú_last_send_timeÚ_last_message_infoÚ_player_blacklistsÚ_channel_historiesÚ_muted_players©Úselfs    ú4C:\Projects\FreeExile\server\chat\channel_manager.pyÚ__init__zChannelManager.__init__(   s0   € àIKˆÔàXZˆÔà79ˆÔàDFˆÔà02ˆÔÐÐó    Ú r   Úchannelr   Úzone_idÚstrÚguild_idÚparty_idÚplayer_aÚintÚplayer_bc                ó„  — |t           j        k    rdS |t           j        k    rd|› �S |t           j        k    rd|› �S |t           j        k    rd|› �S |t           j        k    r%t          ||g¦  «        }d|d         › d|d         › �S |t           j        k    rd	S |t           j        k    rd
|› �S |t           j	        k    rdS dS )z<Derives a deterministic partition key for a channel context.Úworldzzone:zguild:zparty:úwhisper:r   ú:é   Úrecruitú	feedback:ÚsystemÚunspecified)
r   ÚWORLDÚZONEÚGUILDÚPARTYÚWHISPERÚsortedÚRECRUITÚFEEDBACKÚSYSTEM)r   r$   r%   r'   r(   r)   r+   Úpairs           r    Úget_channel_keyzChannelManager.get_channel_key4   sð   € ð •oÔ+Ò+Ð+Ø�7Ø•oÔ*Ò*Ð*Ø$˜7Ð$Ð$Ð$Ø•oÔ+Ò+Ð+Ø&˜HÐ&Ð&Ð&Ø•oÔ+Ò+Ð+Ø&˜HÐ&Ð&Ð&Ø•oÔ-Ò-Ð-Ý˜8 XÐ.Ñ/Ô/ˆDØ1˜d 1œgÐ1Ð1¨¨Q¬Ð1Ð1Ð1Ø•oÔ-Ò-Ð-Ø�9Ø•oÔ.Ò.Ð.Ø)˜xÐ)Ð)Ð)Ø•oÔ,Ò,Ð,Ø�8Øˆ}r"   ç      œ@Ú	player_idÚduration_secondsÚfloatc                óB   — t          j         ¦   «         |z   | j        |<   dS )z3Applies a persistent mute lock on a player account.N)Útimer   )r   rA   rB   s      r    Úmute_playerzChannelManager.mute_playerQ   s!   € å)-¬©¬Ð7GÑ)GˆÔ˜IÑ&Ð&Ð&r"   c                ó<   — | j                              |d¦  «         dS )z.Lifts chat restrictions from a player account.N)r   Úpop)r   rA   s     r    Úunmute_playerzChannelManager.unmute_playerU   s!   € àÔ×Ò 	¨4Ñ0Ô0Ð0Ð0Ð0r"   úTuple[bool, int]c                ó¬   — | j                              |¦  «        }|€dS t          j        ¦   «         }||k     rdt          ||z
  ¦  «        fS | j         |= dS )zOChecks if a player is currently muted, returning (is_muted, remaining_seconds).N)Fr   T)r   ÚgetrE   r*   )r   rA   Ú
mute_untilÚnows       r    Úis_player_mutedzChannelManager.is_player_mutedY   sa   € àÔ(×,Ò,¨YÑ7Ô7ˆ
ØÐØ�8ÝŒi‰kŒkˆØ�ÒÐØ�˜Z¨#Ñ-Ñ.Ô.Ð.Ð.àÔ 	Ð*Øˆxr"   Úrequestr   úTuple[bool, str, int]c                ó¸  — |                       |j        ¦  «        \  }}|rdd|› d�|dz  fS t          j        ¦   «         }|j        }|t          j        k    r|j        | j        k     rdd| j        › d�dfS |t          j        k    r|j        | j	        k     rdd| j	        › d�dfS |t          j
        k    r	|j        sd	S |t          j        k    r	|j        sd
S |t          j        k    rV|j        dk    rdS |j        |j        k    rdS | j                             |j        t%          ¦   «         ¦  «        }|j        |v rdS | j                             |d¦  «        }| j                             |j        |fd¦  «        }||z
  }	|	|k     rt+          ||	z
  dz  ¦  «        }
dd|
› d�|
fS |t          j        t          j        fv r | j                             |j        |f¦  «        }|�}|\  }}||z
  }|j                             ¦   «                              ¦   «         |                     ¦   «                              ¦   «         k    r |dk     rt+          d|z
  dz  ¦  «        }dd|fS dS )zŒ
        Validates whether the player meets channel constraints.
        Returns: (is_allowed, error_reason, cooldown_remaining_ms)
        FuB   TÃ i khoáº£n Ä‘ang bá»‹ táº¡m khÃ³a chat. Thá»�i gian cÃ²n láº¡i: zs.iè  u   Cáº§n Ä‘áº¡t cáº¥p u%    Ä‘á»ƒ phÃ¡t tÃ¡n kÃªnh Tháº¿ Giá»›i.r   u    Ä‘á»ƒ dÃ¹ng kÃªnh ChiÃªu Má»™.)Fu   ChÆ°a gia nháº­p Bang Há»™i.r   )Fu   ChÆ°a gia nháº­p Tá»• Ä�á»™i.r   )Fu)   Má»¥c tiÃªu máº­t thÆ° khÃ´ng há»£p lá»‡.r   )Fu4   KhÃ´ng thá»ƒ tá»± gá»­i máº­t thÆ° cho chÃ­nh mÃ¬nh.r   )Fu2   Ä�á»‘i phÆ°Æ¡ng Ä‘Ã£ cháº·n tin nháº¯n tá»« báº¡n.r   g      ð?r   u'   Gá»­i tin quÃ¡ nhanh! Vui lÃ²ng Ä‘á»£i zms.Nr   u*   PhÃ¡t hiá»‡n spam tin nháº¯n trÃ¹ng láº·p!)Tr#   r   )rO   Ú	sender_idrE   r$   r   r5   Úsender_levelÚMIN_WORLD_LEVELr;   ÚMIN_RECRUIT_LEVELr7   r'   r8   r(   r9   Ú	target_idr   rL   Úsetr   r   r*   r6   r   ÚcontentÚstripÚlower)r   rP   Úis_mutedÚremaining_secrN   r$   Útarget_blacklistÚcooldown_durationÚ	last_timeÚelapsedÚremaining_msÚ	last_infoÚlast_contentÚlast_msg_timeÚtime_since_lastÚremaining_spam_mss                   r    Úvalidate_send_permissionz'ChannelManager.validate_send_permissione   sÏ  € ð #'×"6Ò"6°wÔ7HÑ"IÔ"IÑˆ�-Øð 	GØÐpÐ_lÐpÐpÐpÐrð  CGñ  sGð  Gð  GåŒi‰kŒkˆØ”/ˆð •oÔ+Ò+Ð+°Ô0DÀtÔG[Ò0[Ð0[ØÐk°Ô0DÐkÐkÐkÐmnÐnÐnà•oÔ-Ò-Ð-°'Ô2FÈÔI_Ò2_Ð2_ØÐg°Ô0FÐgÐgÐgÐijÐjÐjð •oÔ+Ò+Ð+°GÔ4DÐ+Ø;Ð;à•oÔ+Ò+Ð+°GÔ4DÐ+Ø<Ð<à•oÔ-Ò-Ð-ØÔ  AÒ%Ð%ØLÐLØÔ  GÔ$5Ò5Ð5ØWÐWà#Ô6×:Ò:¸7Ô;LÍcÉeÌeÑTÔTÐØÔ Ð$4Ð4Ð4ØUÐUð !œN×.Ò.¨w¸Ñ<Ô<ÐØÔ(×,Ò,¨gÔ.?ÀÐ-IÈ3ÑOÔOˆ	Ø˜	‘/ˆàÐ&Ò&Ð&ÝÐ 1°GÑ ;¸tÑCÑDÔDˆLØÐUÀLÐUÐUÐUÐWcÐcÐcð •Ô,­oÔ.BÐCÐCÐCØÔ/×3Ò3°WÔ5FÈÐ4PÑQÔQˆIØÐ$Ø.7Ñ+�˜mØ"%¨Ñ"5�Ø”?×(Ò(Ñ*Ô*×0Ò0Ñ2Ô2°l×6HÒ6HÑ6JÔ6J×6PÒ6PÑ6RÔ6RÒRÐRÐWfÐilÒWlÐWlÝ(+¨S°?Ñ-BÀdÑ,JÑ(KÔ(KÐ%Ø Ð"NÐPaÐaÐaàˆ{r"   c                ó’   — t          j         ¦   «         }|| j        |j        |j        f<   |j        |f| j        |j        |j        f<   dS )zBUpdates player cooldown and spam trackers upon message acceptance.N)rE   r   rS   r$   rY   r   )r   rP   rN   s      r    Úrecord_message_sentz"ChannelManager.record_message_sent¢   sI   € åŒi‰kŒkˆØEHˆÔ˜gÔ/°´ÐAÑBØIPÌÐZ]ÐH^ˆÔ Ô!2°G´OÐ DÑEÐEÐEr"   c                ój   — | j                              ¦   «          | j                             ¦   «          dS )zFClears transient rate-limiting and duplicate message tracking records.N)r   Úclearr   r   s    r    Úreset_rate_limitsz ChannelManager.reset_rate_limits¨   s2   € àÔ×"Ò"Ñ$Ô$Ð$ØÔ×%Ò%Ñ'Ô'Ð'Ð'Ð'r"   Úchannel_keyÚmessager   c                óê   — |                      d¦  «        s|                      d¦  «        rdS || j        vrt          | j        ¬¦  «        | j        |<   | j        |                              |¦  «         dS )zNStores message into recent channel history ring buffer for broadcast channels.r.   r2   N)Úmaxlen)Ú
startswithr   r   ÚMAX_HISTORY_PER_CHANNELÚappend)r   rn   ro   s      r    Úadd_to_historyzChannelManager.add_to_history­   s}   € à×!Ò! *Ñ-Ô-ð 	°×1GÒ1GÈÑ1TÔ1Tð 	ØˆFØ˜dÔ5Ð5Ð5Ý38ÀÔ@\Ð3]Ñ3]Ô3]ˆDÔ# KÑ0ØÔ Ô,×3Ò3°GÑ<Ô<Ð<Ð<Ð<r"   úList[ChatMessageDTO]c                ó\   — | j                              |¦  «        }|rt          |¦  «        ng S )z)Retrieves recent messages from a channel.)r   rL   Úlist)r   rn   Úhistorys      r    Úget_historyzChannelManager.get_historyµ   s-   € àÔ)×-Ò-¨kÑ:Ô:ˆØ 'Ð/�t�G‰}Œ}ˆ}¨RÐ/r"   c                ó<   — | j                              |d¦  «         dS )z-Clears the history ring buffer for a channel.N)r   rH   )r   rn   s     r    Úclear_historyzChannelManager.clear_historyº   s!   € àÔ×#Ò# K°Ñ6Ô6Ð6Ð6Ð6r"   Úblocked_player_idÚ
is_blockedÚboolc                óÌ   — || j         vrt          ¦   «         | j         |<   |r"| j         |                              |¦  «         dS | j         |                              |¦  «         dS )z*Adds or removes a player from a blacklist.N)r   rX   ÚaddÚdiscard)r   rA   r}   r~   s       r    Úset_blacklist_entryz"ChannelManager.set_blacklist_entry¾   sp   € à˜DÔ3Ð3Ð3Ý14±´ˆDÔ# IÑ.Øð 	JØÔ# IÔ.×2Ò2Ð3DÑEÔEÐEÐEÐEàÔ# IÔ.×6Ò6Ð7HÑIÔIÐIÐIÐIr"   N)r   r   )r#   r#   r#   r   r   )r$   r   r%   r&   r'   r&   r(   r&   r)   r*   r+   r*   r   r&   )r@   )rA   r*   rB   rC   r   r   )rA   r*   r   r   )rA   r*   r   rJ   )rP   r   r   rQ   )rP   r   r   r   )rn   r&   ro   r   r   r   )rn   r&   r   rv   )rn   r&   r   r   )rA   r*   r}   r*   r~   r   r   r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__rs   rU   rV   r   r5   r6   r;   r7   r8   r9   r<   r=   r   Ú__annotations__r!   r?   rF   rI   rO   rh   rj   rm   ru   rz   r|   rƒ   © r"   r    r   r      s«  € € € € € € ðð ð
 "ÐØ€OØÐð 	Ô˜tØÔ˜cØÔ ØÔ˜sØÔ˜sØÔ ØÔ  #ØÔ ð	/€Ið 	ð 	ð 	ñ 	ð
3ð 
3ð 
3ð 
3ð ØØØØðð ð ð ð ð:Hð Hð Hð Hð Hð1ð 1ð 1ð 1ð
ð 
ð 
ð 
ð;ð ;ð ;ð ;ðz_ð _ð _ð _ð(ð (ð (ð (ð
=ð =ð =ð =ð0ð 0ð 0ð 0ð
7ð 7ð 7ð 7ðJð Jð Jð Jð Jð Jr"   r   )r‡   Ú
__future__r   rE   Úcollectionsr   Útypingr   r   r   r   r	   r
   Úserver.chat.chat_typesr   r   r   r   r‰   r"   r    ú<module>rŽ      sæ   ððð ð
 #Ð "Ð "Ð "Ð "Ð "à €€€Ø Ð Ð Ð Ð Ð Ø :Ð :Ð :Ð :Ð :Ð :Ð :Ð :Ð :Ð :Ð :Ð :Ð :Ð :Ð :Ð :ðð ð ð ð ð ð ð ð ð ðrJð rJð rJð rJð rJñ rJô rJð rJð rJð rJr"   