o
    ßý°jsc  ã                   @   s  d 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
mZ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mZmZmZ ddlmZmZmZmZ ddl m!Z! dZ"dZ#dZ$dZ%dZ&z
ddl'm(Z(m)Z) W n e*y   ddl(m(Z(m)Z) Y nw G dd„ deƒZ+dS )Ú
é    )Údatetime)Úlinesep)ÚThreadÚLock)Úsleepé   )ÚRESTARTABLEÚget_config_parameterÚAUTO_BIND_DEFAULTÚAUTO_BIND_NONEÚAUTO_BIND_NO_TLSÚAUTO_BIND_TLS_AFTER_BINDÚAUTO_BIND_TLS_BEFORE_BINDé   )ÚBaseStrategy)ÚConnectionUsage)Ú&LDAPConnectionPoolNameIsMandatoryErrorÚ!LDAPConnectionPoolNotStartedErrorÚLDAPOperationResultÚLDAPExceptionErrorÚLDAPResponseTimeoutError)ÚlogÚlog_enabledÚERRORÚBASIC)ÚLDAP_MAX_INTÚTERMINATE_REUSABLE_CONNECTIONéÿÿÿÿéþÿÿÿéýÿÿÿéüÿÿÿ)ÚQueueÚEmptyc                   @   s¼   e Zd ZdZeƒ Zdd„ Zdd„ Zdd„ Zdd	„ Z	d
d„ Z
G dd„ deƒZG dd„ deƒZG dd„ deƒZdd„ Zd'dd„Zdd„ Zdd„ Zd(dd„Zdd„ Zd)d!d"„Zd#d$„ Zd%d&„ ZdS )*ÚReusableStrategyaÊ  
    A pool of reusable SyncWaitRestartable connections with lazy behaviour and limited lifetime.
    The connection using this strategy presents itself as a normal connection, but internally the strategy has a pool of
    connections that can be used as needed. Each connection lives in its own thread and has a busy/available status.
    The strategy performs the requested operation on the first available connection.
    The pool of connections is instantiated at strategy initialization.
    Strategy has two customizable properties, the total number of connections in the pool and the lifetime of each connection.
    When lifetime is expired the connection is closed and will be open again when needed.
    c                 C   ó   t ‚©N©ÚNotImplementedError©Úself© r+   úŠ/root/aizidognhua/tmp/workspace/projects/ec89d86c-575f-41c9-af57-ac45cbdbf775/venv/lib/python3.10/site-packages/ldap3/strategy/reusable.pyÚ	receivingA   ó   zReusableStrategy.receivingc                 C   r%   r&   r'   r)   r+   r+   r,   Ú_start_listenD   r.   zReusableStrategy._start_listenc                 C   r%   r&   r'   )r*   Ú
message_idÚtimeoutr+   r+   r,   Ú_get_responseG   r.   zReusableStrategy._get_responsec                 C   r%   r&   r'   r)   r+   r+   r,   Ú
get_streamJ   r.   zReusableStrategy.get_streamc                 C   r%   r&   r'   )r*   Úvaluer+   r+   r,   Ú
set_streamM   r.   zReusableStrategy.set_streamc                   @   sX   e Zd Z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„ ZdS )zReusableStrategy.ConnectionPoolz6
        Container for the Connection Threads
        c                 C   s–   |j tjv rFtj|j  }|jstj|j = t | ¡S |jr&|j|jkr&|j|_|jr3|j	|jkr3|j|_	|j
rD|j
|j
krD| ¡  |j
|_
|S t | ¡S r&   )Ú	pool_namer$   ÚpoolsÚstartedÚobjectÚ__new__Úpool_keepaliveÚ	keepaliveÚpool_lifetimeÚlifetimeÚ	pool_sizeÚterminate_pool)ÚclsÚ
connectionÚpoolr+   r+   r,   r:   U   s   


z'ReusableStrategy.ConnectionPool.__new__c                 C   sÀ   t | dƒs\|j| _|| _g | _|jptdƒ| _|jptdƒ| _|j	| _
tƒ | _d| _d| _d| _tƒ | _d| _|jr=tƒ nd | _d| _tƒ | _| tj| j< d| _ttƒr^ttd| ƒ d S d S d S )NÚworkersÚREUSABLE_THREADED_POOL_SIZEÚREUSABLE_THREADED_LIFETIMEFr   z!instantiated ConnectionPool: <%r>)Úhasattrr6   ÚnameÚmaster_connectionrD   r?   r
   r=   r>   r;   r<   r"   Úrequest_queueÚ	open_poolÚ	bind_poolÚtls_poolÚdictÚ	_incomingÚcounterÚ_usager   Úterminated_usageÚ
terminatedr   Ú	pool_lockr$   r7   r8   r   r   r   )r*   rB   r+   r+   r,   Ú__init__f   s,   
íz(ReusableStrategy.ConnectionPool.__init__c                 C   s  dt | jƒ d | jrdnd }|dt t| jƒƒ 7 }|dt | jƒ 7 }|dt | jƒ 7 }|dt | jƒ 7 }|d	t | jƒ 7 }|d
t | j	ƒ 7 }|dt | j
ƒ t 7 }|dt | jƒ t 7 }|d7 }| jr‚t| jƒD ]\}}|tt |ƒ d¡ d t |ƒ 7 }qj|S |td 7 }|S )NzPOOL: z - status: r8   rS   z - responses in queue: z - pool size: z - lifetime: z - keepalive: z	 - open: z	 - bind: z - tls: zMASTER CONN: zWORKERS:é   z: z    no active workers in pool)ÚstrrH   r8   ÚlenrO   r?   r>   r<   rK   rL   rM   r   rI   rD   Ú	enumerateÚrjust)r*   ÚsÚiÚworkerr+   r+   r,   Ú__str__|   s     $þz'ReusableStrategy.ConnectionPool.__str__c                 C   s   |   ¡ S r&   )r^   r)   r+   r+   r,   Ú__repr__�   s   z(ReusableStrategy.ConnectionPool.__repr__c              	   C   sX   | j D ]&}|j� |jjjr|jjjsd|_nd|_W d   ƒ n1 s$w   Y  qd S ©NTF)rD   Úworker_lockrB   ÚserverÚschemaÚinfoÚget_info_from_server©r*   r]   r+   r+   r,   re   ’   s   
€ü€ÿz4ReusableStrategy.ConnectionPool.get_info_from_serverc              	   C   s^   | j D ])}|j� |j | jj| jj| jj| jj| jj	¡ W d   ƒ n1 s'w   Y  qd S r&   )
rD   ra   rB   ÚrebindrI   ÚuserÚpasswordÚauthenticationÚsasl_mechanismÚsasl_credentialsrf   r+   r+   r,   Úrebind_poolš   s   
üÿ€ÿz+ReusableStrategy.ConnectionPool.rebind_poolc              	   C   sr   | j s7|  ¡  | jD ]}|j� |j ¡  W d   ƒ n1 sw   Y  q
d| _ d| _ttƒr5t	td| ƒ dS dS )NTFzworker started for pool <%s>)
r8   Úcreate_poolrD   ra   ÚthreadÚstartrS   r   r   r   rf   r+   r+   r,   Ú
start_pool£   s   
ÿ€z*ReusableStrategy.ConnectionPool.start_poolc                    s2   t tƒr
ttdˆ ƒ ‡ fdd„tˆ jƒD ƒˆ _d S )Nzcreated pool <%s>c                    s   g | ]
}t  ˆ jˆ j¡‘qS r+   )r$   ÚPooledConnectionWorkerrI   rJ   )Ú.0Ú_r)   r+   r,   Ú
<listcomp>³   s    z?ReusableStrategy.ConnectionPool.create_pool.<locals>.<listcomp>)r   r   r   Úranger?   rD   r)   r+   r)   r,   rn   °   s   z+ReusableStrategy.ConnectionPool.create_poolc                 C   sŒ   | j sBttƒrttd| ƒ d| _| j ¡  ttdd„ | j	D ƒƒƒD ]}| j 
td d d f¡ q!| j ¡  d| _ ttƒrDttd| ƒ d S d S d S )Nzterminating pool <%s>Fc                 S   s   g | ]	}|j  ¡ r|‘qS r+   )ro   Úis_alive)rs   r]   r+   r+   r,   ru   »   s    zBReusableStrategy.ConnectionPool.terminate_pool.<locals>.<listcomp>Tzpool terminated for <%s>)rS   r   r   r   r8   rJ   Újoinrv   rX   rD   ÚputÚTERMINATE_REUSABLE)r*   rt   r+   r+   r,   r@   µ   s   

ö	z.ReusableStrategy.ConnectionPool.terminate_poolN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r:   rU   r^   r_   re   rm   rq   rn   r@   r+   r+   r+   r,   ÚConnectionPoolQ   s    	r   c                   @   s    e Zd ZdZdd„ Zdd„ ZdS )z'ReusableStrategy.PooledConnectionThreadz®
        The thread that holds the Reusable connection and receive operation request via the queue
        Result are sent back in the pool._incoming list when ready
        c                 C   s8   t  | ¡ d| _|| _|| _ttƒrttd| ƒ d S d S )NTz)instantiated PooledConnectionThread: <%r>)r   rU   Údaemonr]   rI   r   r   r   )r*   r]   rI   r+   r+   r,   rU   Ç   s   
ÿz0ReusableStrategy.PooledConnectionThread.__init__c           
      C   sn  d| j _d}| jjj}|�s˜z|jjd| jjjjd�\}}}}W n ty5   | j j	j
s3| j j	 d¡ Y qw | j j��R d| j _|tkrjd}| j j	jrhz| j j	 ¡  ttƒr[ttdƒ W �n tyg   Y �nw �nt ¡ | j j j| jjjjkr™z| j j	 ¡  W n	 tyŠ   Y nw | j  ¡  ttƒr™ttdƒ |dv�ruz§|jrÐ| j j	j
rÐ| j j	jdd� |jr¿| j j	js¿| j j	jdd� |j rÏ| j j	jsÏ| j j	j!dd� n|jrè| j j	j
sè|jrè| j j	jsè| j j	jdd� | j j"rø|rø| j j	 #¡  d| j _"d }d }|d	k�r| j j	 $| j j	 %|||¡¡}n| j j	 &| j j	 %|||¡¡}| j j	j'}|j(� ||t) *|||¡f|j+|< W d   ƒ n	1 �s?w   Y  W n/ t,�yt }	 z"|j(� |	d d f|j+|< W d   ƒ n	1 �sew   Y  W Y d }	~	nd }	~	ww d| j _|j -¡  | j  j.d
7  _.W d   ƒ n	1 �s‘w   Y  |rttƒ�r¢ttdƒ | jj/�r±| j0| j j	j/7  _0d| j _d S )NTF)Úblockr1   r   zthread terminatedzthread respawn)ÚbindRequestÚunbindRequest©Úread_server_infoÚsearchRequestr   )1r]   ÚrunningrI   ÚstrategyrC   rJ   Úgetr<   r#   rB   ÚclosedÚabandonra   Úbusyrz   ÚboundÚunbindr   r   r   r   r   ÚnowÚcreation_timeÚsecondsr>   Únew_connectionrK   ÚopenrM   Útls_startedÚ	start_tlsrL   Úbindre   Úrefresh_server_infoÚpost_send_searchÚsendÚpost_send_single_responseÚresultrT   r   Údecode_requestrO   r   Ú	task_doneÚtask_counterÚusagerR   )
r*   Ú	terminaterC   rP   Úmessage_typeÚrequestÚcontrolsÚresponser›   Úer+   r+   r,   ÚrunÐ   s–   
$
ý

€ÿûÿ


€

ÿ€ÿ€ÿ
Çø
B

z+ReusableStrategy.PooledConnectionThread.runN)r{   r|   r}   r~   rU   r¦   r+   r+   r+   r,   ÚPooledConnectionThreadÂ   s    	r§   c                   @   s(   e Zd ZdZdd„ Zdd„ Zdd„ ZdS )	z'ReusableStrategy.PooledConnectionWorkerz�
        Container for the restartable connection. it includes a thread and a lock to execute the connection in the pool
        c                 C   sl   || _ || _d| _d| _d| _d | _d | _d| _|  ¡  t	 
| | j ¡| _tƒ | _ttƒr4ttd| ƒ d S d S )NFr   z)instantiated PooledConnectionWorker: <%s>)rI   rJ   r‡   rŒ   re   rB   r�   rž   r’   r$   r§   ro   r   ra   r   r   r   )r*   rB   rJ   r+   r+   r,   rU      s   ÿz0ReusableStrategy.PooledConnectionWorker.__init__c                 C   s’   dt | jƒ t d }|| jrdnd7 }|d| jrdnd 7 }|dd| j ¡   7 }|d	t | jjj	j
t ¡ | j j ƒ 7 }|d
t | jƒ 7 }|S )NzCONN: z       THREAD: r‡   Úhaltedz - rŒ   Ú	availablezcreated at: z - time to live: z - requests served: )rW   rB   r   r‡   rŒ   r�   Ú	isoformatrI   rˆ   rC   r>   r   r�   r‘   rž   )r*   r[   r+   r+   r,   r^   /  s   (z/ReusableStrategy.PooledConnectionWorker.__str__c                 C   sº  ddl m} t ¡ | _|di d| jjr| jjn| jj“d| jj“d| jj	“dt
“d| jj“d| jj“d	t“d
| jj“d| jj“d| jj“d| jj“d| jj“d| jj“d| jj“d| jj“dd“d| jj“d| jj“d| jj“Ž| _| jjrÇ| jjt
tfvrÇttƒr‰ttd| jƒ | jjdd� | jjt krž| jj!dd� n)| jjt"kr³| jj#dd� | jj!dd� n| jjt$krÇ| jj!dd� | jj#dd� | jjrÛ| jj| j_| jj %| j¡ d S d S )Nr   )Ú
Connectionrb   rh   ri   Ú	auto_bindÚversionrj   Úclient_strategyÚauto_referralsÚ
auto_rangerk   rl   Úcheck_namesÚcollect_usageÚ	read_onlyÚraise_exceptionsÚlazyFÚfast_decoderÚreceive_timeoutÚreturn_empty_attributesz"performing automatic bind for <%s>r„   r+   )&Úcore.connectionr«   r   r�   r�   rI   Úserver_poolrb   rh   ri   r   r­   rj   r	   r¯   r°   rk   rl   r±   rQ   r³   r´   r¶   r·   Úempty_attributesrB   r¬   r   r   r   r   r“   r   r–   r   r•   r   Ú
initialize)r*   r«   r+   r+   r,   r’   9  sr   
€ ÿþýüûúùø	÷
öõôóòñðïîþz6ReusableStrategy.PooledConnectionWorker.new_connectionN)r{   r|   r}   r~   rU   r^   r’   r+   r+   r+   r,   rr     s
    
rr   c                 C   s^   t  | |¡ d| _d| _d| _d| _t|dƒr"|jr"t 	|¡| _
d S ttƒr+ttdƒ tdƒ‚)NFTr6   z)reusable connection must have a pool_name)r   rU   ÚsyncÚno_real_dsaÚpooledÚ
can_streamrG   r6   r$   r   rC   r   r   r   r   )r*   Úldap_connectionr+   r+   r,   rU   d  s   
zReusableStrategy.__init__Tc                 C   sH   d| j _| j  ¡  d| j_| jjr |s| jjjs"| jj ¡  d S d S d S r`   )	rC   rK   rq   rB   rŠ   rŸ   rQ   Úinitial_connection_start_timerp   )r*   Úreset_usager…   r+   r+   r,   r“   q  s   
þzReusableStrategy.openc                 C   s6   | j  ¡  d| j _d| j_d| j_d| j _d| j _d S )NFT)rC   r@   rK   rB   r�   rŠ   rL   rM   r)   r+   r+   r,   r    z  s   
zReusableStrategy.terminatec                 C   s*   d| j _| j jr| j j jd7  _dS dS )z1
        Doesn't really close the socket
        Tr   N)rB   rŠ   rŸ   rQ   Úclosed_socketsr)   r+   r+   r,   Ú_close_socket‚  s   ÿzReusableStrategy._close_socketNc                 C   sð   | j jrk|dkrd| j _t}|S |dkrd| j _t}|S |dkr$t}|S |dkr4| jjr4d| j _t	}|S | j j
� | j  jd7  _| j jtkrKd| j _| j j}W d   ƒ n1 sYw   Y  | j j ||||f¡ |S ttƒrtttdƒ tdƒ‚)	Nr‚   Trƒ   FÚabandonRequestÚextendedReqr   z$reusable connection pool not started)rC   r8   rL   Ú
BOGUS_BINDÚBOGUS_UNBINDÚBOGUS_ABANDONrB   Ústarting_tlsrM   ÚBOGUS_EXTENDEDrT   rP   r   rJ   ry   r   r   r   r   )r*   r¡   r¢   r£   rP   r+   r+   r,   r™   ‹  s6   ñôö
ú
ü
zReusableStrategy.sendc                 C   s&  | j j| jjjks-| j j| jjjks-| j j| jjjks-| j j| jjjks-| j j| jjjkrU| j j| jj_| j j| jj_| j j| jj_| j j| jj_| j j| jj_| j ¡  | jj	d j }|j
}d|_
| j jjrl| j jjsx| jj	d j j|d�}n| jj	d j j|dd�}| ¡  ||_
|r‘d| j_|S )Nr   F)r£   )r£   r…   T)rB   rh   rC   rI   ri   rj   rk   rl   rm   rD   rµ   rb   rc   rd   r–   rŽ   rL   )r*   r£   Útemp_connectionÚold_lazyr›   r+   r+   r,   Úvalidate_bind¤  s,   
zReusableStrategy.validate_bindFc              	   C   sj  t dƒ}d }|d u rt dƒ}|tkr tƒ }dd ddddd dœ}nƒ|tkr)d }d }nz|tkr<tƒ }dd d	d
dddddœ}ng|tkrStƒ }dd d	d
dddddœ}d| j_nPd }d }|dkr’z$| jjj	j
� | jjj	j |¡\}}}W d   ƒ n1 syw   Y  W n ty�   t|ƒ ||8 }Y qWw 	 |dkr£ttƒrŸttdƒ tdƒ‚t|tƒrª|‚|r±|||fS ||fS )NÚRESPONSE_SLEEPTIMEÚRESPONSE_WAITING_TIMEOUTÚsuccessÚbindResponser   Ú z<bogus Bind response>)ÚdescriptionÚ	referralsÚtyper›   ÚdnÚmessageÚ	saslCredsz1.3.6.1.4.1.1466.20037ÚextendedRespÚNonez<bogus StartTls response>)r›   rÖ   ÚresponseNamer×   rÕ   ÚresponseValuerØ   rÙ   Fz6no response from worker threads in Reusable connection)r
   rÈ   ÚlistrÉ   rÊ   rÌ   rB   rË   rˆ   rC   rT   rO   ÚpopÚKeyErrorr   r   r   r   r   Ú
isinstancer   )r*   rP   r1   Úget_requestÚ	sleeptimer¢   r¤   r›   r+   r+   r,   Úget_response¿  sP   
ÿ€ý


zReusableStrategy.get_responsec                 C   ó   |S r&   r+   ©r*   rP   r+   r+   r,   rš   ë  r.   z*ReusableStrategy.post_send_single_responsec                 C   ræ   r&   r+   rç   r+   r+   r,   r˜   î  r.   z!ReusableStrategy.post_send_search)TTr&   )NF)r{   r|   r}   r~   rN   r7   r-   r/   r2   r3   r5   r9   r   r   r§   rr   rU   r“   r    rÅ   r™   rÏ   rå   rš   r˜   r+   r+   r+   r,   r$   5   s(    	qZH
	
	
,r$   N),r~   r   Úosr   Ú	threadingr   r   Útimer   rÔ   r	   r
   r   r   r   r   r   Úbaser   Ú
core.usager   Úcore.exceptionsr   r   r   r   r   Ú	utils.logr   r   r   r   Úprotocol.rfc4511r   rz   rÈ   rÉ   rÌ   rÊ   Úqueuer"   r#   ÚImportErrorr$   r+   r+   r+   r,   Ú<module>   s,    $þ