o
    ;h,9                     @   s   d dl Z d dlZd dlZd dlmZmZmZmZmZm	Z	m
Z
 d dlmZ d dlmZmZmZmZ d dlmZ d dlmZmZmZmZ d dlmZ G dd	 d	eZG d
d deZG dd deZG dd deeZG dd deZG dd deZ dS )    N)AsyncIteratorIterableMappingOptionalSequenceTupleType)Redis)
ConnectionConnectionPool
EncodableTSSLConnection)AsyncSentinelCommands)ConnectionErrorReadOnlyErrorResponseErrorTimeoutError)str_if_bytesc                   @      e Zd ZdS )MasterNotFoundErrorN__name__
__module____qualname__ r   r   I/var/www/html/venv/lib/python3.10/site-packages/redis/asyncio/sentinel.pyr          r   c                   @   r   )SlaveNotFoundErrorNr   r   r   r   r   r      r   r   c                       sx   e Zd Z fddZdd Z fddZdd Zd	d
 Z		dddddede	e
 de	e
 de	e f fddZ  ZS )SentinelManagedConnectionc                    s"   | d| _t jdi | d S )Nconnection_poolr   )popr   super__init__)selfkwargs	__class__r   r   r"      s   z"SentinelManagedConnection.__init__c                 C   sB   d| j j d| j j }| jrd| j d| j }||7 }|d S )N<.z,host=z,port=z)>)r&   r   r   hostport)r#   sZ	host_infor   r   r   __repr__   s
   z"SentinelManagedConnection.__repr__c                    s\   |\| _ | _t  I d H  | jjr*| dI d H  t|  I d H dkr,t	dd S d S )NZPINGZPONGzPING failed)
r)   r*   r!   connectr   check_connectionZsend_commandr   read_responser   )r#   addressr%   r   r   
connect_to&   s   z$SentinelManagedConnection.connect_toc              	      sz   | j rd S | jjr| | j I d H I d H  d S | j 2 z3 d H W }z| |I d H W   S  ty9   Y qw 6 tN)_readerr   	is_masterr1   get_master_addressrotate_slavesr   r   )r#   slaver   r   r   _connect_retry.   s    z(SentinelManagedConnection._connect_retryc                    s   | j | jdd I d H S )Nc                 S   s
   t dS )Nr   )asynciosleep)errorr   r   r   <lambda>>   s   
 z3SentinelManagedConnection.connect.<locals>.<lambda>)retryZcall_with_retryr8   r#   r   r   r   r-   ;   s
   
z!SentinelManagedConnection.connectFNT)disconnect_on_errorpush_requestdisable_decodingtimeoutr?   r@   c                   sN   zt  j||||dI d H W S  ty&   | jjr%|  I d H  td w )N)rA   rB   r?   r@   z"The previous master is now a slave)r!   r/   r   r   r4   
disconnectr   )r#   rA   rB   r?   r@   r%   r   r   r/   A   s   z'SentinelManagedConnection.read_response)FN)r   r   r   r"   r,   r1   r8   r-   boolr   floatr/   __classcell__r   r   r%   r   r      s(    r   c                   @   r   )SentinelManagedSSLConnectionNr   r   r   r   r   rG   \   r   rG   c                       s\   e Zd ZdZ fddZdd Z fddZdef fd	d
Zdd Z	de
fddZ  ZS )SentinelConnectionPoolz
    Sentinel backed connection pool.

    If ``check_connection`` flag is set to True, SentinelManagedConnection
    sends a PING command right after establishing the connection.
    c                    sz   | d|ddrtnt|d< |dd| _|dd| _t jdi | t	| | j
d< || _|| _d | _d | _d S )	NZconnection_classsslFr4   Tr.   r   r   )getr    rG   r   r4   r.   r!   r"   weakrefproxyconnection_kwargsservice_namesentinel_managermaster_addressslave_rr_counter)r#   rN   rO   r$   r%   r   r   r"   h   s   

zSentinelConnectionPool.__init__c              	   C   s2   d| j j d| j j d| j d| jrdpd d	S )Nr'   r(   z	(service=(Zmasterr7   z))>)r&   r   r   rN   r4   r>   r   r   r   r,   z   s   zSentinelConnectionPool.__repr__c                    s   t    d | _d | _d S r2   )r!   resetrP   rQ   r>   r%   r   r   rS      s   

zSentinelConnectionPool.reset
connectionc                    s0   | j  p| j o| j|j|jfk}|ot |S r2   )r4   rP   r)   r*   r!   owns_connection)r#   rT   checkr%   r   r   rU      s   z&SentinelConnectionPool.owns_connectionc                    sB   | j | jI d H }| jr| j|kr|| _| jddI d H  |S )NF)Zinuse_connections)rO   discover_masterrN   r4   rP   rC   )r#   rP   r   r   r   r5      s   
z)SentinelConnectionPool.get_master_addressreturnc                 C  s   | j | jI dH }|r8| jdu rtdt|d | _tt|D ]}| jd t| | _|| j }|V  q#z
|  I dH V  W n	 t	yK   Y nw t
d| j)zRound-robin slave balancerNr      zNo slave found for )rO   discover_slavesrN   rQ   randomrandintlenranger5   r   r   )r#   slaves_r7   r   r   r   r6      s   

z$SentinelConnectionPool.rotate_slaves)r   r   r   __doc__r"   r,   rS   r
   rU   r5   r   r6   rF   r   r   r%   r   rH   `   s    
rH   c                   @   s   e Zd ZdZ			dddZdd Zdd	 Zd
edede	fddZ
defddZdee deeeef  fddZdedeeeef  fddZeefdedee dee fddZeefdedee dee fddZdS )Sentinela~  
    Redis Sentinel cluster client

    >>> from redis.sentinel import Sentinel
    >>> sentinel = Sentinel([('localhost', 26379)], socket_timeout=0.1)
    >>> master = sentinel.master_for('mymaster', socket_timeout=0.1)
    >>> await master.set('foo', 'bar')
    >>> slave = sentinel.slave_for('mymaster', socket_timeout=0.1)
    >>> await slave.get('foo')
    b'bar'

    ``sentinels`` is a list of sentinel nodes. Each node is represented by
    a pair (hostname, port).

    ``min_other_sentinels`` defined a minimum number of peers for a sentinel.
    When querying a sentinel, if it doesn't meet this threshold, responses
    from that sentinel won't be considered valid.

    ``sentinel_kwargs`` is a dictionary of connection arguments used when
    connecting to sentinel instances. Any argument that can be passed to
    a normal Redis connection can be specified here. If ``sentinel_kwargs`` is
    not specified, any socket_timeout and socket_keepalive options specified
    in ``connection_kwargs`` will be used.

    ``connection_kwargs`` are keyword arguments that will be used when
    establishing a connection to a Redis server.
    r   Nc                    sJ   |d u rdd |  D }| _ fdd|D  _| _| _| _d S )Nc                 S   s    i | ]\}}| d r||qS )Zsocket_)
startswith).0kvr   r   r   
<dictcomp>   s
    z%Sentinel.__init__.<locals>.<dictcomp>c                    s&   g | ]\}}t d||d  jqS ))r)   r*   r   )r	   sentinel_kwargs)rd   hostnamer*   r>   r   r   
<listcomp>   s    z%Sentinel.__init__.<locals>.<listcomp>)itemsrh   	sentinelsmin_other_sentinelsrM   _force_master_ip)r#   rl   rm   rh   Zforce_master_iprM   r   r>   r   r"      s   


zSentinel.__init__c                    sx   t dd}d v rd |r't| jj i I dH  dS  fdd| jD }tj	| I dH  dS )z
        Execute Sentinel command in sentinel nodes.
        once - If set to True, then execute the resulting command on a single
               node at random, rather than across the entire sentinel cluster.
        onceFNc                    s"   g | ]}t |j i qS r   )r9   Taskexecute_command)rd   sentinelargsr$   r   r   rj      s    z,Sentinel.execute_command.<locals>.<listcomp>T)
rD   rJ   keysr    r[   choicerl   rq   r9   Zgather)r#   rt   r$   ro   tasksr   rs   r   rq      s   
zSentinel.execute_commandc                 C   sX   g }| j D ]}||jjd  d|jjd   qd| j d| jj dd| dS )	Nr)   :r*   r'   r(   z(sentinels=[,z])>)rl   appendr   rM   r&   r   join)r#   Zsentinel_addressesrr   r   r   r   r,      s   

zSentinel.__repr__staterN   rX   c                 C   s2   |d r|d s|d rdS |d | j k rdS dS )Nr4   is_sdownis_odownFznum-other-sentinelsT)rm   )r#   r|   rN   r   r   r   check_master_state   s
   zSentinel.check_master_statec           
         s   t  }t| jD ][\}}z	| I dH }W n ttfy4 } z|| d| W Y d}~q	d}~ww ||}|rd| ||rd|| jd | jd< | j|< | j	durX| j	n|d }||d f  S q	d}	t
|dkrudd| }	td	||	 )
z
        Asks sentinel servers for the Redis master's address corresponding
        to the service labeled ``service_name``.

        Returns a pair (address, port) or raises MasterNotFoundError if no
        master is found.
        Nz - r   ipr*    z : z, zNo master found for )list	enumeraterl   Zsentinel_mastersr   r   rz   rJ   r   rn   r]   r{   r   )
r#   rN   Zcollected_errorsZsentinel_norr   Zmasterser|   r   
error_infor   r   r   rW     s2   

zSentinel.discover_masterr_   c                 C   s:   g }|D ]}|d s|d rq| |d |d f q|S )z1Remove slaves that are in an ODOWN or SDOWN stater~   r}   r   r*   )rz   )r#   r_   Zslaves_aliver7   r   r   r   filter_slaves'  s   zSentinel.filter_slavesc                    sV   | j D ]$}z
||I dH }W n tttfy   Y qw | |}|r(|  S qg S )z;Returns a list of alive slaves for service ``service_name``N)rl   Zsentinel_slavesr   r   r   r   )r#   rN   rr   r_   r   r   r   rZ   2  s   

zSentinel.discover_slavesredis_classconnection_pool_classc                 K   8   d|d< t | j}|| ||| fi |}||S )a  
        Returns a redis client instance for the ``service_name`` master.
        Sentinel client will detect failover and reconnect Redis clients
        automatically.

        A :py:class:`~redis.sentinel.SentinelConnectionPool` class is
        used to retrieve the master's address before establishing a new
        connection.

        NOTE: If the master's address has changed, any cached connections to
        the old master are closed.

        By default clients will be a :py:class:`~redis.Redis` instance.
        Specify a different class to the ``redis_class`` argument if you
        desire something different.

        The ``connection_pool_class`` specifies the connection pool to
        use.  The :py:class:`~redis.sentinel.SentinelConnectionPool`
        will be used by default.

        All other keyword arguments are merged with any connection_kwargs
        passed to this class and passed to the connection pool as keyword
        arguments to be used to initialize Redis connections.
        Tr4   dictrM   updateZ	from_poolr#   rN   r   r   r$   rM   r   r   r   r   
master_for@  s
   


zSentinel.master_forc                 K   r   )a  
        Returns redis client instance for the ``service_name`` slave(s).

        A SentinelConnectionPool class is used to retrieve the slave's
        address before establishing a new connection.

        By default clients will be a :py:class:`~redis.Redis` instance.
        Specify a different class to the ``redis_class`` argument if you
        desire something different.

        The ``connection_pool_class`` specifies the connection pool to use.
        The SentinelConnectionPool will be used by default.

        All other keyword arguments are merged with any connection_kwargs
        passed to this class and passed to the connection pool as keyword
        arguments to be used to initialize Redis connections.
        Fr4   r   r   r   r   r   	slave_forg  s
   


zSentinel.slave_for)r   NN)r   r   r   ra   r"   rq   r,   r   strrD   r   rW   r   r   r   r   r   r   rZ   r	   rH   r   r   r   r   r   r   r   rb      sL    
#


*rb   )!r9   r[   rK   typingr   r   r   r   r   r   r   Zredis.asyncio.clientr	   Zredis.asyncio.connectionr
   r   r   r   Zredis.commandsr   Zredis.exceptionsr   r   r   r   Zredis.utilsr   r   r   r   rG   rH   rb   r   r   r   r   <module>   s    $BG