o
    LjJ                     @   s   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 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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Union)Redis)SentinelCommands)
ConnectionConnectionPoolSSLConnection)ConnectionErrorReadOnlyErrorResponseErrorTimeoutError)SENTINELc                   @      e Zd ZdS )MasterNotFoundErrorN__name__
__module____qualname__ r   r   L/home/djax/ivt_ai_plugin/venv/lib/python3.10/site-packages/redis/sentinel.pyr          r   c                   @   r   )SlaveNotFoundErrorNr   r   r   r   r   r      r   r   c                	       st   e Zd Z fddZdd Zdd Zdd Zd	d
 Z	dedddde	e
ef 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   sR   | j }dt| j dt| j d|j d}| jr'd| j d| j }|| }|S )N<.	(service=z%s)>z,host=z,port=)r   typer   r   service_namehostport)r   pools	host_infor   r   r   __repr__!   s   z"SentinelManagedConnection.__repr__c                 C   s"   |\| _ | _| j| jjdd d S )NF)check_healthretry_socket_connect)r&   r'   connect_check_healthr   check_connection)r   addressr   r   r   
connect_to,   s
   
z$SentinelManagedConnection.connect_toc              	   C   s\   | j rd S | jjr| | j  d S | j D ]}z| |W   S  ty+   Y qw tN)_sockr   	is_masterr1   get_master_addressrotate_slavesr	   r   )r   slaver   r   r   _connect_retry4   s   z(SentinelManagedConnection._connect_retryc                 C   s   | j | jdd S )Nc                 S   s   d S r2   r   )errorr   r   r   <lambda>B   s    z3SentinelManagedConnection.connect.<locals>.<lambda>)retrycall_with_retryr8   r   r   r   r   connectA   s   z!SentinelManagedConnection.connectF)timeoutdisconnect_on_errorpush_requestr?   r@   rA   c                   s@   zt  j||||dW S  ty   | jjr|   td w )N)disable_decodingr?   r@   rA   z"The previous master is now a slave)r   read_responser
   r   r4   
disconnectr	   )r   rB   r?   r@   rA   r   r   r   rC   D   s   z'SentinelManagedConnection.read_response)F)r   r   r   r   r+   r1   r8   r>   r   r   floatobjectr   boolrC   __classcell__r   r   r   r   r      s$    
r   c                   @   r   )SentinelManagedSSLConnectionNr   r   r   r   r   rI   _   r   rI   c                   @   s4   e Zd Zdd Zdd Zdd Zdd Zd	d
 ZdS )SentinelConnectionPoolProxyc                 C   s0   t || _|| _|| _|| _|| _|   d S r2   )weakrefrefconnection_pool_refr4   r/   r%   sentinel_managerreset)r   r   r4   r/   r%   rN   r   r   r   r   d   s   z$SentinelConnectionPoolProxy.__init__c                 C   s   d | _ d | _d S r2   )master_addressslave_rr_counterr=   r   r   r   rO   s   s   
z!SentinelConnectionPoolProxy.resetc                 C   sD   | j | j}| jr | j|kr || _|  }|d ur |jdd |S )NF)inuse_connections)rN   discover_masterr%   r4   rP   rM   rD   )r   rP   r   r   r   r   r5   w   s   z.SentinelConnectionPoolProxy.get_master_addressc                 c   s    | j | j}|r5| jd u rtdt|d | _tt|D ]}| jd t| | _|| j }|V  q z|  V  W n	 t	yE   Y nw t
d| j)Nr      zNo slave found for )rN   discover_slavesr%   rQ   randomrandintlenranger5   r   r   )r   slaves_r7   r   r   r   r6      s   

z)SentinelConnectionPoolProxy.rotate_slavesc                 C      |   S zRound-robin replica balancer.

        This is an alias for :py:meth:`rotate_slaves`,
        using the preferred Redis 5.0+ terminology.
        r6   r=   r   r   r   rotate_replicas      z+SentinelConnectionPoolProxy.rotate_replicasN)r   r   r   r   rO   r5   r6   r_   r   r   r   r   rJ   c   s    rJ   c                       sd   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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	d	i | | j| j
d< || _|| _d S )
Nconnection_classsslFr4   Tr/   )r   r4   r/   r%   rN   r   r   )getr   rI   r   r4   r/   rJ   proxyr   r   connection_kwargsr%   rN   )r   r%   rN   r   r   r   r   r      s&   

zSentinelConnectionPool.__init__c              	   C   s:   | j rdnd}dt| j dt| j d| j d| d	S )Nmasterr7   r!   r"   r#   (z))>)r4   r$   r   r   r%   )r   roler   r   r   r+      s   zSentinelConnectionPool.__repr__c                    s   t    | j  d S r2   )r   rO   re   r=   r   r   r   rO      s   
zSentinelConnectionPool.resetc                 C   s   | j jS r2   )re   rP   r=   r   r   r   rP      s   z%SentinelConnectionPool.master_addressc                    s4   | j  p| j o| j|j|jfk}t }|o||S r2   )r4   rP   r&   r'   r   owns_connection)r   
connectioncheckparentr   r   r   rj      s
   z&SentinelConnectionPool.owns_connectionc                 C   
   | j  S r2   )re   r5   r=   r   r   r   r5      s   
z)SentinelConnectionPool.get_master_addressc                 C   rn   )zRound-robin slave balancer)re   r6   r=   r   r   r   r6      s   
z$SentinelConnectionPool.rotate_slavesc                 C   r\   r]   r^   r=   r   r   r   r_      r`   z&SentinelConnectionPool.rotate_replicas)r   r   r   __doc__r   r+   rO   propertyrP   rj   r5   r6   r_   rH   r   r   r   r   ra      s    
ra   c                   @   s   e Zd ZdZ			d#ddZdd Zdd	 Zd$ddZdd Z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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                    sJ   |d u rdd |  D }| _ fdd|D  _| _| _| _d S )Nc                 S   s    i | ]\}}| d r||qS )socket_)
startswith).0kvr   r   r   
<dictcomp>  s
    z%Sentinel.__init__.<locals>.<dictcomp>c                    s$   g | ]\}}t ||fi  jqS r   )r   sentinel_kwargs)rt   hostnamer'   r=   r   r   
<listcomp>  s    z%Sentinel.__init__.<locals>.<listcomp>)itemsrx   	sentinelsmin_other_sentinelsrf   _force_master_ip)r   r|   r}   rx   force_master_iprf   r   r=   r   r      s   


zSentinel.__init__c                 O   s   t |dd}t |dd}|r)t| jj|i |}|r#|gS |r'dS dS g }| jD ]}||j|i | q.|r@|S t|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.
        onceFreturn_responsesT)rG   r   rV   choicer|   execute_commandappendall)r   argsr   r   r   response	responsessentinelr   r   r   r     s   
zSentinel.execute_commandc                 C   sN   g }| j D ]}|d|jj qdt| j dt| j dd| dS )Nz{host}:{port}r!   r"   z(sentinels=[,z])>)	r|   r   
format_mapr   rf   r$   r   r   join)r   sentinel_addressesr   r   r   r   r+   1  s   
zSentinel.__repr__returnc                 C   sX   d}| j D ] }z|  W q ty% } z|du r|}W Y d}~qd}~ww |r*|dS )au  
        Close all sentinel clients created by this Sentinel and their
        connection pools.

        Each client is closed independently: if one raises, the remaining
        clients are still closed and the first error is re-raised afterwards.

        Clients returned by ``master_for``/``slave_for`` are owned by the
        caller and are not closed here.
        N)r|   close	Exception)r   excr   er   r   r   r   <  s   
zSentinel.closec                 C   s   | S r2   r   r=   r   r   r   	__enter__Q  s   zSentinel.__enter__c                 C   s   |    d S r2   )r   )r   exc_type	exc_value	tracebackr   r   r   __exit__T  s   zSentinel.__exit__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)r}   )r   stater%   r   r   r   check_master_stateW  s
   zSentinel.check_master_statec           
      C   s   t  }t| jD ]X\}}z| }W n ttfy0 } z|| d| W Y d}~qd}~ww ||}|r`| ||r`|| jd | jd< | j|< | j	durT| j	n|d }||d f  S qd}	t
|dkrqd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.
        z - Nr   ipr'    z : z, zNo master found for )list	enumerater|   sentinel_mastersr	   r   r   rd   r   r~   rX   r   r   )
r   r%   collected_errorssentinel_nor   mastersr   r   r   
error_infor   r   r   rS   _  s0   

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 stater   r   r   r'   )r   )r   rZ   slaves_aliver7   r   r   r   filter_slaves  s   zSentinel.filter_slavesc                 C   
   |  |S )zRemove replicas that are in an ODOWN or SDOWN state.

        This is an alias for :py:meth:`filter_slaves`,
        using the preferred Redis 5.0+ terminology.
        )r   )r   replicasr   r   r   filter_replicas     
zSentinel.filter_replicasc                 C   sN   | j D ]!}z||}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``)r|   sentinel_slavesr	   r   r   r   )r   r%   r   rZ   r   r   r   rU     s   

zSentinel.discover_slavesc                 C   r   )zReturns a list of alive replicas for service ``service_name``.

        This is an alias for :py:meth:`discover_slaves`,
        using the preferred Redis 5.0+ terminology.
        )rU   )r   r%   r   r   r   discover_replicas  r   zSentinel.discover_replicasc                 K   4   d|d< t | j}|| |||| fi |S )a9  
        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.

        HIMPORT note: the returned client exposes the HIMPORT command family
        (``himport_prepare``, ``himport_set``, ``himport_discard``,
        ``himport_discard_all``). Fieldsets are declared at runtime with
        ``himport_prepare`` on the client and live on that client's shared registry,
        so they survive Sentinel failover automatically: the pool re-points to the
        new master and the fieldset is re-prepared lazily on the next
        ``himport_set``. Each call to the current method returns a *new* client with
        its *own* empty registry, so call ``himport_prepare`` on the long-lived client
        you reuse rather than creating a fresh one per operation; otherwise ``himport_set``
        fails with ``no such fieldset``. (``himport_set`` is a write and is served by
        the master.)
        Tr4   dictrf   update	from_poolr   r%   redis_classconnection_pool_classr   rf   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.

        HIMPORT note: the returned client exposes the HIMPORT command family
        (``himport_prepare``, ``himport_set``, ``himport_discard``,
        ``himport_discard_all``). Fieldsets are declared at runtime with
        ``himport_prepare`` on the client and live on that client's shared registry,
        so they survive Sentinel failover automatically: the pool re-points to the
        new master and the fieldset is re-prepared lazily on the next
        ``himport_set``. Each call to current method returns a *new* client with
        its *own* empty registry, so call ``himport_prepare`` on the long-lived client
        you reuse rather than creating a fresh one per operation; otherwise ``himport_set``
        fails with ``no such fieldset``. (``himport_set`` is a write and is served by
        the master.)
        Fr4   r   r   r   r   r   	slave_for  s   $

zSentinel.slave_forc                 K   s   | j |f||d|S )z
        Returns redis client instance for the ``service_name`` replica(s).

        This is an alias for :py:meth:`slave_for`,
        using the preferred Redis 5.0+ terminology.
        )r   r   )r   )r   r%   r   r   r   r   r   r   replica_for  s   zSentinel.replica_for)r   NN)r   N)r   r   r   ro   r   r   r+   r   r   r   r   rS   r   r   rU   r   r   ra   r   r   r   r   r   r   r   rq      s4    

#	
5
.rq   )rV   rK   typingr   r   redis.clientr   redis.commandsr   redis.connectionr   r   r   redis.exceptionsr	   r
   r   r   redis.utilsr   r   r   ReplicaNotFoundErrorr   rI   rJ   ra   rq   r   r   r   r   <module>   s     C8E