
    @j&                    `   S r SSKJr  SSKrSSKrSSKrSSKrSSKrSSKJ	r	  \	" \
5      R                  5       R                  r\S-  rSSSS	S
S.rSS jrSS jrSS jrS S jrS!S jrS"S#S jjrS$S jrS%S jrSS.S&S jjrS'S jrS(S jrS'S jrS'S jrS)S jr\S:X  a  \" \" 5       5      eg)*a  NW AL Scanner process cleanup / preflight helper.

Purpose:
- STOP_* must stop the launcher *and* any orphan service processes that survived it.
- START_* must not silently adopt an old parser/server left over from a previous build.

This script is intentionally conservative: it only force-stops listeners whose
command lines identify them as one of this platform's known services.
    )annotationsN)Pathtenants)zserve_v097_incident_video.py)zpeet_server_hazcams_wu.py)z	server.jszlightning-radar-dashboard)zplatform_launcher.py)zradio_intelligence_server.pycorepeet	lightning
operationsradio_intelligencec                    [         U -  S-  nUR                  5       (       d  [        SU  35      e[        R                  " UR                  SS95      $ )Nzstation.jsonzTenant not found: z	utf-8-sigencoding)TENANTS_DIRexists
SystemExitjsonloads	read_text)	tenant_idpaths     platform_process_control.pyload_tenantr       sI    "^3D;;==-i[9::::dnnkn:;;    c                     [         S-  S-  U -  $ )Nruntime	instances)BASE_DIR)r   s    r   runtime_dirr   '   s    i+-	99r   c                    [         R                  S:w  a   [         R                  " U S5        g[        R
                  " SSSU  3SS	S
/SSSS9nSU  S3UR                  ;   $ ! [         a     gf = f)Nntr   TFtasklistz/FIzPID eq z/FOCSVz/NHreplacecapture_outputtexterrors")osnamekillOSError
subprocessrunstdout)pidcps     r   	pid_aliver2   +   s|    	ww$	GGCO 
	UgcUOUE5A$y
B se1:""  		s   A! !
A.-A.c                   [         R                  S:w  a  U SSS.$ S[        U 5       S3n[        R                  " SSSU/S	S	S
S9nUR
                  R                  5       nU(       d  g  [        R                  " U5      $ ! [         a     g f = f)Nr     )	ProcessIdNameCommandLinez6$p=Get-CimInstance Win32_Process -Filter "ProcessId = z" -ErrorAction SilentlyContinue; if($p){$p | Select-Object ProcessId,Name,ExecutablePath,CommandLine,ParentProcessId | ConvertTo-Json -Compress}
powershell
-NoProfile-CommandTr#   r$   )
r)   r*   intr-   r.   r/   stripr   r   	Exception)r0   psr1   r&   s       r   process_infor?   9   s    	ww$ "R@@
A#c( Lz 	z  
|ZDUY`dmv	wB99??Dzz$ s   (A> >
B
Bc                   [         R                  S:w  a  / $ S[        U 5       S3n[        R                  " SSSU/SSSS	9nUR
                  R                  5       nU(       d  / $  [        R                  " U5      n[        U[        5      (       a  U/$ U=(       d    /  Vs/ s H  n[        U5      PM     sn$ ! [         a    / s $ f = fs  snf )
Nr    z Get-NetTCPConnection -LocalPort z} -State Listen -ErrorAction SilentlyContinue | Select-Object -ExpandProperty OwningProcess -Unique | ConvertTo-Json -Compressr8   r9   r:   Tr#   r$   )r)   r*   r;   r-   r.   r/   r<   r   r   r=   
isinstance)portr>   r1   r&   dataxs         r   listener_pidsrE   J   s    	ww$	
*3t9+ 6Y 	Y  
|ZDUY`dmv	wB99??D	zz$ $v!ZRZ)ZqCFZ))	  	 *s   %B8  C
8CCTc                   [        U 5      (       d  g[        R                  S:X  a  SS[        U 5      /nU(       a  UR	                  S5        UR	                  S5        [
        R                  " U[
        R                  [
        R                  S9nUR                  S:H  =(       d    [        U 5      (       + $  [        R                  " U S	5        g! [         a     gf = f)
NTr    taskkillz/PIDz/Tz/F)r/   stderrr      )r2   r)   r*   strappendr-   r.   DEVNULL
returncoder+   r,   )r0   treecmdr1   s       r   rG   rG   ^   s    S>>	ww$63s8,JJt

4^^C
(:(::CUCUV}}!73%77
R s   6C 
CCc                   ^ U (       d  g[        U R                  S5      =(       d    S5      R                  5       mU[        S   :X  a  [	        U4S jU 5       5      $ [        U4S jU 5       5      $ )NFr7   r4   r	   c              3  H   >#    U  H  oR                  5       T;   v   M     g 7fNlower.0scommands     r   	<genexpr>$signature_matches.<locals>.<genexpr>u   s     <A779'   "c              3  H   >#    U  H  oR                  5       T;   v   M     g 7frR   rS   rU   s     r   rY   rZ   v   s     8ZwwyG#Zr[   )rJ   getrT   KNOWN_PORT_SIGNATURESallany)info
signaturesrX   s     @r   signature_matchesrc   o   sZ    $((=)/R0668G*;77<<<<8Z888r   c                   [        U 5      S-  nUR                  5       (       d  g  [        UR                  SS9R	                  5       5      nU(       ac  [        U5      (       aS  [        SU S35        [        USS9  [        S	5       H+  n[        U5      (       d    O[        R                  " S
5        M-      UR                  SS9  g ! [
         a    Sn Nf = f! [
         a     g f = f)Nplatform_launcher.pidutf-8r   r   zStopping platform launcher PID z and its child tree...TrN      g?
missing_ok)r   r   r;   r   r<   r=   r2   printrG   rangetimesleepunlink)r   pidfiler0   _s       r   stop_launcher_from_pidfilerr   y   s    )$'>>G>>'##W#5;;=> y~~/u4JKL4 rAS>>JJsO $'    s#   &C 7C CC
C&%C&verbosec               p   U R                  S5      =(       d    0 nU R                  S5      =(       d    0 n[        UR                  SS5      5      [        UR                  SS5      5      [        UR                  SS5      5      S[        UR                  SS5      5      S	.nS
nS GH  nUR                  U5      (       d  M  UR                  U5      nUc  M2  [        [        U5      5       H  n[	        U5      n	[        U	[        U   5      (       aG  U(       a(  [        SU SU SU SU	R                  SS5       S3	5        [        USS9(       a  US-  nMk  Mm  U(       d  Mv  [        U	=(       d    0 R                  S5      =(       d    S5      n
[        SU SU S35        [        SU
 35        M     GM     U$ )Nportsservicesr   Tr   Flightning_dashboardr   r   r   )r   r   r	   r   r
   zStopping stale z listener on port z: PID z (r6   process)rg      r7   zunknown processzWARNING: port z, is occupied by an unrecognized process PID z; leaving it untouched.z	         )
r]   boolrE   r;   r?   rc   r^   rk   rG   rJ   )tenantrt   rv   rw   role_enabledstoppedrolerB   r0   ra   rO   s              r   stop_known_port_ownersr      s   JJw%2Ezz*%+HX\\&$/0X\\&%01(,,'<dCD"8<<0De#LML GQ%%yy< T+C$D '<T'BCCOD61CD6PSuTVW[W_W_`fgpWqVrrstuCd+qLG ,4:2**=9N=NOtf,XY\X]]tuv	#'( , R" Nr   c                Z   [         R                  S:w  a  g[        [        U 5      S-  R	                  5       5      R                  5       R                  SS5      nSU S3n[        R                  " SS	S
U/SSSS9nUR                  R                  5       nU(       d  g [        R                  " U5      n[        U[        5      (       a  U/O[!        U=(       d    / 5      nSnU H4  n[#        SU SU  S35        [%        [        U5      SS9(       d  M/  US-  nM6     U$ ! [         a     gf = f)zOSpark has no listen port, so identify this tenant by its --output-dir argument.r    r   r	   'z''z$items=Get-CimInstance Win32_Process | Where-Object { $_.Name -match '^py(?:thon(?:w)?(?:3(?:\.\d+)?)?)?\.exe$' -and $_.CommandLine -like '*spark_lightning_bridge_v003.py*' -and $_.CommandLine.ToLower().Contains('zQ') }; $items | Select-Object -ExpandProperty ProcessId | ConvertTo-Json -Compressr8   r9   r:   Tr#   r$   z Stopping stale Spark bridge PID z for z...rg   r{   )r)   r*   rJ   r   resolverT   r#   r-   r.   r/   r<   r   r   r=   rA   r;   listrk   rG   )	r   markerr>   r1   r&   rC   pidscountr0   s	            r   stop_spark_for_tenantr      s)   	ww$+i(;6??ABHHJRRSVX\]F	. /5X 6Y	Y  
|ZDUY`dmv	wB99??Dzz$  c**D6TZR0@DE0U9+SIJCH4((QJE  L  s   D 
D*)D*c                   U R                  S5      =(       d    0 nU R                  S5      =(       d    0 nSS/nUR                  SS5      (       a  UR                  S5        UR                  SS5      (       a  UR                  S	5        UR                  S
S5      (       a  UR                  S
5        / nU HY  nUR                  U5      nUc  M  [        [        U5      5      (       d  M4  UR                  XV[        [        U5      5      45        M[     U(       aI  [	        S5        U H7  u  pVn[	        SU SU SSR                  [        [        U5      5       35        M9     gg)Nrv   rw   r   r
   r   Frx   Tr	   r   z.One or more required ports are still occupied:z  z: port z	, PID(s) z, )r]   rK   rE   r;   rk   joinmaprJ   )r}   rv   rw   rolesbusyr   rB   r   s           r   verify_ports_freer      s$   JJw%2Ezz*%+H\"E||FE""V||)400[!||(%00)*Dyyc$i 8 8KK]3t9%=>?  >? $DBtfGD6499ST]3K2LMN !%r   c                *   [        U 5      n[        SUR                  SU 5       35        [        U 5        [	        U5        [        U 5        [        R                  " S5        [	        USS9  [        U5      nU(       a  [        S5        g[        S5        g	)
NzNWAL process cleanup: display_nameg      ?Frs   z>All managed listeners are stopped and required ports are free.r   z>STOP completed with warnings. Review the occupied ports above.   )	r   rk   r]   rr   r   r   rm   rn   r   )r   r}   oks      r   do_stopr      sz    #F	"6::ni#H"I
JKy)6")$JJsO651	6	"B	NO	
JKr   c                   [        U 5      n[        U 5      S-  nUR                  5       (       a^   [        UR	                  SS9R                  5       5      nU(       a   [        U5      (       a  [        SU S35        g UR                  SS	9  [        U5        [        U 5        [        R                  " S
5        [        U5      (       d  [        S5        g[        S5        g! [         a    Sn Nf = f! [         a     Nrf = f)Nre   rf   r   r   z,Platform launcher is already running as PID .   Tri   gffffff?zPPreflight failed. A required port is occupied by a process we did not recognize.r   z5Preflight OK: no stale NWAL service processes remain.)r   r   r   r;   r   r<   r=   r2   rk   ro   r   r   rm   rn   r   )r   r}   rp   r0   s       r   do_preflightr      s    #F)$'>>G~~	g'''9??ABC 9S>>@QGH	NNdN+
 6")$JJtV$$`a	
AB%  	C	  		s#   &C! >C3 !C0/C03
D ?D c                    [        [        R                  5      S:w  d  [        R                  S   S;  a  [        S5        g[        R                  S   [        R                  S   pU S:X  a  [	        U5      $ [        U5      $ )Nr   r{   >   stop	preflightzFUsage: py -X utf8 platform_process_control.py stop|preflight TENANT_ID@   r   r   )lensysargvrk   r   r   )actionr   s     r   mainr     sa    
388}SXXa[0EEVWSXXa[I!'6!179N|I7NNr   __main__)r   rJ   returndict)r   rJ   r   r   )r0   r;   r   r|   )r0   r;   r   dict | None)rB   r;   r   z	list[int])T)r0   r;   rN   r|   r   r|   )ra   r   rb   ztuple[str, ...]r   r|   )r   rJ   r   None)r}   r   rt   r|   r   r;   )r   rJ   r   r;   )r}   r   r   r|   )r   r;   ) __doc__
__future__r   r   r)   r-   r   rm   pathlibr   __file__r   parentr   r   r^   r   r   r2   r?   rE   rG   rc   rr   r   r   r   r   r   r   __name__r    r   r   <module>r      s    #  	  
  >!!#**" .*;+; <:#"*("9, =A >:.$6O z
TV
 r   