U
    hs                    @   s  U d dl Z d dlZd dlZd dlZd dlZd dlZd dl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mZmZmZmZ d dlmZmZ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&m'Z' dd
l(m)Z) ddl*m+Z+ ddl,m-Z-m.Z. ddl/m0Z0m1Z1 ddl2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z: ddl;m<Z< ddl=m>Z>m?Z?m@Z@mAZAmBZBmCZCmDZDmEZEmFZF e@rd dlGZGndZGe?rd dlHZHdZIdZJdZKdZLdZMeN ZOeee&e'e%f  ePd< e?re%ZQne&ZQG dd dZRG dd dZSG dd dZTG dd deTZUG dd  d eUZVG d!d" d"eTZWG d#d$ d$eVZXG d%d& d&eUZYd'ZZd(d) Z[e\e]e]e[e[e^e\e\e[e]d*
Z_d+d, Z`ed-d.d/ZaG d0d. d.ZbG d1d2 d2ebZcdS )3    N)abstractmethod)chain)EmptyFull	LifoQueue)AnyCallableDictListOptionalTypeTypeVarUnion)parse_qsunquoteurlparse)
CacheEntryCacheEntryStatusCacheFactoryCacheFactoryInterfaceCacheInterfaceCacheKey   )Encoder_HiredisParser_RESP2Parser_RESP3Parser)TokenInterface)	NoBackoff)CredentialProvider"UsernamePasswordCredentialProvider)AfterConnectionReleasedEventEventDispatcher)AuthenticationError$AuthenticationWrongNumberOfArgsErrorChildDeadlockedErrorConnectionError	DataError
RedisErrorResponseErrorTimeoutError)Retry)	CRYPTOGRAPHY_AVAILABLEHIREDIS_AVAILABLESSL_AVAILABLEcompare_versionsdeprecated_argsensure_stringformat_error_messageget_lib_versionstr_if_bytes   *   $s   
       DefaultParserc                   @   s   e Zd ZedddZdS )HiredisRespSerializer)argsc                 G   s   g }t |d tr4t|d   |dd  }n(d|d kr\t|d  |dd  }z|t| W n0 tk
r   t	
 \}}}t||Y nX |S 2Pack a series of arguments into the Redis protocolr   r   N    )
isinstancestrtupleencodesplitappendhiredispack_command	TypeErrorsysexc_infor'   with_traceback)selfr;   output_value	traceback rP   4/tmp/pip-unpacked-wheel-4avdqdik/redis/connection.pypackL   s    "zHiredisRespSerializer.packN)__name__
__module____qualname__r
   rR   rP   rP   rP   rQ   r:   K   s   r:   c                   @   s"   e Zd ZddddZdd ZdS )PythonRespSerializerNreturnc                 C   s   || _ || _d S N)_buffer_cutoffrB   )rK   buffer_cutoffrB   rP   rP   rQ   __init__^   s    zPythonRespSerializer.__init__c              	   G   s  g }t |d tr4t|d   |dd  }n(d|d kr\t|d  |dd  }tttt| t	f}| j
}t| j|D ]|}t|}t||ks||kst |trt|tt| t	f}|| || t	}qt|tt| t	|t	f}q|| |S r<   )r?   r@   rA   rB   rC   	SYM_EMPTYjoinSYM_STARlenSYM_CRLFrZ   map
memoryview
SYM_DOLLARrD   )rK   r;   rL   Zbuffr[   argZ
arg_lengthrP   rP   rQ   rR   b   s@    "





zPythonRespSerializer.pack)rS   rT   rU   r\   rR   rP   rP   rP   rQ   rV   ]   s   rV   c                   @   s  e Zd Zedd Zedd Zedd Zedd Zed	d
 Zedd Z	edd Z
edd Zedd Zed,ddZedd Zed-ddZed.dddddZedd  Zed!d" Zeeeeeef eeef f d#d$d%Zeed&d'd(Zed)d* Zd+S )/ConnectionInterfacec                 C   s   d S rY   rP   rK   rP   rP   rQ   repr_pieces   s    zConnectionInterface.repr_piecesc                 C   s   d S rY   rP   rK   callbackrP   rP   rQ   register_connect_callback   s    z-ConnectionInterface.register_connect_callbackc                 C   s   d S rY   rP   ri   rP   rP   rQ   deregister_connect_callback   s    z/ConnectionInterface.deregister_connect_callbackc                 C   s   d S rY   rP   rK   parser_classrP   rP   rQ   
set_parser   s    zConnectionInterface.set_parserc                 C   s   d S rY   rP   rg   rP   rP   rQ   get_protocol   s    z ConnectionInterface.get_protocolc                 C   s   d S rY   rP   rg   rP   rP   rQ   connect   s    zConnectionInterface.connectc                 C   s   d S rY   rP   rg   rP   rP   rQ   
on_connect   s    zConnectionInterface.on_connectc                 G   s   d S rY   rP   rK   r;   rP   rP   rQ   
disconnect   s    zConnectionInterface.disconnectc                 C   s   d S rY   rP   rg   rP   rP   rQ   check_health   s    z ConnectionInterface.check_healthTc                 C   s   d S rY   rP   rK   commandru   rP   rP   rQ   send_packed_command   s    z'ConnectionInterface.send_packed_commandc                 O   s   d S rY   rP   rK   r;   kwargsrP   rP   rQ   send_command   s    z ConnectionInterface.send_commandr   c                 C   s   d S rY   rP   rK   timeoutrP   rP   rQ   can_read   s    zConnectionInterface.can_readFdisconnect_on_errorpush_requestc                C   s   d S rY   rP   )rK   disable_decodingr   r   rP   rP   rQ   read_response   s    z!ConnectionInterface.read_responsec                 G   s   d S rY   rP   rs   rP   rP   rQ   rF      s    z ConnectionInterface.pack_commandc                 C   s   d S rY   rP   rK   commandsrP   rP   rQ   pack_commands   s    z!ConnectionInterface.pack_commandsrW   c                 C   s   d S rY   rP   rg   rP   rP   rQ   handshake_metadata   s    z&ConnectionInterface.handshake_metadatatokenc                 C   s   d S rY   rP   rK   r   rP   rP   rQ   set_re_auth_token   s    z%ConnectionInterface.set_re_auth_tokenc                 C   s   d S rY   rP   rg   rP   rP   rQ   re_auth   s    zConnectionInterface.re_authN)T)r   )F)rS   rT   rU   r   rh   rk   rl   ro   rp   rq   rr   rt   ru   rx   r{   r~   r   rF   r   propertyr   r	   bytesr@   r   r   r   r   rP   rP   rP   rQ   rf      sR   









 	

*rf   c                   @   s(  e Zd ZdZdddddedddedddde ddddd	ddfeee	 ee
 ee
 ee	e	eeeee	 ee	 ee	 ee	 eedf eeg df  ee ee eeg df  ee d
ddZdd Zedd Zdd Zdd Zdd Zdd Zdd Zdd ZdLeddd Zed!d" Zed#d$ Zd%d& Zd'd( ZdMedd)d*Z d+d, Z!d-d. Z"d/d0 Z#d1d2 Z$dNd3d4Z%d5d6 Z&dOd7d8Z'dPddd9d:d;Z(d<d= Z)d>d? Z*eee	f d@dAdBZ+e,ee-e.e.f e-e	e	f f d@dCdDZ/e/j0ee-e.e.f e-e	e	f f dEdFdDZ/e1dGdHdIZ2dJdK Z3dS )QAbstractConnectionz0Manages communication to and from a Redis serverr   NFutf-8stricti   zredis-pyr8   )dbpasswordsocket_timeoutsocket_connect_timeoutretry_on_timeoutencodingencoding_errorsdecode_responsessocket_read_sizehealth_check_intervalclient_namelib_namelib_versionusernameretryredis_connect_funccredential_providerprotocolcommand_packerevent_dispatcherc                 C   s  |s|r|dk	rt d|dkr*t | _n|| _t | _|| _|| _|| _|| _	|| _
|| _|| _|| _|dkrv|}|| _|| _|tkrg }|r|t || _|s|r|dkrtt d| _nt|| _| j| ntt d| _|| _d| _|| _t|||	| _d| _d| _ || _!| "|
 g | _#d| _$d| _%zHzt(|}W n6 t)k
r`   t*}Y n t+k
r|   t&d	Y nX W 5 |dk s|dkrt&d|| _'X | ,|| _-dS )
a2  
        Initialize a new Connection.
        To specify a retry policy for specific errors, first set
        `retry_on_error` to a list of the error/s to retry on, then set
        `retry` to a valid `Retry` object.
        To retry on TimeoutError, `retry_on_timeout` can also be set to `True`.
        Nz'username' and 'password' cannot be passed along with 'credential_provider'. Please provide only one of the following arguments: 
1. 'password' and (optional) 'username'
2. 'credential_provider'r   r   ip  r8      zprotocol must be either 2 or 3zprotocol must be an integer).r'   r"   _event_dispatcherosgetpidpidr   r   r   r   r   r   r   r   r   r   SENTINELrD   r*   retry_on_errorr+   r   r   copydeepcopyZupdate_supported_errorsr   next_health_checkr   r   encoderr   _sock_socket_read_sizero   _connect_callbacksrZ   _re_auth_tokenr&   r   intrG   DEFAULT_RESP_VERSION
ValueError_construct_command_packer_command_packer)rK   r   r   r   r   r   r   r   r   r   rn   r   r   r   r   r   r   r   r   r   r   r   r   prP   rP   rQ   r\      sh     



zAbstractConnection.__init__c                 C   s8   d dd |  D }d| jj d| jj d| dS )N,c                 S   s   g | ]\}}| d | qS )=rP   ).0kvrP   rP   rQ   
<listcomp>E  s     z/AbstractConnection.__repr__.<locals>.<listcomp><.()>)r^   rh   	__class__rT   rS   )rK   Z	repr_argsrP   rP   rQ   __repr__D  s    zAbstractConnection.__repr__c                 C   s   d S rY   rP   rg   rP   rP   rQ   rh   H  s    zAbstractConnection.repr_piecesc                 C   s&   z|    W n tk
r    Y nX d S rY   )rt   	Exceptionrg   rP   rP   rQ   __del__L  s    zAbstractConnection.__del__c                 C   s*   |d k	r|S t rt S t| j| jjS d S rY   )r-   r:   rV   rZ   r   rB   )rK   packerrP   rP   rQ   r   R  s
    z,AbstractConnection._construct_command_packerc                 C   s$   t |}|| jkr | j| dS )a^  
        Register a callback to be called when the connection is established either
        initially or reconnected.  This allows listeners to issue commands that
        are ephemeral to the connection, for example pub/sub subscription or
        key tracking.  The callback must be a _method_ and will be kept as
        a weak reference.
        N)weakref
WeakMethodr   rD   )rK   rj   ZwmrP   rP   rQ   rk   Z  s    

z,AbstractConnection.register_connect_callbackc                 C   s0   z| j t| W n tk
r*   Y nX dS )z
        De-register a previously registered callback.  It will no-longer receive
        notifications on connection events.  Calling this is not required when the
        listener goes away, since the callbacks are kept as weak methods.
        N)r   remover   r   r   ri   rP   rP   rQ   rl   f  s    z.AbstractConnection.deregister_connect_callbackc                 C   s   || j d| _dS )z
        Creates a new instance of parser_class with socket size:
        _socket_read_size and assigns it to the parser for the connection
        :param parser_class: The required parser class
        )r   N)r   _parserrm   rP   rP   rQ   ro   q  s    zAbstractConnection.set_parserc                 C   s   | j dd dS )z5Connects to the Redis server if not already connectedTru   N)connect_check_healthrg   rP   rP   rQ   rq   y  s    zAbstractConnection.connectTr   c              
      s    j r
d S z" j fdd fdd}W nL tjk
rJ   tdY n0 tk
rx } zt |W 5 d }~X Y nX | _ z& j	d kr j
|d n
 	  W n tk
r       Y nX dd  jD  _ jD ]}| }|r|  qd S )Nc                      s      S rY   )_connectrP   rg   rP   rQ   <lambda>  r7   z9AbstractConnection.connect_check_health.<locals>.<lambda>c                    s
     | S rY   rt   errorrg   rP   rQ   r     r7   zTimeout connecting to serverr   c                 S   s   g | ]}| r|qS rP   rP   )r   refrP   rP   rQ   r     s      z;AbstractConnection.connect_check_health.<locals>.<listcomp>)r   r   call_with_retrysocketr}   r*   OSErrorr&   _error_messager   on_connect_check_healthr(   rt   r   )rK   ru   socker   rj   rP   rg   rQ   r   }  s0    
 
 

z'AbstractConnection.connect_check_healthc                 C   s   d S rY   rP   rg   rP   rP   rQ   r     s    zAbstractConnection._connectc                 C   s   d S rY   rP   rg   rP   rP   rQ   _host_error  s    zAbstractConnection._host_errorc                 C   s   t |  |S rY   )r2   r   )rK   	exceptionrP   rP   rQ   r     s    z!AbstractConnection._error_messagec                 C   s   | j dd d S )NTr   )r   rg   rP   rP   rQ   rr     s    zAbstractConnection.on_connectc                 C   s  | j |  | j }d}| js(| js(| jrD| jp:t| j| j}| }|r| jdkrt| j t	r~| 
t |j| j _| j |  t|dkrd|d g}| jd| jdf|dd	i |  | _n|r0| jd|dd	i z|  }W n2 tk
r   | jd|d
 d	d |  }Y nX t|dkrtdn| jdkrt| j t	rj| 
t |j| j _| j |  | jd| j|d |  | _| jd| jkr| jd| jkrtd| jr| jdd| j|d t|  dkrtdz*| jr| jddd| j|d |   W n tk
r,   Y nX z*| jrV| jddd| j|d |   W n tk
rn   Y nX | jr| jd| j|d t|  dkrtddS )z=Initialize the connection, authenticate and select a databaseN)r8   2r   defaultr   ZHELLOAUTHru   Fr   OKzInvalid Username or Passwords   protoprotozInvalid RESP versionCLIENTZSETNAMEzError setting client nameZSETINFOzLIB-NAMEzLIB-VERZSELECTzInvalid Database)r   )r   rr   r   r   r   r    Zget_credentialsr   r?   r   ro   r   ZEXCEPTION_CLASSESr`   r{   r   r   r$   r4   r#   getr&   r   r   r)   r   r   )rK   ru   parserZ	auth_argsZcred_providerZauth_responserP   rP   rQ   r     s    

  



z*AbstractConnection.on_connect_check_healthc              	   G   s   | j   | j}d| _|dkr"dS t | jkrZz|tj W n t	t
fk
rX   Y nX z|  W n t	k
rz   Y nX dS )z!Disconnects from the Redis serverN)r   Zon_disconnectr   r   r   r   shutdownr   	SHUT_RDWRr   rG   close)rK   r;   Z	conn_sockrP   rP   rQ   rt     s    
zAbstractConnection.disconnectc                 C   s*   | j ddd t|  dkr&tddS )z Send PING, expect PONG in returnZPINGFr   ZPONGz#Bad response from PING health checkN)r{   r4   r   r&   rg   rP   rP   rQ   
_send_ping0  s    zAbstractConnection._send_pingc                 C   s   |    dS )z Function to call when PING failsNr   rK   r   rP   rP   rQ   _ping_failed6  s    zAbstractConnection._ping_failedc                 C   s*   | j r&t | jkr&| j| j| j dS )z3Check the health of the connection with a PING/PONGN)r   time	monotonicr   r   r   r   r   rg   rP   rP   rQ   ru   :  s    zAbstractConnection.check_healthc              
   C   s  | j s| jdd |r|   z*t|tr0|g}|D ]}| j | q4W n tjk
rn   |   t	dY n t
k
r } zV|   t|jdkrd|jd  }}n|jd }|jd }td| d| d	W 5 d
}~X Y n tk
r   |    Y nX d
S )z2Send an already packed command to the Redis serverFr   zTimeout writing to socketr   UNKNOWNr   zError z while writing to socket. r   N)r   r   ru   r?   r@   sendallr   r}   rt   r*   r   r`   r;   r&   BaseException)rK   rw   ru   itemr   errnoerrmsgrP   rP   rQ   rx   ?  s,    


&z&AbstractConnection.send_packed_commandc                 O   s"   | j | jj| |ddd dS )z+Pack and send a command to the Redis serverru   Tr   N)rx   r   rR   r   ry   rP   rP   rQ   r{   ^  s    

zAbstractConnection.send_commandc              
   C   sn   | j }|s|   |  }z| j|W S  tk
rh } z"|   td| d|j W 5 d}~X Y nX dS )z8Poll the socket to see if there's data that can be read.Error while reading from z: N)	r   rq   r   r   r~   r   rt   r&   r;   )rK   r}   r   
host_errorr   rP   rP   rQ   r~   e  s    zAbstractConnection.can_readr   c             
   C   s   |   }z2| jdkr*ts*| jj||d}n| jj|d}W n tjk
rj   |rX|   td| Y nd t	k
r } z&|r|   t
d| d|j W 5 d}~X Y n" tk
r   |r|    Y nX | jrt | j | _t|trz|W 5 ~X |S )z0Read the response from a previously sent command)3r   )r   r   )r   zTimeout reading from r   z : N)r   r   r-   r   r   r   r}   rt   r*   r   r&   r;   r   r   r   r   r   r?   r)   )rK   r   r   r   r   responser   rP   rP   rQ   r   s  s6    	 &
z AbstractConnection.read_responsec                 G   s   | j j| S )r=   )r   rR   rs   rP   rP   rQ   rF     s    zAbstractConnection.pack_commandc           	      C   s   g }g }d}| j }|D ]}| jj| D ]r}t|}||ksL||ksLt|trh|r`|t| d}g }||kszt|tr|| q&|| ||7 }q&q|r|t| |S )z.Pack multiple commands into the Redis protocolr   )	rZ   r   rR   r`   r?   rc   rD   r]   r^   )	rK   r   rL   piecesZbuffer_lengthr[   cmdchunkZchunklenrP   rP   rQ   r     s0    
z AbstractConnection.pack_commandsrW   c                 C   s   | j S rY   )r   rg   rP   rP   rQ   rp     s    zAbstractConnection.get_protocolc                 C   s   | j S rY   Z_handshake_metadatarg   rP   rP   rQ   r     s    z%AbstractConnection.handshake_metadatarN   c                 C   s
   || _ d S rY   r   )rK   rN   rP   rP   rQ   r     s    r   c                 C   s
   || _ d S rY   )r   r   rP   rP   rQ   r     s    z$AbstractConnection.set_re_auth_tokenc                 C   s8   | j d k	r4| d| j d| j   |   d | _ d S Nr   oid)r   r{   try_get	get_valuer   rg   rP   rP   rQ   r     s    

zAbstractConnection.re_auth)T)T)T)r   )F)4rS   rT   rU   __doc__r   r9   r3   r   r   r@   floatboolr   r   r   r   r"   r\   r   r   rh   r   r   rk   rl   ro   rq   r   r   r   r   rr   r   rt   r   r   ru   rx   r{   r~   r   rF   r   rp   r   r	   r   r   setterr   r   r   rP   rP   rP   rQ   r      s   
`
"

o

 ,((r   c                       s:   e Zd ZdZd fdd	Zd	d
 Zdd Zdd Z  ZS )
Connectionz4Manages TCP communication to and from a Redis server	localhost  FNr   c                    s8   || _ t|| _|| _|pi | _|| _t jf | d S rY   )hostr   portsocket_keepalivesocket_keepalive_optionssocket_typesuperr\   )rK   r
  r  r  r  r  rz   r   rP   rQ   r\     s    	

zConnection.__init__c                 C   s6   d| j fd| jfd| jfg}| jr2|d| jf |S )Nr
  r  r   r   )r
  r  r   r   rD   rK   r   rP   rP   rQ   rh     s    zConnection.repr_piecesc                 C   s<  d}t | j| j| jt jD ]}|\}}}}}d}zt  |||}|t jt jd | j	r|t j
t jd | j D ]\}	}
|t j|	|
 qx|| j || || j |W   S  tk
r } zB|}|dk	rz|t j W n tk
r   Y nX |  W 5 d}~X Y qX q|dk	r0|tddS )zCreate a TCP socket connectionNr   z)socket.getaddrinfo returned an empty list)r   getaddrinfor
  r  r  SOCK_STREAM
setsockoptIPPROTO_TCPTCP_NODELAYr  
SOL_SOCKETSO_KEEPALIVEr  items
settimeoutr   rq   r   r   r   r   r   )rK   errresfamilysocktyper   	canonnameZsocket_addressr   r   r   rM   rP   rP   rQ   r     s>       




zConnection._connectc                 C   s   | j  d| j S )N:)r
  r  rg   rP   rP   rQ   r      s    zConnection._host_error)r  r	  FNr   	rS   rT   rU   r  r\   rh   r   r   __classcell__rP   rP   r  rQ   r    s        -r  c                   @   s<  e Zd ZdZdZdZeeej	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d>ddZdd Zd?ddZd@ddd d!d"Zd#d$ Zd%d& Zeeeeef eeef f d'd(d)Zd*d+ Zd,d- Z ed.d/d0d1Z!d2d3 Z"e#eee$e#e  f  d4d5d6Z%d7d8 Z&e'd9d:d;Z(d<d= Z)d.S )ACacheProxyConnections   fooz7.4.0Zredis)conncache	pool_lockc                 C   sh   t  | _|| _| jj| _| jj| _| jj| _|j| _|| _|| _	t
 | _d | _d | _| | j d S rY   )r   r   r   _connr   r
  r  r   
_pool_lock_cache	threadingRLock_cache_lock_current_command_cache_keyZ_current_optionsrk   _enable_tracking_callback)rK   r$  r%  r&  rP   rP   rQ   r\   )  s    




zCacheProxyConnection.__init__c                 C   s
   | j  S rY   )r'  rh   rg   rP   rP   rQ   rh   <  s    z CacheProxyConnection.repr_piecesc                 C   s   | j | d S rY   )r'  rk   ri   rP   rP   rQ   rk   ?  s    z.CacheProxyConnection.register_connect_callbackc                 C   s   | j | d S rY   )r'  rl   ri   rP   rP   rQ   rl   B  s    z0CacheProxyConnection.deregister_connect_callbackc                 C   s   | j | d S rY   )r'  ro   rm   rP   rP   rQ   ro   E  s    zCacheProxyConnection.set_parserc                 C   s   | j   | j jdd }|d kr2| j jdd }| j jdd }|d krZ| j jdd }|d ksj|d krrtdt|}t|}|| jkst|| jdkrtdd S )Ns   serverservers   versionversionz0Cannot retrieve information about server versionr   ziTo maximize compatibility with all Redis products, client-side caching is supported by Redis 7.4 or later)	r'  rq   r   r   r&   r1   DEFAULT_SERVER_NAMEr/   MIN_ALLOWED_VERSION)rK   Zserver_nameZ
server_verrP   rP   rQ   rq   H  s$    
zCacheProxyConnection.connectc                 C   s   | j   d S rY   )r'  rr   rg   rP   rP   rQ   rr   _  s    zCacheProxyConnection.on_connectc              	   G   s,   | j  | j  W 5 Q R X | jj|  d S rY   )r,  r)  flushr'  rt   rs   rP   rP   rQ   rt   b  s    zCacheProxyConnection.disconnectc                 C   s   | j   d S rY   )r'  ru   rg   rP   rP   rQ   ru   g  s    z!CacheProxyConnection.check_healthTc                 C   s   | j | d S rY   )r'  rx   rv   rP   rP   rQ   rx   j  s    z(CacheProxyConnection.send_packed_commandc              
   O   s,  |    | j@ | jt|d ddsJd | _| jj|| W 5 Q R  d S W 5 Q R X |dd krjt	dt|d t
|dd| _| j | j| jr| j| j}|j| jkr| j  |j r|jjdd qW 5 Q R X W 5 Q R  d S | jt| j| jtj| jd W 5 Q R X | jj|| d S )	Nr   rP   )rw   Z
redis_keyskeyszCannot create cache key.Tr   )	cache_keycache_valuestatusconnection_ref)_process_pending_invalidationsr,  r)  Zis_cachabler   r-  r'  r{   r   r   rA   r9  r(  r~   r   setr   DUMMY_CACHE_VALUEr   IN_PROGRESS)rK   r;   rz   entryrP   rP   rQ   r{   o  s:     
z!CacheProxyConnection.send_commandr   c                 C   s   | j |S rY   )r'  r~   r|   rP   rP   rQ   r~     s    zCacheProxyConnection.can_readFr   c             
   C   s  | j d | jd k	rf| j| jd k	rf| j| jjtjkrft| j| jj	}d | _|W  5 Q R  S W 5 Q R X | j
j|||d}| j ~ | jd kr|W  5 Q R  S |d kr| j| jg |W  5 Q R  S | j| j}|d k	rtj|_||_	| j| d | _W 5 Q R X |S )N)r   r   r   )r,  r-  r)  r   r8  r   r=  r   r   r7  r'  r   Zdelete_by_cache_keysZVALIDr;  )rK   r   r   r   r  r   Zcache_entryrP   rP   rQ   r     s@    
z"CacheProxyConnection.read_responsec                 G   s   | j j| S rY   )r'  rF   rs   rP   rP   rQ   rF     s    z!CacheProxyConnection.pack_commandc                 C   s   | j |S rY   )r'  r   r   rP   rP   rQ   r     s    z"CacheProxyConnection.pack_commandsrW   c                 C   s   | j jS rY   )r'  r   rg   rP   rP   rQ   r     s    z'CacheProxyConnection.handshake_metadatac                 C   s   | j   d S rY   )r'  r   rg   rP   rP   rQ   r     s    zCacheProxyConnection._connectc                 C   s   | j   d S rY   )r'  r   rg   rP   rP   rQ   r     s    z CacheProxyConnection._host_errorN)r$  rX   c                 C   s(   | ddd |  |j| j d S )Nr   ZTRACKINGON)r{   r   r   Zset_invalidation_push_handler_on_invalidation_callback)rK   r$  rP   rP   rQ   r.    s    z.CacheProxyConnection._enable_tracking_callbackc                 C   s   |   r| jjdd q d S )NTr5  )r~   r'  r   rg   rP   rP   rQ   r:    s    z3CacheProxyConnection._process_pending_invalidations)datac              	   C   s>   | j . |d d kr | j  n| j|d  W 5 Q R X d S )Nr   )r,  r)  r3  Zdelete_by_redis_keys)rK   rA  rP   rP   rQ   r@    s    z.CacheProxyConnection._on_invalidation_callbackc                 C   s
   | j  S rY   )r'  rp   rg   rP   rP   rQ   rp     s    z!CacheProxyConnection.get_protocolr   c                 C   s   | j | d S rY   )r'  r   r   rP   rP   rQ   r     s    z&CacheProxyConnection.set_re_auth_tokenc                 C   s   | j   d S rY   )r'  r   rg   rP   rP   rQ   r     s    zCacheProxyConnection.re_auth)T)r   )F)*rS   rT   rU   r<  r2  r1  rf   r   r*  Lockr\   rh   rk   rl   ro   rq   rr   rt   ru   rx   r{   r~   r   rF   r   r   r   r	   r   r@   r   r   r   r.  r:  r
   r   r@  rp   r   r   r   rP   rP   rP   rQ   r#  $  sF   
0
  -("r#  c                       s6   e Zd ZdZd fdd	Z fdd	Zd
d Z  ZS )SSLConnectionzManages SSL connections to and from the Redis server(s).
    This class extends the Connection class, adding SSL functionality, and making
    use of ssl.SSLContext (https://docs.python.org/3/library/ssl.html#ssl.SSLContext)
    NrequiredTFc                    s   t std|| _|| _|dkr(tj}n:t|trbtjtjtj	d}||krZtd| || }|| _
|| _|| _|| _| j
tjkr|nd| _|| _|	| _|
| _|| _|| _|| _|| _t jf | dS )a  Constructor

        Args:
            ssl_keyfile: Path to an ssl private key. Defaults to None.
            ssl_certfile: Path to an ssl certificate. Defaults to None.
            ssl_cert_reqs: The string value for the SSLContext.verify_mode (none, optional, required), or an ssl.VerifyMode. Defaults to "required".
            ssl_ca_certs: The path to a file of concatenated CA certificates in PEM format. Defaults to None.
            ssl_ca_data: Either an ASCII string of one or more PEM-encoded certificates or a bytes-like object of DER-encoded certificates.
            ssl_check_hostname: If set, match the hostname during the SSL handshake. Defaults to False.
            ssl_ca_path: The path to a directory containing several CA certificates in PEM format. Defaults to None.
            ssl_password: Password for unlocking an encrypted private key. Defaults to None.

            ssl_validate_ocsp: If set, perform a full ocsp validation (i.e not a stapled verification)
            ssl_validate_ocsp_stapled: If set, perform a validation on a stapled ocsp response
            ssl_ocsp_context: A fully initialized OpenSSL.SSL.Context object to be used in verifying the ssl_ocsp_expected_cert
            ssl_ocsp_expected_cert: A PEM armoured string containing the expected certificate to be returned from the ocsp verification service.
            ssl_min_version: The lowest supported SSL version. It affects the supported SSL versions of the SSLContext. None leaves the default provided by ssl module.
            ssl_ciphers: A string listing the ciphers that are allowed to be used. Defaults to None, which means that the default ciphers are used. See https://docs.python.org/3/library/ssl.html#ssl.SSLContext.set_ciphers for more information.

        Raises:
            RedisError
        z$Python wasn't built with SSL supportN)noneoptionalrD  z+Invalid SSL Certificate Requirements Flag: F)r.   r(   keyfilecertfilessl	CERT_NONEr?   r@   CERT_OPTIONALCERT_REQUIRED	cert_reqsca_certsca_dataca_pathcheck_hostnamecertificate_passwordssl_validate_ocspssl_validate_ocsp_stapledssl_ocsp_contextssl_ocsp_expected_certssl_min_versionssl_ciphersr  r\   )rK   Zssl_keyfileZssl_certfileZssl_cert_reqsZssl_ca_certsZssl_ca_datassl_check_hostnameZssl_ca_pathZssl_passwordrS  rT  rU  rV  rW  rX  rz   Z	CERT_REQSr  rP   rQ   r\      s<    (
zSSLConnection.__init__c              	      s>   t   }z| |W S  ttfk
r8   |   Y nX dS )zN
        Wrap the socket with SSL support, handling potential errors.
        N)r  r   _wrap_socket_with_sslr   r(   r   rK   r   r  rP   rQ   r   J  s    
zSSLConnection._connectc           
      C   s  t  }| j|_| j|_| js$| jr:|j| j| j| jd | j	dk	sX| j
dk	sX| jdk	rn|j| j	| j
| jd | jdk	r| j|_| jr|| j | jdkrtdkrtd| jr| jrtd|j|| jd}| jrvd	dl}d
dlm} | jdkr"|j|jj}|| j || j n| j}| || j! |j"|t## }|$  |%| j| j&f |'  |(  |S | jdkrtrd
dlm)} ||| j| j&| j	}	|	* r|S t+d|S )z
        Wraps the socket with SSL support.

        Args:
            sock: The plain socket to wrap with SSL.

        Returns:
            An SSL wrapped socket.
        )rH  rG  r   N)cafilecapathcadataTFzcryptography is not installed.zKEither an OCSP staple or pure OCSP connection must be validated - not both.)server_hostnamer   r   )ocsp_staple_verifier)OCSPVerifierzocsp validation error),rI  create_default_contextrQ  rM  verify_moderH  rG  load_cert_chainrR  rN  rP  rO  load_verify_locationsrW  minimum_versionrX  set_ciphersrS  r,   r(   rT  wrap_socketr
  OpenSSLZocspr`  rU  ZSSLContextZSSLv23_METHODZuse_certificate_fileZuse_privatekey_fileZset_ocsp_client_callbackrV  r  r   Zrequest_ocsprq   r  do_handshaker   ra  Zis_validr&   )
rK   r   contextsslsockri  r`  Z
staple_ctxconra  orP   rP   rQ   rZ  U  sp    
  
 
z#SSLConnection._wrap_socket_with_ssl)NNrD  NNTNNFFNNNN)rS   rT   rU   r  r\   r   rZ  r"  rP   rP   r  rQ   rC    s$                 JrC  c                       s:   e Zd ZdZd fdd	Zdd Zdd	 Zd
d Z  ZS )UnixDomainSocketConnectionz4Manages UDS communication to and from a Redis server Nc                    s   t  jf | || _|| _d S rY   )r  r\   pathr   )rK   rr  r   rz   r  rP   rQ   r\     s    z#UnixDomainSocketConnection.__init__c                 C   s.   d| j fd| jfg}| jr*|d| jf |S )Nrr  r   r   )rr  r   r   rD   r  rP   rP   rQ   rh     s    z&UnixDomainSocketConnection.repr_piecesc                 C   s   t  t jt j}|| j z|| j W nD tk
rp   z|t j	 W n tk
r`   Y nX |
   Y nX || j |S )z&Create a Unix domain socket connection)r   AF_UNIXr  r  r   rq   rr  r   r   r   r   r   r[  rP   rP   rQ   r     s    z#UnixDomainSocketConnection._connectc                 C   s   | j S rY   )rr  rg   rP   rP   rQ   r     s    z&UnixDomainSocketConnection._host_error)rq  Nr!  rP   rP   r  rQ   rp    s
   rp  )0FFALSENNOc                 C   s6   | d ks| dkrd S t | tr.|  tkr.dS t| S )Nrq  F)r?   r@   upperFALSE_STRINGSr  r   rP   rP   rQ   to_bool  s
    r{  )
r   r   r   r  r   r   max_connectionsr   rY  r}   c              
   C   s  |  ds&|  ds&|  ds&tdt| } i }t| j D ]v\}}|r@t|dkr@t|d }t	|}|rz||||< W q t
tfk
r   td| dY qX q@|||< q@| jrt| j|d< | jrt| j|d	< | jd
kr| jrt| j|d< t|d< n| jr"t| j|d< | jr8t| j|d< | jrd|krztt| jdd|d< W n ttfk
r   Y nX | jdkrt|d< |S )Nzredis://z	rediss://zunix://zRRedis URL must specify one of the following schemes (redis://, rediss://, unix://)r   zInvalid value for 'z' in connection URL.r   r   unixrr  connection_classr
  r  r   /rq  Zrediss)
startswithr   r   r   queryr  r`   r   URL_QUERY_ARGUMENT_PARSERSr   rG   r   r   schemerr  rp  hostnamer  r   replaceAttributeErrorrC  )urlrz   namerN   r   rP   rP   rQ   	parse_url  sR    


r  _CPConnectionPool)boundc                   @   s(  e Zd ZdZeee eedddZe	ddfe
e e
e dddZeefd	d
dZdd Zdd	ddZdd	ddZedgdddd2dd	ddZed	ddZdd	ddZddddd Zdedd!d"Zd3edd$d%d&Zdd	d'd(Zedd)d*d+Zed,d-d.Ze d/d0d1Z!dS )4r  a  
    Create a connection pool. ``If max_connections`` is set, then this
    object raises :py:class:`~redis.exceptions.ConnectionError` when the pool's
    limit is reached.

    By default, TCP connections are created unless ``connection_class``
    is specified. Use class:`.UnixDomainSocketConnection` for
    unix sockets.

    Any additional keyword arguments are passed to the constructor of
    ``connection_class``.
    )clsr  rX   c                 K   s0   t |}d|kr|d |d< || | f |S )a  
        Return a connection pool configured from the given URL.

        For example::

            redis://[[username]:[password]]@localhost:6379/0
            rediss://[[username]:[password]]@localhost:6379/0
            unix://[username@]/path/to/socket.sock?db=0[&password=password]

        Three URL schemes are supported:

        - `redis://` creates a TCP socket connection. See more at:
          <https://www.iana.org/assignments/uri-schemes/prov/redis>
        - `rediss://` creates a SSL wrapped TCP socket connection. See more at:
          <https://www.iana.org/assignments/uri-schemes/prov/rediss>
        - ``unix://``: creates a Unix Domain Socket connection.

        The username, password, hostname, path and all querystring values
        are passed through urllib.parse.unquote in order to replace any
        percent-encoded values with their corresponding characters.

        There are several ways to specify a database number. The first value
        found will be used:

            1. A ``db`` querystring option, e.g. redis://localhost?db=0
            2. If using the redis:// or rediss:// schemes, the path argument
               of the url, e.g. redis://localhost/0
            3. A ``db`` keyword argument to this function.

        If none of these options are specified, the default db=0 is used.

        All querystring options are cast to their appropriate Python types.
        Boolean arguments can be specified with string values "True"/"False"
        or "Yes"/"No". Values that cannot be properly cast cause a
        ``ValueError`` to be raised. Once parsed, the querystring arguments
        and keyword arguments are passed to the ``ConnectionPool``'s
        class initializer. In the case of conflicting arguments, querystring
        arguments always win.
        r~  )r  update)r  r  rz   Zurl_optionsrP   rP   rQ   from_url+  s
    )
zConnectionPool.from_urlN)r|  cache_factoryc                 K   s:  |pd}t |tr|dk r"td|| _|| _|| _d | _|| _|dsT|dr|ddkrjt	d| jd}|d k	rt |t
std	|| _n.| jd k	r| j | _nt| jd | _|dd  |dd  | jd
d | _| jd krt | _t | _| jd kr$t | _n
t | _|   d S )Nl        r   z,"max_connections" must be a positive integerZcache_configr%  r   )r   r   z4Client caching is only supported with RESP version 3z#Cache must implement CacheInterfacer   )r?   r   r   r~  connection_kwargsr|  r%  Z_cache_factoryr   r(   r   Z	get_cacher   popr   r"   r*  r+  
_fork_lock_lockrB  reset)rK   r~  r|  r  r  r%  rP   rP   rQ   r\   \  s>    





zConnectionPool.__init__rW   c              	   C   s2   dt | j dt | j dt| jf | j dS )Nr   r   r   r   )typerT   rS   reprr~  r  rg   rP   rP   rQ   r     s    0zConnectionPool.__repr__c                 C   s   | j ddS )z
        Returns:
            The RESP protocol version, or ``None`` if the protocol is not specified,
            in which case the server default will be used.
        r   N)r  r   rg   rP   rP   rQ   rp     s    zConnectionPool.get_protocolc                 C   s"   d| _ g | _t | _t | _d S )Nr   )_created_connections_available_connectionsr;  _in_use_connectionsr   r   r   rg   rP   rP   rQ   r    s    zConnectionPool.resetc                 C   sP   | j t krL| jjdd}|s$tz| j t kr<|   W 5 | j  X d S )N   )r}   )r   r   r   r  acquirer%   releaser  )rK   ZacquiredrP   rP   rQ   	_checkpid  s    #zConnectionPool._checkpid*)Use get_connection() without args instead5.3.0Zargs_to_warnreasonr0  r  c              
   O   s   |    | j> z| j }W n tk
r:   |  }Y nX | j| W 5 Q R X zf|  z|	 rx| j
dkrxtdW n: tttfk
r   |  |  |	 rtdY nX W n  tk
r   | |  Y nX |S )zGet a connection from the poolNConnection has dataConnection not ready)r  r  r  r  
IndexErrormake_connectionr  addrq   r~   r%  r&   r*   r   rt   r   r  rK   command_namer4  options
connectionrP   rP   rQ   get_connection  s*    
zConnectionPool.get_connectionc                 C   s,   | j }t|dd|dd|dddS )z,Return an encoder based on encoding settingsr   r   r   r   r   F)r   r   r   )r  r   r   )rK   rz   rP   rP   rQ   get_encoder  s    


zConnectionPool.get_encoderrf   c                 C   sT   | j | jkrtd|  j d7  _ | jdk	rFt| jf | j| j| jS | jf | jS )zCreate a new connectionzToo many connectionsr   N)r  r|  r&   r%  r#  r~  r  r  rg   rP   rP   rQ   r    s    
  zConnectionPool.make_connection)r  rX   c              	   C   s   |    | jv z| j| W n  tk
r@   Y W 5 Q R  dS X | |rj| j| | j	t
| n|  W 5 Q R  dS W 5 Q R X dS )z(Releases the connection back to the poolN)r  r  r  r   KeyErrorowns_connectionr  rD   r   dispatchr!   rt   rK   r  rP   rP   rQ   r  %  s    
zConnectionPool.releasec                 C   s   |j | j kS rY   )r   r  rP   rP   rQ   r  =  s    zConnectionPool.owns_connectionT)inuse_connectionsrX   c              	   C   sJ   |    | j2 |r$t| j| j}n| j}|D ]}|  q.W 5 Q R X dS )z
        Disconnects connections in the pool

        If ``inuse_connections`` is True, disconnect connections that are
        current in use, potentially by other threads. Otherwise only disconnect
        connections that are idle in the pool.
        N)r  r  r   r  r  rt   )rK   r  connectionsr  rP   rP   rQ   rt   @  s     zConnectionPool.disconnectc                 C   s   |    dS )z-Close the pool, disconnecting all connectionsNr   rg   rP   rP   rQ   r   T  s    zConnectionPool.close)r   rX   c                 C   s8   | j d|i | jD ]
}||_q| jD ]
}||_q(d S )Nr   )r  r  r  r   r  )rK   r   r$  rP   rP   rQ   	set_retryX  s
    

zConnectionPool.set_retryr   c              	      sv   j f jD ]B  j fddfdd  j fddfdd qjD ]   qXW 5 Q R X d S )Nc                      s     dd S r   )r{   r  r  rP   )r$  r   rP   rQ   r   c  s     z1ConnectionPool.re_auth_callback.<locals>.<lambda>c                    s
     | S rY   _mockr   rg   rP   rQ   r   f  r7   c                      s      S rY   )r   rP   )r$  rP   rQ   r   i  r7   c                    s
     | S rY   r  r   rg   rP   rQ   r   i  r7   )r  r  r   r   r  r   r   rP   )r$  rK   r   rQ   re_auth_callback_  s    


 

zConnectionPool.re_auth_callbackr   c                    s   dS )z
        Dummy functions, needs to be passed as error callback to retry object.
        :param error:
        :return:
        NrP   r   rP   rP   rQ   r  n  s    zConnectionPool._mock)N)T)"rS   rT   rU   r  classmethodr   r  r@   r  r  r   r   r   r\   r   rp   r  r  r0   r  r   r  r  r  r  r  rt   r   r+   r  r   r  r(   r  rP   rP   rP   rQ   r    s:   2?/"	c                       sd   e Zd ZdZddeef fdd	Zdd Zdd	 Ze	d
gddddddZ
dd Zdd Z  ZS )BlockingConnectionPoola  
    Thread-safe blocking connection pool::

        >>> from redis.client import Redis
        >>> client = Redis(connection_pool=BlockingConnectionPool())

    It performs the same function as the default
    :py:class:`~redis.ConnectionPool` implementation, in that,
    it maintains a pool of reusable connections that can be shared by
    multiple redis clients (safely across threads if required).

    The difference is that, in the event that a client tries to get a
    connection from the pool when all of connections are in use, rather than
    raising a :py:class:`~redis.ConnectionError` (as the default
    :py:class:`~redis.ConnectionPool` implementation does), it
    makes the client wait ("blocks") for a specified number of seconds until
    a connection becomes available.

    Use ``max_connections`` to increase / decrease the pool size::

        >>> pool = BlockingConnectionPool(max_connections=10)

    Use ``timeout`` to tell it either how many seconds to wait for a connection
    to become available, or to block forever:

        >>> # Block forever.
        >>> pool = BlockingConnectionPool(timeout=None)

        >>> # Raise a ``ConnectionError`` after five seconds if a connection is
        >>> # not available.
        >>> pool = BlockingConnectionPool(timeout=5)
    2      c                    s(   || _ || _t jf ||d| d S )N)r~  r|  )queue_classr}   r  r\   )rK   r|  r}   r~  r  r  r  rP   rQ   r\     s    zBlockingConnectionPool.__init__c                 C   sN   |  | j| _z| jd  W q tk
r6   Y q:Y qX qg | _t | _d S rY   )	r  r|  pool
put_nowaitr   _connectionsr   r   r   rg   rP   rP   rQ   r    s    zBlockingConnectionPool.resetc                 C   sD   | j dk	r&t| jf | j| j | j}n| jf | j}| j| |S )zMake a fresh connection.N)r%  r#  r~  r  r  r  rD   r  rP   rP   rQ   r    s    
  z&BlockingConnectionPool.make_connectionr  r  r  r  Nc              
   O   s   |    d}z| jjd| jd}W n tk
r>   tdY nX |dkrP|  }z\|  z| rltdW n: tt	t
fk
r   |  |  | rtdY nX W n  tk
r   | |  Y nX |S )a7  
        Get a connection, blocking for ``self.timeout`` until a connection
        is available from the pool.

        If the connection returned is ``None`` then creates a new connection.
        Because we use a last-in first-out queue, the existing connections
        (having been returned to the pool after the initial ``None`` values
        were added) will be returned before ``None`` values. This means we only
        create new connections when we need to, i.e.: the actual number of
        connections will only increase in response to demand.
        NT)blockr}   zNo connection available.r  r  )r  r  r   r}   r   r&   r  rq   r~   r*   r   rt   r   r  r  rP   rP   rQ   r    s,    
z%BlockingConnectionPool.get_connectionc                 C   sT   |    | |s*|  | jd dS z| j| W n tk
rN   Y nX dS )z)Releases the connection back to the pool.N)r  r  rt   r  r  r   r  rP   rP   rQ   r    s    
zBlockingConnectionPool.releasec                 C   s    |    | jD ]}|  qdS )z(Disconnects all connections in the pool.N)r  r  rt   r  rP   rP   rQ   rt     s    
z!BlockingConnectionPool.disconnect)N)rS   rT   rU   r  r  r   r\   r  r  r0   r  r  rt   r"  rP   rP   r  rQ   r  w  s    #4r  )dr   r   r   rH   r*  r   r   abcr   	itertoolsr   queuer   r   r   typingr   r   r	   r
   r   r   r   r   urllib.parser   r   r   Zredis.cacher   r   r   r   r   r   _parsersr   r   r   r   Z
auth.tokenr   backoffr   credentialsr   r    eventr!   r"   
exceptionsr#   r$   r%   r&   r'   r(   r)   r*   r   r+   utilsr,   r-   r.   r/   r0   r1   r2   r3   r4   rI  rE   r_   rd   ra   r]   r   objectr   __annotations__r9   r:   rV   rf   r   r  r#  rC  rp  rz  r{  r   r  listr  r  r  r  r  rP   rP   rP   rQ   <module>   s    ( 	(
,
3Q   |J W ,#	9  \