
    Mi>+                         S SK JrJrJrJr  S SKJrJr  S SKJ	r	  S SK
r
S SKrS SKr " S S5      r " S S\5      r " S	 S
\5      rg)    )ListDictOptionalTuple)ABCabstractmethod)cycleNc            
           \ rS rSr   SS\S\\   S\\   S\\   4S jjrS\\   4S	 jr\S
\SS 4S j5       r	\S\
SS 4S j5       r\SS\S\S    4S jj5       rS\
4S jrSS jrSrg)ProxyConfig   Nserverusernamepasswordipc                 d    Xl         X l        X0l        U=(       d    U R                  5       U l        g)a  Configuration class for a single proxy.

Args:
    server: Proxy server URL (e.g., "http://127.0.0.1:8080")
    username: Optional username for proxy authentication
    password: Optional password for proxy authentication
    ip: Optional IP address for verification purposes
N)r   r   r   _extract_ip_from_serverr   )selfr   r   r   r   s        q/var/www/eduai.edurigo.com/storigo/production/storigo_env/lib/python3.13/site-packages/crawl4ai/proxy_strategy.py__init__ProxyConfig.__init__   s*        6446    returnc                      SU R                   ;   a2  U R                   R                  S5      S   R                  S5      nUS   $ U R                   R                  S5      nUS   $ ! [         a     gf = f)z#Extract IP address from server URL.z://   :r   N)r   split	Exception)r   partss     r   r   #ProxyConfig._extract_ip_from_server#   so    		#))%0399#>Qx))#.Qx 		s   AA$ A$ $
A10A1	proxy_strc                     U R                  S5      n[        U5      S:X  a  Uu  p#pE[        SU SU 3UUUS9$ [        U5      S:X  a  Uu  p#[        SU SU 3US9$ [        SU  35      e)zMCreate a ProxyConfig from a string in the format 'ip:port:username:password'.r      zhttp://r   r   r   r      )r   r   zInvalid proxy string format: )r   lenr   
ValueError)r    r   r   portr   r   s         r   from_stringProxyConfig.from_string0   s     $u:?+0(Bh AdV,!!	  Z1_HB AdV, 
 <YKHIIr   
proxy_dictc                     [        U R                  S5      U R                  S5      U R                  S5      U R                  S5      S9$ )z'Create a ProxyConfig from a dictionary.r   r   r   r   r#   )r   get)r*   s    r   	from_dictProxyConfig.from_dictE   sA     >>(+^^J/^^J/~~d#	
 	
r   env_varc                    / n [         R                  " U S5      R                  S5      nU H0  nU(       d  M  UR                  [        R                  U5      5        M2     U$ ! [         a  n[        SU 35         SnAU$ SnAff = f)zLoad proxies from environment variable.

Args:
    env_var: Name of environment variable containing comma-separated proxy strings
    
Returns:
    List of ProxyConfig objects
 ,z(Error loading proxies from environment: N)osgetenvr   appendr   r(   r   print)r/   proxies
proxy_listproxyes        r   from_envProxyConfig.from_envO   s     	B7B/55c:J#{66u=> $   	B<QC@AA	Bs   AA" "
B,B  Bc                 `    U R                   U R                  U R                  U R                  S.$ )z%Convert to dictionary representation.r#   r#   r   s    r   to_dictProxyConfig.to_dictd   s*     kk''	
 	
r   c                 n    U R                  5       nUR                  U5        [        R                  U5      $ )zCreate a copy of this configuration with updated values.

Args:
    **kwargs: Key-value pairs of configuration options to update

Returns:
    ProxyConfig: A new instance with the specified updates
)r?   updater   r-   )r   kwargsconfig_dicts      r   cloneProxyConfig.clonem   s.     lln6"$$[11r   )r   r   r   r   )NNN)PROXIES)r   r   )__name__
__module____qualname____firstlineno__strr   r   r   staticmethodr(   r   r-   r   r;   r?   rE   __static_attributes__ r   r   r   r      s     #'"& 77 3-7 3-	7
 SM7,#  Js J} J J( 
d 
} 
 
 # d=.A  (
 
2r   r   c            	           \ rS rSrSr\S\\   4S j5       r\S\	\   4S j5       r
\ SS\S	\\   S\\   4S
 jj5       r\S\SS4S j5       r\S\S\\   4S j5       r\S\\\4   4S j5       rSrg)ProxyRotationStrategy{   z1Base abstract class for proxy rotation strategiesr   c                    #    g7f)z.Get next proxy configuration from the strategyNrO   r>   s    r   get_next_proxy$ProxyRotationStrategy.get_next_proxy~   s
      	   r7   c                     g)z(Add proxy configurations to the strategyNrO   r   r7   s     r   add_proxies!ProxyRotationStrategy.add_proxies   s     	r   N
session_idttlc                    #    g7faN  
Get or create a sticky proxy for a session.

If session_id already has an assigned proxy (and hasn't expired), return it.
If session_id is new, acquire a new proxy and associate it.

Args:
    session_id: Unique session identifier
    ttl: Optional time-to-live in seconds for this session

Returns:
    ProxyConfig for this session
NrO   )r   r[   r\   s      r   get_proxy_for_session+ProxyRotationStrategy.get_proxy_for_session   s
     & 	rV   c                    #    g7fzk
Release a sticky session, making the proxy available for reuse.

Args:
    session_id: Session to release
NrO   r   r[   s     r   release_session%ProxyRotationStrategy.release_session   s
      	rV   c                     gz
Get the proxy for an existing session without creating new one.

Args:
    session_id: Session to look up

Returns:
    ProxyConfig if session exists and hasn't expired, None otherwise
NrO   rc   s     r   get_session_proxy'ProxyRotationStrategy.get_session_proxy   s     	r   c                     g)z\
Get all active sticky sessions.

Returns:
    Dictionary mapping session_id to ProxyConfig
NrO   r>   s    r   get_active_sessions)ProxyRotationStrategy.get_active_sessions   s     	r   rO   N)rH   rI   rJ   rK   __doc__r   r   r   rT   r   rY   rL   intr_   rd   rh   r   rk   rN   rO   r   r   rQ   rQ   {   s    ;h{&;   4#4    " c] 
+		 (     
C 
H[4I 
 
 T#{*:%;  r   rQ   c                       \ rS rSrSrSS\\   4S jjrS\\   4S jrS\	\   4S jr
 SS	\S
\	\   S\	\   4S jjrS	\SS4S jrS	\S\	\   4S jrS\\\4   4S jrS\4S jrSrg)RoundRobinProxyStrategy   a  Simple round-robin proxy rotation strategy using ProxyConfig objects.

Supports sticky sessions where a session_id can be bound to a specific proxy
for the duration of the session. This is useful for deep crawling where
you want to maintain the same IP address across multiple requests.
Nr7   c                     / U l         SU l        0 U l        [        R                  " 5       U l        U(       a  U R                  U5        gg)zg
Initialize with optional list of proxy configurations

Args:
    proxies: List of ProxyConfig objects
N)_proxies_proxy_cycle	_sessionsasyncioLock_session_lockrY   rX   s     r   r    RoundRobinProxyStrategy.__init__   s>     ,. NP$\\^W% r   c                 n    U R                   R                  U5        [        U R                   5      U l        g)z$Add new proxies to the rotation poolN)rt   extendr	   ru   rX   s     r   rY   #RoundRobinProxyStrategy.add_proxies   s%    W%!$--0r   r   c                 X   #    U R                   (       d  g[        U R                   5      $ 7f)z%Get next proxy in round-robin fashionN)ru   nextr>   s    r   rT   &RoundRobinProxyStrategy.get_next_proxy   s"       D%%&&s   (*r[   r\   c                 "  #    U R                    ISh  vN   XR                  ;   am  U R                  U   u  p4nUb  UOUnUb>  [        R                  " 5       U-
  nXv:  a  U R                  U	 O&UsSSS5      ISh  vN   $ UsSSS5      ISh  vN   $ U R                  5       I Sh  vN nU(       a%  U[        R                  " 5       U4U R                  U'   UsSSS5      ISh  vN   $  N Nq N` NI N! , ISh  vN  (       d  f       g= f7fr^   )ry   rv   timerT   )r   r[   r\   r9   
created_atsession_ttleffective_ttlelapseds           r   r_   -RoundRobinProxyStrategy.get_proxy_for_session   s     $ %%%^^+15
1K.; (+K ,"iikJ6G/ NN:6$ &%% ! &%%$ --//E.3TYY[#-Fz*- &%%$ 0% &%%%s   DC+DAC5/D;C-<DC5DC/DC5'C1(1C5D%C3&D-D/D1C53D5D;C><DDc                    #    U R                    ISh  vN   XR                  ;   a  U R                  U	 SSS5      ISh  vN   g N1 N! , ISh  vN  (       d  f       g= f7frb   )ry   rv   rc   s     r   rd   'RoundRobinProxyStrategy.release_session  s=      %%%^^+NN:. &%%%%%sB   A#AA#A	A#A A#A#	A AA A#c                     XR                   ;  a  gU R                   U   u  p#nUb  [        R                  " 5       U-
  nXT:  a  gU$ rg   )rv   r   )r   r[   r9   r   r\   r   s         r   rh   )RoundRobinProxyStrategy.get_session_proxy  sH     ^^+!%
!;3 ?iikJ.G~r   c                     [         R                   " 5       n0 nU R                  R                  5        H  u  nu  pEnUb  X-
  nXv:  a  M  XBU'   M     U$ )zu
Get all active sticky sessions (excluding expired ones).

Returns:
    Dictionary mapping session_id to ProxyConfig
)r   rv   items)r   current_timeactive_sessionsr[   r9   r   r\   r   s           r   rk   +RoundRobinProxyStrategy.get_active_sessions-  s[     yy{48NN4H4H4J0J0C&3>*/J' 5K r   c                   #    U R                    ISh  vN   [        R                  " 5       n/ nU R                  R                  5        H*  u  nu  pEnUc  M  X-
  nXv:  d  M  UR	                  U5        M,     U H  nU R                  U	 M     [        U5      sSSS5      ISh  vN   $  N N! , ISh  vN  (       d  f       g= f7f)zU
Remove all expired sessions from tracking.

Returns:
    Number of sessions removed
N)ry   r   rv   r   r5   r%   )r   r   expiredr[   r9   r   r\   r   s           r   cleanup_expired_sessions0RoundRobinProxyStrategy.cleanup_expired_sessionsA  s      %%%99;LG8<8L8L8N4
4U?*7G~z2	 9O &
NN:. & w< &%%%%%sP   CB)C<B-B-"5B-C#B+$C+C-C3B64C C)rt   ru   ry   rv   rm   )rH   rI   rJ   rK   rn   r   r   r   rY   r   rT   rL   ro   r_   rd   rh   r   rk   r   rN   rO   r   r   rq   rq      s    &[ 1 & 14#4 1
'h{&; ' "(( c]( 
+		(T	/ 	/ 	/C H[4I .T#{*:%; (   r   rq   )typingr   r   r   r   abcr   r   	itertoolsr	   r3   rw   r   r   rQ   rq   rO   r   r   <module>r      sE    . . #  	  l2 l2^AC AFW 3 W r   