o
    <‘ðinE  ã                   @   sÆ  U d dl Z d dlZd dlZd dlmZmZ d dlmZ d dlm	Z	m
Z
mZmZmZ d dlmZ d dlmZ d dlmZmZ d dlmZ d dlmZ d dlmZ d d	lmZ d d
lm Z  d dl!m"Z" eeef Z#dede$fdd„Z%de&dede&fdd„Z'dZ(dZ)dZ*dZ+dZ,e -e.¡Z/G dd„ deƒZ0G dd„ deƒZ1G dd„ de1ƒZ2G dd„ de2ƒZ3G dd „ d e2ƒZ4G d!d"„ d"e2ƒZ5G d#d$„ d$eƒZ6e6j7Z8e6e9d%< G d&d'„ d'e0ƒZ:G d(d)„ d)e:ƒZ;G d*d+„ d+e:ƒZ<dS ),é    N)ÚABCÚabstractmethod)ÚEnum)ÚListÚOptionalÚTupleÚTypeÚUnion)ÚRedis)ÚRedisCluster)ÚDEFAULT_TIMEOUTÚAsyncHTTPClientWrapper)Ú	NoBackoff)Ú
HttpClient)ÚUnhealthyDatabaseException)ÚRetryÚclsÚreturnc                 C   s$   t  | j¡}tdd„ |j ¡ D ƒƒS )z7Extract parameter names from a class's __init__ method.c                 s   s6   � | ]\}}|d kr|j tjjtjjfv r|V  qdS )ÚselfN)ÚkindÚinspectÚ	ParameterÚPOSITIONAL_OR_KEYWORDÚKEYWORD_ONLY)Ú.0ÚnameÚparam© r   ú`/root/parts/websockify/install/lib/python3.10/site-packages/redis/asyncio/multidb/healthcheck.pyÚ	<genexpr>   s   € þÿýüz#_get_init_params.<locals>.<genexpr>)r   Ú	signatureÚ__init__Ú	frozensetÚ
parametersÚitems)r   Úsigr   r   r   Ú_get_init_params   s   þr&   Úkwargsc                    s   t |ƒ‰ ‡ fdd„|  ¡ D ƒS )zJFilter kwargs to only include parameters accepted by the class's __init__.c                    s   i | ]\}}|ˆ v r||“qS r   r   )r   ÚkÚv©Úallowedr   r   Ú
<dictcomp>(   s    z"_filter_kwargs.<locals>.<dictcomp>)r&   r$   )r'   r   r   r*   r   Ú_filter_kwargs%   s   r-   é   é   g      à?iˆ  c                   @   sh   e Zd ZdZeedefdd„ƒƒZeedefdd„ƒƒZ	eedefdd„ƒƒZ
ed	edefd
d„ƒZdS )ÚHealthCheckz!
    Health check interface.
    r   c                 C   ó   dS )z*Number of probes to execute health checks.Nr   ©r   r   r   r   Úhealth_check_probes9   ó   zHealthCheck.health_check_probesc                 C   r1   )z"Delay between health check probes.Nr   r2   r   r   r   Úhealth_check_delay?   r4   zHealthCheck.health_check_delayc                 C   r1   )zCTimeout for the full health check operation (including all probes).Nr   r2   r   r   r   Úhealth_check_timeoutE   r4   z HealthCheck.health_check_timeoutÚ	hc_clientc                 Ã   ó   �dS )ap  
        Function to determine the health status.

        Args:
            database: The database being checked
            hc_client: A Redis client (AsyncRedis or AsyncRedisCluster) to use for
                health checks. This client follows topology changes automatically.

        Returns:
            True if the database is healthy, False otherwise.
        Nr   ©r   Údatabaser7   r   r   r   Úcheck_healthK   s   €zHealthCheck.check_healthN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__Úpropertyr   Úintr3   Úfloatr5   r6   ÚAsyncRedisClientTÚboolr;   r   r   r   r   r0   4   s    r0   c                   @   s`   e Zd ZdZedee defdd„ƒZededefdd„ƒZ	ede
fd	d
„ƒZeddd„ƒZdS )ÚHealthCheckPolicyz)
    Health checks execution policy.
    Úhealth_checksr   c                 Ã   r8   )z8Execute health checks and return database health status.Nr   )r   rF   r:   r   r   r   Úexecute`   ó   €zHealthCheckPolicy.executeÚhealth_checkc                 Ã   r8   ©z?
        Executes health check against given database.
        Nr   ©r   rI   r:   r   r   r   Ú_executee   ó   €zHealthCheckPolicy._executec                 Ã   r8   )z=
        Get a health check client for the database.
        Nr   )r   r:   r   r   r   Ú
get_clientl   rM   zHealthCheckPolicy.get_clientNc                 Ã   r8   )úClose all health check clients.Nr   r2   r   r   r   Úcloses   rH   zHealthCheckPolicy.close©r   N)r<   r=   r>   r?   r   r   r0   rD   rG   rL   rC   rN   rP   r   r   r   r   rE   [   s    rE   c                   @   s\   e Zd ZdZdd„ Zdee defdd„Zde	fdd	„Z
ddd„Zededefdd„ƒZd
S )ÚAbstractHealthCheckPolicyz'
    Abstract health check policy.
    c                 C   s
   i | _ d S ©N)Ú_clientsr2   r   r   r   r!   ~   s   
z"AbstractHealthCheckPolicy.__init__rF   r   c                 ƒ   sh   �dt f‡ ‡fdd„‰tj‡fdd„|D ƒddiŽI dH }|D ]}t|tƒr,td	ˆ |ƒ‚|s1 d
S qdS )a  
        Execute all health checks concurrently with individual timeouts.
        Each health check runs with its own timeout, and all run in parallel.

        All exception handling is centralized here - _execute() methods just
        propagate exceptions naturally.
        rI   c                 “   s    �t jˆ | ˆ ¡| jd�I d H S )N)Útimeout)ÚasyncioÚwait_forrL   r6   )rI   )r:   r   r   r   Úexecute_with_timeoutŒ   s
   €
þz?AbstractHealthCheckPolicy.execute.<locals>.execute_with_timeoutc                    s   g | ]}ˆ |ƒ‘qS r   r   )r   Úhc)rX   r   r   Ú
<listcomp>”   s    z5AbstractHealthCheckPolicy.execute.<locals>.<listcomp>Úreturn_exceptionsTNzUnhealthy databaseF)r0   rV   ÚgatherÚ
isinstanceÚ	Exceptionr   )r   rF   r:   ÚresultsÚresultr   )r:   rX   r   r   rG   ‚   s   €
ÿþ
þz!AbstractHealthCheckPolicy.executec              	   Ã   sð   �t |ƒ}| j |¡}|du rvt|jttfƒr)|j ¡ }t|tƒ}tdi |¤Ž}nHt|jt	t
fƒrg|j ¡  ¡ }t|t	ƒ}|jj}|rc|d }t	d|j|j|jjj|jjj|jjj|jjdœ|¤Ž}ntdƒ‚tdt|jƒ› �ƒ‚|| j|< |S )a  
        Get or create a health check client for the database.

        Creates a single client instance per database that follows topology
        changes automatically. For cluster databases, the client handles
        node discovery and slot mapping internally.
        Nr   )ÚhostÚportÚdynamic_startup_nodesÚaddress_remapÚrequire_full_coverageÚretryz?Cluster client has no nodes - cannot create health check clientzUnsupported client type: r   )ÚidrT   Úgetr]   ÚclientÚ
AsyncRedisÚ	SyncRedisÚget_connection_kwargsr-   ÚAsyncRedisClusterÚSyncRedisClusterÚcopyÚstartup_nodesra   rb   Únodes_managerÚ_dynamic_startup_nodesrd   Ú_require_full_coveragerf   Ú
ValueErrorÚ	TypeErrorÚtype)r   r:   Údb_idri   Úconn_kwargsÚfiltered_kwargsrp   Ú
first_noder   r   r   rN   £   s<   €


úù
ÿ
z$AbstractHealthCheckPolicy.get_clientNc                 Ã   s>   �dd„ | j  ¡ D ƒ}|rtj|ddiŽI dH  | j  ¡  dS )rO   c                 S   s   g | ]	}t  | ¡ ¡‘qS r   )rV   Úcreate_taskÚaclose)r   ri   r   r   r   rZ   Ò   s    ÿz3AbstractHealthCheckPolicy.close.<locals>.<listcomp>r[   TN)rT   ÚvaluesrV   r\   Úclear)r   Úclose_tasksr   r   r   rP   Ð   s   €ÿzAbstractHealthCheckPolicy.closerI   c                 Ã   r8   rJ   r   rK   r   r   r   rL   Û   rM   z"AbstractHealthCheckPolicy._executerQ   )r<   r=   r>   r?   r!   r   r0   rD   rG   rC   rN   rP   r   rL   r   r   r   r   rR   y   s    !
-rR   c                   @   ó"   e Zd ZdZdedefdd„ZdS )ÚHealthyAllPolicyzM
    Policy that returns True if all health check probes are successful.
    rI   r   c                 Ã   sd   �|   |¡I dH }|j}t|ƒD ]}| ||¡I dH }|s  dS ||d k r/t |j¡I dH  qdS )úŠ
        Executes health check against given database.

        Uses a single client that handles topology changes automatically.
        NFé   T)rN   r3   Úranger;   rV   Úsleepr5   )r   rI   r:   ri   ÚprobesÚattemptr`   r   r   r   rL   è   s   €€zHealthyAllPolicy._executeN©r<   r=   r>   r?   r0   rD   rL   r   r   r   r   r�   ã   ó    r�   c                   @   r€   )ÚHealthyMajorityPolicya3  
    Policy that returns True if a majority of health check probes are successful.

    Majority means more than half must pass:
    - 3 probes: need 2+ to pass (1 failure allowed)
    - 4 probes: need 3+ to pass (1 failure allowed, tie = unhealthy)
    - 5 probes: need 3+ to pass (2 failures allowed)
    rI   r   c           
      Ã   sÈ   �|j }|d d }|  |¡I dH }d}t|ƒD ]I}z| ||¡I dH }|s2|d8 }|dk r2W  dS W n tyQ }	 z|	}|d8 }|dk rG|‚W Y d}	~	nd}	~	ww ||d k rat |j¡I dH  qdS )r‚   rƒ   é   Nr   FT©r3   rN   r„   r;   r^   rV   r…   r5   )
r   rI   r:   r†   Úallowed_unsuccessful_probesri   Úlast_exceptionr‡   r`   Úer   r   r   rL     s2   €€ÿ€ü€zHealthyMajorityPolicy._executeNrˆ   r   r   r   r   rŠ   ü   s    	rŠ   c                   @   r€   )ÚHealthyAnyPolicyzT
    Policy that returns True if at least one health check probe is successful.
    rI   r   c           	      Ã   s    �|j }d}|  |¡I dH }t|ƒD ]7}z| ||¡I dH }|r$W  dS W n ty9 } z|}W Y d}~nd}~ww ||d k rIt |j¡I dH  q|rN|‚dS )r‚   NTrƒ   FrŒ   )	r   rI   r:   r†   rŽ   ri   r‡   r`   r�   r   r   r   rL   -  s(   €þ€ÿ€zHealthyAnyPolicy._executeNrˆ   r   r   r   r   r�   (  r‰   r�   c                   @   s   e Zd ZeZeZeZdS )ÚHealthCheckPoliciesN)	r<   r=   r>   r�   ÚHEALTHY_ALLrŠ   ÚHEALTHY_MAJORITYr�   ÚHEALTHY_ANYr   r   r   r   r‘   J  s    r‘   ÚDEFAULT_HEALTH_CHECK_POLICYc                   @   sv   e Zd Zeeefdededefdd„Ze	defdd„ƒZ
e	defd	d
„ƒZe	defdd„ƒZededefdd„ƒZdS )ÚAbstractHealthCheckr3   r5   r6   c                 C   s&   |dk rt dƒ‚|| _|| _|| _d S )Nrƒ   z*health_check_probes must be greater than 0)rt   Ú_health_check_probesÚ_health_check_delayÚ_health_check_timeout)r   r3   r5   r6   r   r   r   r!   T  s
   
zAbstractHealthCheck.__init__r   c                 C   ó   | j S rS   )r—   r2   r   r   r   r3   `  ó   z'AbstractHealthCheck.health_check_probesc                 C   rš   rS   )r˜   r2   r   r   r   r5   d  r›   z&AbstractHealthCheck.health_check_delayc                 C   rš   rS   )r™   r2   r   r   r   r6   h  r›   z(AbstractHealthCheck.health_check_timeoutr7   c                 Ã   s   �d S rS   r   r9   r   r   r   r;   l  s   €z AbstractHealthCheck.check_healthN)r<   r=   r>   ÚDEFAULT_HEALTH_CHECK_PROBESÚDEFAULT_HEALTH_CHECK_DELAYÚDEFAULT_HEALTH_CHECK_TIMEOUTrA   rB   r!   r@   r3   r5   r6   r   rC   rD   r;   r   r   r   r   r–   S  s&    üþý
ür–   c                   @   r€   )ÚPingHealthCheckz-
    Health check based on PING command.
    r7   r   c                 Ã   sJ   �t |tƒr| d¡I d H S | ¡ }|D ]}|j d¡I d H s" dS qdS )NÚPINGFT)r]   rj   Úexecute_commandÚ	get_nodesÚredis_connection)r   r:   r7   Ú	all_nodesÚnoder   r   r   r;   v  s   €
ÿzPingHealthCheck.check_healthN)r<   r=   r>   r?   rC   rD   r;   r   r   r   r   rŸ   q  r‰   rŸ   c                       s¶   e Zd ZdZdeeddddddddeeefde	de	de
deeeef  d	ed
ee dee deeeef  dee dee dee de	de
de
f‡ fdd„Zdedefdd„Z‡  ZS )ÚLagAwareHealthCheckz�
    Health check available for Redis Enterprise deployments.
    Verify via REST API that the database is healthy based on different lags.
    iã$  NTÚrest_api_portÚlag_aware_toleranceÚhttp_timeoutÚ
auth_basicÚ
verify_tlsÚca_fileÚca_pathÚca_dataÚclient_cert_fileÚclient_key_fileÚclient_key_passwordr3   r5   r6   c                    sN   t t||ttƒ dd�|||||	|
|d�
ƒ| _|| _|| _tƒ j|||d� dS )a¨  
        Initialize LagAwareHealthCheck with the specified parameters.

        Args:
            rest_api_port: Port number for Redis Enterprise REST API (default: 9443)
            lag_aware_tolerance: Tolerance in lag between databases in MS (default: 100)
            http_timeout: Request timeout in seconds (default: DEFAULT_TIMEOUT)
            auth_basic: Tuple of (username, password) for basic authentication
            verify_tls: Whether to verify TLS certificates (default: True)
            ca_file: Path to CA certificate file for TLS verification
            ca_path: Path to CA certificates directory for TLS verification
            ca_data: CA certificate data as string or bytes
            client_cert_file: Path to client certificate file for mutual TLS
            client_key_file: Path to client private key file for mutual TLS
            client_key_password: Password for encrypted client private key
        r   )Úretries)
rU   rª   rf   r«   r¬   r­   r®   r¯   r°   r±   )r3   r5   r6   N)	r   r   r   r   Ú_http_clientÚ_rest_api_portÚ_lag_aware_toleranceÚsuperr!   )r   r§   r¨   r©   rª   r«   r¬   r­   r®   r¯   r°   r±   r3   r5   r6   ©Ú	__class__r   r   r!   ‰  s*   $öÿ
ýzLagAwareHealthCheck.__init__r7   r   c           
      Ã   s  �|j du r
tdƒ‚t|jttfƒr|j ¡ d }n|j ¡ d j}|j › d| j	› �}|| j
j_d}| j
 d¡I dH D ]"}|d D ]}|d |krM|} n|d	 D ]
}||kr[|} nqQqAq;|du rkt d
¡ tdƒ‚d|d › d| j› �}	| j
j|	dd�I dH  dS )a  
        Check database health via Redis Enterprise REST API.

        Note: The client parameter is not used for this health check as it
        relies on the REST API instead of Redis protocol. The client is
        accepted for interface compatibility.
        Nz[Database health check url is not set. Please check DatabaseConfig for the current database.ra   r   ú:z/v1/bdbsÚ	endpointsÚdns_nameÚaddrz8LagAwareHealthCheck failed: Couldn't find a matching bdbzCould not find a matching bdbz	/v1/bdbs/Úuidz=/availability?extend_check=lag&availability_lag_tolerance_ms=F)Úexpect_jsonT)Úhealth_check_urlrt   r]   ri   rj   rk   rl   r¢   ra   r´   r³   Úbase_urlrh   ÚloggerÚwarningrµ   )
r   r:   r7   Údb_hostrÀ   Úmatching_bdbÚbdbÚendpointr¼   Úurlr   r   r   r;   Ã  s>   €
ÿ
þ€
ÿÿz LagAwareHealthCheck.check_health)r<   r=   r>   r?   ÚDEFAULT_LAG_AWARE_TOLERANCEr   rœ   r�   rž   rA   rB   r   r   ÚstrrD   r	   Úbytesr!   rC   r;   Ú__classcell__r   r   r·   r   r¦   ƒ  s\    îþýüûúø	÷
öôóòðïî:r¦   )=rV   r   ÚloggingÚabcr   r   Úenumr   Útypingr   r   r   r   r	   Úredis.asyncior
   rj   Úredis.asyncio.clusterr   rm   Úredis.asyncio.http.http_clientr   r   Úredis.backoffr   Úredis.clientrk   Úredis.clusterrn   Úredis.http.http_clientr   Úredis.multidb.exceptionr   Úredis.retryr   rC   r"   r&   Údictr-   rœ   ÚDEFAULT_HEALTH_CHECK_INTERVALrž   r�   rÈ   Ú	getLoggerr<   rÁ   r0   rE   rR   r�   rŠ   r�   r‘   r’   r•   Ú__annotations__r–   rŸ   r¦   r   r   r   r   Ú<module>   sF   
 
'j,"