o
    .j                     @  s  U d dl m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	m
Z
 ddlmZmZmZmZmZmZ ddlmZ ddlmZ ejrdd	lmZ dd
lmZ ddlmZ ddlmZ ddl m!Z! ej"eee!f Z#de$d< ej"eef Z%de$d< ej&de%dZ'ne&dZ'e	G dd dej(e' Z)d,ddZ*e	G dd dej(e' Z+dZ,de$d< ej-dkrej.Z/d-d d!Z0nd-d"d!Z0d.d&d'Z1G d(d) d)ej(e' Z2G d*d+ d+ej(e' Z3dS )/    )annotationsN)	dataclassfield   )AtomicTrafficOverwhelmedTrafficTrafficStateUnavailableTraffictraffic_state_ofItemPlaceholder   )timeout)GroupedDict)AsyncHTTPConnection)AsyncConnectionPool)AsyncHTTPResponse)ResponsePromise)PoolKeyztyping.TypeAliasMappableTrafficManageableTrafficT)boundc                   @  s.   e Zd ZU dZded< ded< dZded< dS )	ActiveCursorz_Duplicated from sync part for typing reasons. 'T' in TrafficPolice sync is bound to sync types!intobj_idr   conn_or_pool   depthN)__name__
__module____qualname____doc____annotations__r    r#   r#   ^/home/thesage/.local/lib/python3.10/site-packages/urllib3_future/util/_async/traffic_police.pyr   )   s
   
 r   returnasyncio.Task[typing.Any]c                  C  s   t  } | d u rtd| S )Nz>Attempt to call function outside of (async) running event loop)asynciocurrent_taskRuntimeError)tr#   r#   r$   _current_task_or_die2   s   r+   c                   @  st   e Zd ZU dZeedZded< eej	dZ
ded< dZded	< dZd
ed< dZded< ejejejfZded< dS )AsyncPendingSignalzPA task may want to block on a specific signal to avoid consuming CPU needlessly.)default_factoryr&   
owner_taskzasyncio.EventeventNT | Nonetarget_conn_or_pool
int | Nonetarget_obj_idr   ztuple[TrafficState, ...]states)r   r   r    r!   r   r+   r.   r"   r'   Eventr/   r1   r3   r   r   IDLEUSED	SATURATEDr4   r#   r#   r#   r$   r,   ;   s   
 r,   g-C6?float_COALESCE_DELAYwin32Nonec                  C  s(   t  t } t  | k r	 t  | k s
d S d S N)_perf_counterr:   )deadliner#   r#   r$   _kernel_recv_coalesce^   s   

r@   c                   C  s   t t d S r=   )timesleepr:   r#   r#   r#   r$   r@   h   s   r4   r   boolc                  G  s   t dd | D S )u  Infer whether the caller wants to WRITE (True) or READ (False)
    based on the traffic states being queried.

    Querying exclusively for states with remaining request capacity
    (IDLE, USED) implies a WRITE intent — looking for a connection to
    send a new request on.
    Querying for states with open streams that may be at capacity
    (SATURATED) implies a READ intent — waiting to consume responses.
    c                 s  s    | ]}|t jk V  qd S r=   )r   r8   ).0stater#   r#   r$   	<genexpr>v   s    z#_intent_to_write.<locals>.<genexpr>)all)r4   r#   r#   r$   _intent_to_writel   s   
rH   c                   @  sn   e Zd ZdZd#ddZd$dd	Zd%ddZd%ddZd&ddZ	d'd(ddZ	d)ddZ
d%ddZd%d d!Zd"S )*AsyncSignalszeThe signal mgr counterpart of our synchronous implementation but for monothreaded/goto label version.cursors/dict[asyncio.Task[typing.Any], ActiveCursor[T]]r%   r<   c                 C  sL   t  | _t  | _t | _| j  i | _|| _	t | _
d| _d| _d S )Ng        )collectionsdeque_priority_signals_furthest_signalsr'   r5   _generic_waitersset_saturated_signals_cursors_writing_tasks_last_dispatch_end_ema_gap)selfrJ   r#   r#   r$   __init__|   s   


zAsyncSignals.__init__c                 C  s   | j t  d S r=   )rT   addr+   rW   r#   r#   r$   declare_writing   s   zAsyncSignals.declare_writingrC   c                 C  s(   t  }|| jv r| j| |  S dS NF)r+   rT   remove_refresh_generic_waitersrW   r(   r#   r#   r$   terminate_writing   s
   
zAsyncSignals.terminate_writingc                 C  sD   | j s| jr| j r| j  dS dS | j s | j  dS dS NTF)rT   rN   rP   is_setclearrQ   rZ   r#   r#   r$   r^      s   



z%AsyncSignals._refresh_generic_waitersr1   r0   r4   r   AsyncPendingSignal[T]c                 G  sn   t ||d}|d urt||_|d ur#t|}|| jvr#t | j|< t| r/| j| |S | j	
| |S )N)r4   r1   )r,   idr3   rR   r'   r5   rH   rN   
appendleftrO   append)rW   r1   r4   signalr   r#   r#   r$   register   s   

zAsyncSignals.registerFrh   unblockc                 C  sR   z|| j v r| j | n| j| W n	 ty   Y nw |r'|j  d S d S r=   )rN   r]   rO   
ValueErrorr/   rQ   )rW   rh   rj   r#   r#   r$   
unregister   s   
zAsyncSignals.unregisterr   c                 C  s`   | j  rdS t|tju rdS t|}|| jvr t | j|< | j|  r)dS | j	r.dS dS NFT)
rP   rb   r
   r   r8   re   rR   r'   r5   rN   )rW   r1   r   r#   r#   r$   should_queue_read_operation   s   

z(AsyncSignals.should_queue_read_operationc                 C  s   t  }|| jvr
t| j| }d}|j| jv r#| j|j }|  d}g }| jr4| j }|j  d}| j	D ]}|j
|jkrI|j  || q7|D ]}| j	| qL| j|= |r]dS |S rm   )r+   rS   r   r   rR   rQ   rN   popleftr/   rO   r3   rg   r]   )rW   r(   cursorany_broadcast_push	conditionawoken_signalsawoken_signalrh   r#   r#   r$   kill   s2   






zAsyncSignals.killc                 C  s  t  }|| jvr
t| j| }t|j}t|jddsDt }| jdkr?|| j }| j	d |d  | _	t
| j	 }|dkr?t  t | _|tju}|tju}|tju }	d}
|j| jv ry| j|j }|tju rq| sp|  d}
n| ry|  t| j}|r|r| j }|j|_| j|= || j|j< d|_|| jv r| j| | j|j |j  |   dS |	r|r|s|
S d }| jD ]}||jvrq|j |jkr|} nq|d ur|j|_| j|= || j|j< d|_|j  | j| |   dS |
S )N_fast_recv_modeTr   gffffff?g333333?Fr   )!r+   rS   r   r
   r   getattrrA   perf_counterrU   rV   r:   r@   r   r8   r6   r   rR   rb   rQ   rc   rC   rN   popr.   r   rT   r]   rY   r/   r^   rO   r4   r3   )rW   r(   rp   current_statenownatural_gap	remainingcan_write_morecan_read_anythingcan_only_writerq   r/   anything_pending_writeearly_unpack_signallate_signal_electedrh   r#   r#   r$   next  sx   

















zAsyncSignals.nextN)rJ   rK   r%   r<   r%   r<   r%   rC   )r1   r0   r4   r   r%   rd   )F)rh   rd   rj   rC   r%   r<   )r1   r   r%   rC   )r   r   r    r!   rX   r[   r`   r^   ri   rl   rn   ru   r   r#   r#   r#   r$   rI   y   s    






%rI   c                   @  s  e Zd ZdZ			d_d`d
dZedaddZdbddZedcddZddddZ	edcddZ
edcddZedcddZded d!Zdfd#d$Zdgdhd)d*Zdbd+d,Zdgdid-d.Zdjd0d1Zddd2dkd6d7Z	dldmd:d;Z				dndod>d?Z	dpdqdAdBZdrdCdDZej			dsdtdHdIZ		dudvdJdKZej				dwdxdMdNZdcdOdPZdbdQdRZdedSdTZdedUdVZ dcdWdXZ!dydZd[Z"dzd]d^Z#dS ){AsyncTrafficPolicea  Task-safe extended-Queue implementation.

    This class is made to enforce the 'I will have order!' psychopath philosophy.
    Rational: Recent HTTP protocols handle concurrent streams, therefore it is
    not as flat as before, we need to answer the following problems:

    1) we cannot just dispose of the oldest connection/pool, it may have a pending response in it.
    2) we need a map, a dumb and simple GPS, to avoid wasting CPU resources searching for a response (promise resolution).
       - that would permit doing read(x) on one response and then read(x) on another without compromising the concerned
         connection.
       - multiplexed protocols can permit temporary locking of a single connection even if response isn't consumed
         (instead of locking through entire lifecycle single request).

    This program is (very) complex and need, for patches, at least both unit tests and integration tests passing.
    NFTmaxsizer2   concurrencyrC   strict_maxsizec                 C  sZ   || _ || _|| _|| _i | _i | _ttd| _t | _	d| _
i | _d| _t| j| _dS )a  
        :param maxsize: Maximum number of items that can be contained.
        :param concurrency: Whether to allow a single item to be used across multiple tasks.
        :param strict_maxsize: If True the scheduler does not increase maxsize for a temporary increase.
        )key_fnFN)r   r   r   _original_maxsize	_registry
_containerr   re   _map
_map_types	_shutdownrS   parentrI   _signals)rW   r   r   r   r#   r#   r$   rX     s   zAsyncTrafficPolice.__init__r%   ActiveCursor[T] | Nonec                 C  s   t  }|| jv r| j| S d S r=   r+   rS   r_   r#   r#   r$   _cursor  s   

zAsyncTrafficPolice._cursorr<   c                 C  s    t  }|| jv r| j|= d S d S r=   r   r_   r#   r#   r$   _unset_cursor  s   
z AsyncTrafficPolice._unset_cursorc                 C  s
   | j d uS r=   )r   rZ   r#   r#   r$   busy  s   
zAsyncTrafficPolice.busyr   r   c                 C  s    | j }|d u r	dS |jt|kS r\   )r   r   re   )rW   r   active_cursorr#   r#   r$   is_held  s   zAsyncTrafficPolice.is_heldc                 C  s   t dd | j D S )Nc                 s      | ]
}t |tju V  qd S r=   )r
   r   r6   rD   _r#   r#   r$   rF     s    
z3AsyncTrafficPolice.bag_only_idle.<locals>.<genexpr>)rG   r   valuesrZ   r#   r#   r$   bag_only_idle  s   z AsyncTrafficPolice.bag_only_idlec                 C  s"   | j sdS tdd | j  D S )z@All manageable traffic is saturated. No more capacity available.Fc                 s  r   r=   )r
   r   r8   r   r#   r#   r$   rF     s
    
z8AsyncTrafficPolice.bag_only_saturated.<locals>.<genexpr>)r   rG   r   rZ   r#   r#   r$   bag_only_saturated  s
   z%AsyncTrafficPolice.bag_only_saturatedc                 C  s2   | j sdS | j  D ]}t|tjur dS q
dS rm   )r   r   r
   r   r8   )rW   connr#   r#   r$   bag_not_saturated  s   z$AsyncTrafficPolice.bag_not_saturatedr   c                 C  
   t | jS r=   lenr   rZ   r#   r#   r$   __len__     
zAsyncTrafficPolice.__len__valuec                 C  sb   t |}|| jvrd S g }| j D ]\}}t ||kr!|| q|D ]
}| j|= | j|= q$d S r=   )re   r   r   itemsrg   r   )rW   r   r   outdated_keyskeyvalr#   r#   r$   
_map_clear  s   


zAsyncTrafficPolice._map_cleartraffic_typetypeblockr0   c           
        s   d}| j |D ]}|d7 }| j| }t|}|| jv r!|  S q	|r&|s(dS | jdtjtj	}|j
 I dH  |jdu rAdS | j|jD ]}| j | |urRqH|j  S |   t| j | ddu}	|	sldS | j||dI dH S )zRFind the first available conn or pool that is linked to at least one traffic type.r   r   N)r   r   )r   keys_forr   re   r   r   ri   r   r7   r8   r/   waitr   releaser   __iter___find_by)
rW   r   r   eligible_object_counttkr   r   rh   mkany_remaining_eligible_objectr#   r#   r$   r     s@   



zAsyncTrafficPolice._find_byc                   s   | j }|du r
dS | |j | j|j= | js&| j r%t	dI dH  n	| j
|j= |   z|j I dH  W dS  tyD   Y dS w )zIn case there is no other way, a conn or pool may be unusable and should be destroyed.
        This make the scheduler forget about it.Nr   )r   r   r   r   r   r   r   ru   r'   rB   r   r   close	Exception)rW   r   r#   r#   r$   kill_cursor   s"   


zAsyncTrafficPolice.kill_cursorc                   s*  d\}}| j s
dS | j  D ]\}}|| jv r&t|tju r&||}} nq|dur]|dur]| | | j |= | j|= | jt d|dI dH  z
|	 I dH  W dS  t
y\   Y dS w |shtd| j d| jdtj}z
|j I dH  W n tjy   | j|  w | j|dI dH  dS )zWhen trying to fill the bag, arriving at the maxsize, we may want to remove an item.
        This method try its best to find the most appropriate idle item and removes it.
        NNNTimmediately_unavailabler   zCannot select a disposable connection to ease the charge. This usually means that your pool sizing is insufficient, please increase your pool maxsize appropriately. Currently set at maxsize=zE. Usually you want as much as the number of active tasks/connections.r   )r   r   r   r
   r   r6   r   putr   r   r   r   r   r   ri   r/   r   r'   CancelledErrorrl   _sacrifice_first_idle)rW   r   eligible_obj_ideligible_conn_or_poolr   r   rh   r#   r#   r$   r   8  sV   


z(AsyncTrafficPolice._sacrifice_first_idletyping.AsyncGenerator[T, None]c              	   C s   | j rtdt }| jrjg }| j D ]\}}t|tjur!q|||f q|D ]@\}}|| jvs;t|tjur<q+| j	sC| j|= t
||| j|< t|dr[|js[|  I dH  q+z	|V  W |   q+|   w dS dS )z6Iterate over idle conn contained in the container bag.zaOne connection/pool active per thread at a given time. Call release prior to calling this method.is_connectedN)r   r   r+   r   r   r
   r   r6   rg   r   r   rS   hasattrr   r   r   )rW   r(   idle_targets
cur_obj_idcur_conn_or_poolr   r   r#   r#   r$   	iter_idler  s>   
	zAsyncTrafficPolice.iter_idle)r   r   traffic_indicatorsr   r   c             	     s  | j r|  I d H  | jsd| _ d S | jd ur?t| j| jkr?t|| jvr?| j|dI d H  | jd ur?| j| jj= | 	  d}t
 }| j}zt|}|| jv }	|	r|| jv rgW |retdI d H  d S d S |d ur|j|krttd| jd8  _|jdkr| js| j rd}| j rd}n| 	  || j|< n
| 	  n|| j|< |rt||| j|< t|t}
|
s| js| j  | jdu r|
s|| j|< d}|r|D ]}| || qW |rtdI d H  d S d S |rtdI d H  w w )NFr   r   z7You must release the previous connection prior to this.r   T)r   r   r   r   r   re   r   r   r   r   r+   r   r'   rB   r   r   r   r   r`   r   r   rS   
isinstancer   r[   memorize)rW   r   r   r   r   should_schedule_another_taskr(   r   r   registered_conn_or_poolis_placeholder	indicatorr#   r#   r$   r     sv   



+








zAsyncTrafficPolice.putnon_saturated_onlynot_idle_onlyc                   s   | j d||dI d H S )NF)r   r   r   )get)rW   r   r   r#   r#   r$   
get_nowait  s   zAsyncTrafficPolice.get_nowaitr   float | Nonec              
     s  d }| j d urtd| jr| jr-| jd ur-| jt| jkr-| jt d|dI d H  d S t	 }| jr|rYd\}}| j
 D ]\}}	t|	tju rJq>||	}} |d urX| j|= n-|sc| j \}}n#d\}}| j
 D ]\}}	t|	tju rxql||	}} |d ur| j|= |d ur|d urt||| j|< | jr|| j|< |S |r| js| j  |S |d u rT|rP|rtjtjf}
n|rtjtjf}
ntjtjtjf}
| jjd g|
R  }zP|d urz*t|d4 I d H  |j I d H  W d   I d H  n1 I d H sw   Y  W n ty } z	td| d|d }~ww |j I d H  W n tjy8   | j|  w |jd u rM| jt d|dI d H  d S |jS td|S )	Nz_One connection/pool active per task at a given time. Call release prior to calling this method.Tr   r   )delayzNo connection available within z
 second(s)zNo connection available) r   r   r   r   r   r   r   r   r   r+   r   r
   r   r8   popitemr6   r   rS   r   r   r[   r7   ri   ctx_expire_inr/   r   TimeoutErrorr	   r'   r   rl   r   )rW   r   r   r   r   r   r(   r   r   r   r4   rh   er#   r#   r$   r     s   
	







*
zAsyncTrafficPolice.gettraffic_indicatorc                 C  s   | j }|d u r|d u rtd|d u r!|d usJ |j|j}}nt||}}|| jvr/d S t|trB|| j|< t	|| j
|< d S t|}|| j|< t	|| j
|< d S )Nz(No connection active on the current task)r   r   r   r   re   r   r   tupler   r   r   )rW   r   r   r   r   traffic_indicator_idr#   r#   r$   r   y  s   



zAsyncTrafficPolice.memorizec                 C  sj   t |tr|nt|}|| jvrd S | j|= | j|= | jd ur3z	| j| W d S  ty2   Y d S w d S r=   )r   r   re   r   r   r   forgetr	   )rW   r   r   r#   r#   r$   r     s   

zAsyncTrafficPolice.forgetMappableTraffic | Noneplaceholder_setGtyping.AsyncGenerator[typing.Callable[[T], typing.Awaitable[None]] | T]c                  s   |dur j ||dI dH }|dur|V  dS g |dur#| |s6 jt gR d|dI dH  dd fd
d}|V  sO  I dH  dS dS )aW  Reserve a spot into the TrafficPolice instance while you construct your conn_or_pool.

        Creating a conn_or_pool may or may not take significant time, in order
        to avoid having many thread racing for TrafficPolice insert, we must
        have a way to instantly reserve a spot meanwhile we built what
        is required.
        N)r   r   Tr   Fswappable_conn_or_poolr   r%   r<   c                   sJ   d j }|d ur j|j=     j| gR dddI d H  d S )NTFr   )r   r   r   r   r   )r   r   rW   	swap_mader   r#   r$   
inner_swap  s   
z5AsyncTrafficPolice.locate_or_hold.<locals>.inner_swap)r   r   r%   r<   )locaterg   r   r   r   )rW   r   r   r   r   r   r#   r   r$   locate_or_hold  s4   
z!AsyncTrafficPolice.locate_or_holdc                   s  	 t |ts&t |tr|nt|}|| jvrd\}}n| j| }t|}ntd|d u r\|d u r\t |ts\| j D ]\}}t|dr[t |j	t
r[|j	|I d H r[||}} nq<t |tsbn	tdI d H  q|d u ss|d u rud S | j}	|	d ur|	j|kr|	 jd7  _|	jS td|| jvs| j|r|std| j|tjtj}
z
|
j I d H  W n tjy   | j|
  w |
jd u s|
j | jvrtd	|S t!||| j"t# < | j$s| j|= |S )
NTr   zunsupported traffic_indicatorpoolr   r   ^Seeking to locate a connection when having another one used, did you forget a call to release?zUnavailable connectionzConnection was killed in flight)%r   r   r   re   r   rk   r   r   r   r   r   beaconr   r'   rB   r   r   r   r   r   r   r   rn   r	   ri   r   r7   r8   r/   r   r   rl   r3   r   rS   r+   r   )rW   r   r   r   r   r   r   r_obj_idr_conn_or_poolr   rh   r#   r#   r$   r     s|   






#

zAsyncTrafficPolice.locateMappableTraffic | type | Nonec           
   
   C s  d}d }zzz|rJt |tr>| |I d H }|r=t|}| j}|d ur-|j|kr,tdn?t||| jt	 < | j
s=| j|= n.| j|||dI d H }n"| jd ura| j}| jd7  _|j|j}}n| j|||dI d H }|d u r||d urxtdtd|V  W n
 ty   d} w W | ot|d	d}	|	r|  I d H  d S |  rtd
I d H  d S d S | ot|d	d}	|	r|  I d H  w |  rtd
I d H  w w )NTr   )r   r   r   )r   r   r   zDNo connection matches the traffic indicator (promise, response, ...)zNo connection are availableF	is_closedr   )r   r   r   re   r   r   r   r   rS   r+   r   r   r   r   r   r   r	   r   rw   r   r   r'   rB   )
rW   r   r   r   r   
clean_exitr   r   r   withhold_connr#   r#   r$   borrow<  s|   



	zAsyncTrafficPolice.borrowc                 C  sd   | j }d}|d ur0| jd8  _|jdkr0| js,| j }|s*|j| j|j< |   |S |   |S )NFr   r   )	r   r   r   r   r   r   r   r   r   )rW   r   cursor_transferredr#   r#   r$   r     s   


zAsyncTrafficPolice.releasec              	     s   g }| j D ]}t| j | tju r|| q|D ]}| j |= qt| jt|kr-d| _|D ] }| j|}z	|	 I dH  W n	 t
yI   Y nw | | q/| j}|durb|j|v rd|   dS dS dS )zShutdown traffic pool.TN)r   r
   r   r6   rg   r   r   r   ry   r   r   r   r   r   r   )rW   planned_removalr   r   r   r#   r#   r$   rc     s0   



zAsyncTrafficPolice.clearc                 C  r   r=   )r   r   rZ   r#   r#   r$   qsize  r   zAsyncTrafficPolice.qsizec                 C  r   r=   r   rZ   r#   r#   r$   rsize  r   zAsyncTrafficPolice.rsizec                 C  s   t |  S r=   )rC   r   rZ   r#   r#   r$   empty  s   zAsyncTrafficPolice.emptyMappableTraffic | typec                   sx   t |tst |tr|nt|}|| jv S | j}z| |I d H d uW |s.| jr/|   S S S |s:| jr;|   w w w r=   )r   r   r   re   r   r   r   r   )rW   r   r   pre_acquired_connr#   r#   r$   r     s   




zAsyncTrafficPolice.beaconstrc                 C  sH   | j }| o| j}|rd}n|rd}nd}d|   d| j d| dS )N	SaturatedIdleUsedz<AsyncTrafficPolice /z (z)>)r   r   r   r   )rW   is_saturatedis_idlestatusr#   r#   r$   __repr__  s   zAsyncTrafficPolice.__repr__rm   )r   r2   r   rC   r   rC   )r%   r   r   r   )r   r   r%   rC   )r%   r   )r   r   r%   r<   )T)r   r   r   rC   r%   r0   )r   rC   r%   r<   )r%   r   )
r   r   r   r   r   rC   r   rC   r%   r<   )FF)r   rC   r   rC   r%   r0   )TNFF)
r   rC   r   r   r   rC   r   rC   r%   r0   r=   )r   r   r   r0   r%   r<   )r   r   r%   r<   ra   )r   r   r   rC   r   rC   r%   r   )TN)r   r   r   rC   r   r   r%   r0   )NTNF)
r   r   r   rC   r   r   r   rC   r%   r   )r   r   r%   rC   )r%   r   )$r   r   r    r!   rX   propertyr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   
contextlibasynccontextmanagerr   r   r   r   rc   r   r   r   r   r  r#   r#   r#   r$   r   y  st    

	



.
:2Zx
AU
L




r   )r%   r&   r   )r4   r   r%   rC   )4
__future__r   r'   rL   r  sysrA   typingdataclassesr   r   traffic_policer   r   r   r	   r
   r   contrib.ssa._timeoutr   r   _collectionsr   TYPE_CHECKING_async.connectionr   _async.connectionpoolr   _async.responser   backendr   poolmanagerr   Unionr   r"   r   TypeVarr   Genericr   r+   r,   r:   platformrx   r>   r@   rH   rI   r   r#   r#   r#   r$   <module>   sP     

	



  