+
    j                         R t ^ RIt^ RIt^ RIt^ RIt^ RIHt ^RIHt ^t	Rt
^tR tR	R lt ! R R]P                  4      tR# )
u   sshj.probe — reachability probing (bounded pool).

B2 step 3d: moved verbatim from sshj_cli.py (single-file era) — no
behavior change. Owns PROBE_TIMEOUT (main's direct probe imports
it back). Edge: tailnet.ssh_host (probe args resolve via it).
N)ThreadPoolExecutor)ssh_hostg?c           
          V P                  R 4      '       dK   \        V 4      pR.pV P                  R4      R9  d   VRV R,          .,          pVRRRRRRRVR	.	,          pV# RRRRRRRRV R
,          R	.
pV# )srcsshportz-p-ozBatchMode=yeszStrictHostKeyChecking=nozLogLevel=ERRORz--truealias) 22)getr   )htgtargss   &  src/sshj/probe.py_probe_argsr      s    uuU||qkw55=
*T1V9%%D.H'sF< 	<4$0J"D!G*f>DK    c           
         \        V4      R9  d-   \        ^\        \        \	        V4      4      \
        4      4      M\
        p\        V 4      pRRV 2.VR&    \        P                  ! 4       p\        P                  ! V\        P                  \        P                  R7      p\        P                  ! 4       V,           ^,           pVP                  4       f   Ve9   VP                  4       '       d#   VP                  4        VP                  4        R# \        P                  ! 4       V8  d#   VP                  4        VP                  4        R# \        P                   ! \"        4       K  VP$                  ^ 8H  p\        P                  ! 4       V,
          R,          p	Y'       d   V	3# R3#   \         d    \
        p EL}i ; i  \&         d    Ru # i ; i)	uT  Returns (up: bool, latency_ms: float|None) via a timed ssh round-trip.

`stop_event` (optional, a threading.Event): when set, the in-flight ssh
is KILLED and the probe returns down — a quit must be instant, so the
pool's workers can be interrupted (2026-09-21: Esc blocked on
concurrent.futures' atexit hook waiting for in-flight probes).r   zConnectTimeout=:   r   N)stdoutstderrNg     @@)r   none)FN)strmaxminintfloatPROBE_TIMEOUT
ValueErrorr   time
subprocessPopenDEVNULLpollis_setkillwaitsleep
PROBE_POLL
returncode	Exception)
r   	timeout_s
stop_eventtr   t0pendupmss
   &&&       r   prober4   &   sh   ADYWcAcC3s5+,m<=iv q>D,-DIYY[T**<*<$.$6$68iikAo!ffh%**;*;*=*=""yy{c!""JJz"\\QiikB&("B''$''+  ,  s>   AF- BG 3!G ;G AG *G -GGGGc                   j   a a ] tR t^It oRtV 3R lt]R 4       tR tR t	R t
R tR tR	 tR
tVtV ;t# )CheckeruE  Probes hosts in a bounded worker pool (B14), in priority order,
until the screen dies. One probe at a time (the old behavior) is
SSHJ_PROBE_CONCURRENCY=1; default is 3 — a pool of N ssh round-trips
that each cost <5s used to serialise to N×5s, so the pool probes
visible rows first and the rest fill in as workers free up.c                  < \         SV `  R R7       V Uu/ uF  q"R,          VbK  	  upV n        / V n        / V n        \
        P                  ! 4       V n        V Uu. uF  q"R,          NK  	  upV n        \
        P                  ! 4       V n
        RV n        \
        P                  ! 4       V n        V P                  4       V n        \        V P                  RR7      V n        R# u upi u upi )T)daemonr
   Fr4   )max_workersthread_name_prefixN)super__init__by_aliasstatuslatency	threadingLocklockorderEventkickdonestop_ev
_pool_size	pool_sizer   pool)selfhostsr   	__class__s   && r   r<   Checker.__init__P   s    %05617Q6NN$	*/0%Qjj%0
OO%		
 !(*&7D	 7 1s   C#C(c                      \        \        P                  P                  R R4      4      p \	        ^\        ^V 4      4      #   \         d
    \        u # i ; i)SSHJ_PROBE_CONCURRENCYr   )r   osenvironr   r   r   r   PROBE_POOL_DEFAULT)ns    r   rH   Checker._pool_sizeb   sI    	&BJJNN#;R@AAq#b!*%% 	&%%	&s   >A AAc                N   V P                   ;_uu_ 4        VR ,          V P                  9   d    RRR4       R# WP                  VR ,          &   V P                  P                  VR ,          4       RRR4       V P                  P                  4        R#   + '       g   i     L,; i)r
   N)rB   r=   rC   appendrE   set)rK   r   s   &&r   add_hostChecker.add_hostj   si    YYYzT]]* Y )*MM!G*%JJaj)	 
 			 Ys   B7BB$	c                    V P                   ;_uu_ 4        \        \        P                  V4      4      V n        R R R 4       V P
                  P                  4        R #   + '       g   i     L,; iN)rB   listdictfromkeysrC   rE   rX   )rK   ordered_aliasess   &&r   reprioritizeChecker.reprioritizer   s:    YYYdmmO<=DJ 		 Ys   $AA-	c                |    R V n         V P                  P                  4        V P                  P                  4        R# )TN)rF   rG   rX   rE   rK   s   &r   stopChecker.stopw   s&    			r   c                x   V P                   ;_uu_ 4        V P                   Uu. uF  qV P                  9  g   K  VNK  	  ppV F  pRV P                  V&   K  	  V Uu. uF  qP                  V,          NK  	  ppRRR4       X'       g   R# \        P                  ! 4       pV F)  pV P
                  P                  V P                  V4       K+  	  \        P                  ! ^ 4       V P                  '       gq   V P                   ;_uu_ 4        X Uu. uF&  qP                  P                  V4      R9  g   K$  VNK(  	  ppRRR4       X'       g   M\        P                  ! R4       K  \        P                  ! 4       V,
          # u upi u upi   + '       g   i     EL; iu upi   + '       g   i     Lp; i)zProbe every host not yet measured, concurrently under the pool.
Returns seconds the pass took (0.0 when there was nothing to do).
The thread loop calls this; tests call it directly (deterministic).checkNg        g?)r2   down)rB   rC   r>   r=   r    rJ   submit
_probe_oner(   rF   r   )rK   atodorL   r/   r   missings   &      r   run_onceChecker.run_once|   s6    YYY#zzBz!dkk-AAAzDB!(A /34t!]]1%%tE4	 
 YY[AIIT__a0 

1)))&* +dkkooa.@)/*11d +  JJtyy{R% C 5	 YY+ sQ   FFFFF:FF)!F$9F$?F)
FF!	$F))F9	c                   VR ,          p\        WP                  RR4      V P                  R7      w  r4V P                  ;_uu_ 4        V P                  '       d   W P
                  9  d    RRR4       R# V'       d   RMRV P                  V&   Ve   W@P                  V&   RRR4       V P                  P                  4        R#   + '       g   i     L,; i)r
   timeoutr   )r-   Nr2   ri   )
r4   r   rG   rB   rF   r=   r>   r?   rE   rX   )rK   r   r
   r2   r3   s   &&   r   rk   Checker._probe_one   s    '
q%%	2.4<<HYYYyyyU--7 Y *,DKK~&(U#  			 Ys   $C5C=#CC	c                    V P                   '       g\   V P                  4        V P                   '       d   R# V P                  P                  R 4       V P                  P	                  4        Km  R# )g      ?N)rF   ro   rE   r'   clearrd   s   &r   runChecker.run   sC    )))MMOyyyIINN3IIOO r   )
r=   rF   rE   r?   rB   rC   rJ   rI   r>   rG   )__name__
__module____qualname____firstlineno____doc__r<   staticmethodrH   rY   ra   re   ro   rk   rv   __static_attributes____classdictcell____classcell__)rM   __classdict__s   @@r   r6   r6   I   sH     CD$ & &

 2	 r   r6   r\   )r|   rQ   r!   r@   r    concurrent.futuresr   tailnetr   r   r)   rS   r   r4   Threadr6    r   r   <module>r      sO    
    1  
  F]i ]r   