U
    	d57                     @   s   d dl Z d dlZd dlmZ d dlmZ d dlmZ d dlm	Z	m
Z
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ZG dd de
ZG dd deZdS )    N)Optional)Redis)SentinelCommands)
ConnectionConnectionPoolSSLConnection)ConnectionErrorReadOnlyErrorResponseErrorTimeoutError)str_if_bytesc                   @   s   e Zd ZdS )MasterNotFoundErrorN__name__
__module____qualname__ r   r   K/var/www/html/myproject/myenv/lib/python3.8/site-packages/redis/sentinel.pyr      s   r   c                   @   s   e Zd ZdS )SlaveNotFoundErrorNr   r   r   r   r   r      s   r   c                       s^   e Zd Z fddZdd Z fddZdd Zd	d
 Zdddee	 d fddZ
  ZS )SentinelManagedConnectionc                    s   | d| _t jf | d S )Nconnection_pool)popr   super__init__)selfkwargs	__class__r   r   r      s    z"SentinelManagedConnection.__init__c                 C   sD   | j }t| j d|j d}| jr@d| j d| j }|| }|S )N	<service=z%s>z,host=z,port=)r   typer   service_namehostport)r   poolsZ	host_infor   r   r   __repr__   s    z"SentinelManagedConnection.__repr__c                    sD   |\| _ | _t   | jjr@| d t|  dkr@t	d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              	   C   sf   | j r
d S | jjr$| | j  n>| j D ].}z| |W   S  tk
rZ   Y q.Y q.X q.td S N)_sockr   	is_masterr*   get_master_addressrotate_slavesr   r   )r   slaver   r   r   _connect_retry)   s    z(SentinelManagedConnection._connect_retryc                 C   s   | j | jdd S )Nc                 S   s   d S r+   r   )errorr   r   r   <lambda>7       z3SentinelManagedConnection.connect.<locals>.<lambda>)retryZcall_with_retryr1   r   r   r   r   r&   6   s    z!SentinelManagedConnection.connectF)disconnect_on_errorc                   sF   zt  j||dW S  tk
r@   | jjr:|   td Y nX d S )N)disable_decodingr7   z"The previous master is now a slave)r   r(   r	   r   r-   
disconnectr   )r   r8   r7   r   r   r   r(   9   s    z'SentinelManagedConnection.read_response)F)r   r   r   r   r%   r*   r1   r&   r   boolr(   __classcell__r   r   r   r   r      s    r   c                   @   s   e Zd ZdS )SentinelManagedSSLConnectionNr   r   r   r   r   r<   M   s   r<   c                   @   s,   e Zd Zdd Zdd Zdd Zdd Zd	S )
SentinelConnectionPoolProxyc                 C   s0   t || _|| _|| _|| _|| _|   d S r+   )weakrefrefconnection_pool_refr-   r'   r    sentinel_managerreset)r   r   r-   r'   r    rA   r   r   r   r   R   s    z$SentinelConnectionPoolProxy.__init__c                 C   s   d | _ d | _d S r+   )master_addressslave_rr_counterr6   r   r   r   rB   a   s    z!SentinelConnectionPoolProxy.resetc                 C   sD   | j | j}| jr@| j|kr@|| _|  }|d k	r@|jdd |S )NF)Zinuse_connections)rA   discover_masterr    r-   rC   r@   r9   )r   rC   r   r   r   r   r.   e   s    z.SentinelConnectionPoolProxy.get_master_addressc                 c   s   | j | j}|rh| jd kr2tdt|d | _tt|D ](}| jd t| | _|| j }|V  q>z|  V  W n t	k
r   Y nX t
d| jd S )Nr      zNo slave found for )rA   discover_slavesr    rD   randomrandintlenranger.   r   r   )r   slaves_r0   r   r   r   r/   p   s    

z)SentinelConnectionPoolProxy.rotate_slavesN)r   r   r   r   rB   r.   r/   r   r   r   r   r=   Q   s   r=   c                       s\   e Zd ZdZ fddZdd Z fddZedd	 Z fd
dZ	dd Z
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                    s~   | d|ddrtnt|d< |dd| _|dd| _t| | j| j||d| _t j	f | | j| j
d< || _|| _d S )	NZconnection_classsslFr-   Tr'   )r   r-   r'   r    rA   r   )getr   r<   r   r-   r'   r=   proxyr   r   connection_kwargsr    rA   )r   r    rA   r   r   r   r   r      s&    
zSentinelConnectionPool.__init__c                 C   s,   | j r
dnd}t| j d| j d| dS )NZmasterr0   r   ())r-   r   r   r    )r   Zroler   r   r   r%      s    zSentinelConnectionPool.__repr__c                    s   t    | j  d S r+   )r   rB   rQ   r6   r   r   r   rB      s    
zSentinelConnectionPool.resetc                 C   s   | j jS r+   )rQ   rC   r6   r   r   r   rC      s    z%SentinelConnectionPool.master_addressc                    s4   | j  p| j o| j|j|jfk}t }|o2||S r+   )r-   rC   r!   r"   r   owns_connection)r   
connectioncheckparentr   r   r   rU      s
    z&SentinelConnectionPool.owns_connectionc                 C   s
   | j  S r+   )rQ   r.   r6   r   r   r   r.      s    z)SentinelConnectionPool.get_master_addressc                 C   s
   | j  S )zRound-robin slave balancer)rQ   r/   r6   r   r   r   r/      s    z$SentinelConnectionPool.rotate_slaves)r   r   r   __doc__r   r%   rB   propertyrC   rU   r.   r/   r;   r   r   r   r   rN      s   
rN   c                   @   sf   e Zd ZdZdddZdd Zdd	 Zd
d Zdd Zdd Z	dd Z
eefddZeefddZdS )Sentinelar  
    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)
    >>> master.set('foo', 'bar')
    >>> slave = sentinel.slave_for('mymaster', socket_timeout=0.1)
    >>> 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                    sD   |d k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 ||f jqS r   )r   sentinel_kwargs)r]   hostnamer"   r6   r   r   
<listcomp>   s   z%Sentinel.__init__.<locals>.<listcomp>)itemsra   	sentinelsmin_other_sentinelsrR   )r   re   rf   ra   rR   r   r6   r   r      s    	
zSentinel.__init__c                 O   s\   t |dd}d| kr&|d |r@t| jj|| n| jD ]}|j|| qFd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.
        onceFT)r:   rP   keysr   rH   choicere   execute_command)r   argsr   rg   sentinelr   r   r   rj      s    

zSentinel.execute_commandc                 C   s@   g }| j D ]}|d|jj q
t| j dd| dS )Nz{host}:{port}z<sentinels=[,z]>)re   append
format_mapr   rR   r   r   join)r   Zsentinel_addressesrl   r   r   r   r%      s    
zSentinel.__repr__c                 C   s2   |d r|d s|d rdS |d | j k r.dS dS )Nr-   is_sdownis_odownFznum-other-sentinelsT)rf   )r   stater    r   r   r   check_master_state  s
    zSentinel.check_master_statec           	      C   s   t  }t| jD ]\}}z| }W nB ttfk
rf } z || d| W Y qW 5 d}~X Y nX ||}|r| ||r|| jd  | jd< | j|< |d |d f  S qd}t	|dkrdd
| }td	|| dS )
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.
        z - Nr   ipr"    z : z, zNo master found for )list	enumeratere   Zsentinel_mastersr   r   rn   rP   rt   rJ   rp   r   )	r   r    Zcollected_errorsZsentinel_norl   Zmastersers   
error_infor   r   r   rE     s"    
zSentinel.discover_masterc                 C   s:   g }|D ],}|d s|d rq| |d |d f q|S )z1Remove slaves that are in an ODOWN or SDOWN staterr   rq   ru   r"   )rn   )r   rL   Zslaves_aliver0   r   r   r   filter_slaves*  s    zSentinel.filter_slavesc                 C   sT   | j D ]H}z||}W n tttfk
r6   Y qY nX | |}|r|  S qg S )z;Returns a list of alive slaves for service ``service_name``)re   Zsentinel_slavesr   r
   r   r{   )r   r    rl   rL   r   r   r   rG   3  s    



zSentinel.discover_slavesc                 K   s0   d|d< t | j}|| |||| f|dS )a  
        Returns a redis client instance for the ``service_name`` master.

        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.
        Tr-   r   dictrR   updater   r    Zredis_classZconnection_pool_classr   rR   r   r   r   
master_for?  s    

 zSentinel.master_forc                 K   s0   d|d< t | j}|| |||| f|dS )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.
        Fr-   r|   r}   r   r   r   r   	slave_fore  s    

 zSentinel.slave_for)r   N)r   r   r   rY   r   rj   r%   rt   rE   r{   rG   r   rN   r   r   r   r   r   r   r[      s      
	
)r[   )rH   r>   typingr   Zredis.clientr   Zredis.commandsr   Zredis.connectionr   r   r   Zredis.exceptionsr   r	   r
   r   Zredis.utilsr   r   r   r   r<   r=   rN   r[   r   r   r   r   <module>   s   908