
    j;                    n   d Z 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 ddlmZ ddlmZ ddlmZ  ee      j+                         j,                  Zed	z  Zed
z  ZdZdZ ed      ZddZddZddZddZ ddZ!dddZ"d ddZ# G d de      Z$d!dZ%d Z&e'dk(  r e&        yy)"uN   Local Executive Desk / Last Click — static files + submit + desk reply loop.    )annotationsN)datetimetimezone)SimpleHTTPRequestHandlerThreadingHTTPServer)Path)urlparse)ZoneInfostatecertsi="  i   zAmerica/Chicagoc                 f    t        j                  t        j                        j	                  d      S )Nz%Y-%m-%dT%H:%M:%SZ)r   nowr   utcstrftime     7/home/michael/Desktop/LOOK_AT_THESE/serve_last_click.pynow_isor      s!    <<%../CDDr   c                 R    t        j                  t              j                  d      S )Nz%Y-%m-%dT%H:%M:%S%z)r   r   CTr   r   r   r   now_ctr      s    <<$$%:;;r   c                    | j                         s|S 	 t        j                  | j                  d            S # t        $ r |cY S w xY w)Nutf-8encoding)existsjsonloads	read_text	Exception)pathdefaults     r   	read_jsonr#   !   sC    ;;=zz$..'.:;; s   $9 AAc                    | j                   j                  dd       | j                  t        j                  |d      d       y )NTparentsexist_ok   indentr   r   )parentmkdir
write_textr   dumps)r!   datas     r   
write_jsonr0   *   s4    KKdT2OODJJtA.OAr   c                   | j                         si S | j                  d      }|ddddd}t        j                  d|t        j                  t        j
                  z        }|r"|j                  d      j                         |d<   t        j                  d|t        j                        }|r"|j                  d      j                         |d	<   t        j                  d
|t        j                        }|r"|j                  d      j                         |d<   t        j                  d|t        j                        }|r|j                  d      }g }|j                         D ]_  }	|	j                  d      r|j                  |	dd        )|	j                  d      r|j                  |	dd        O|j                  |	       a dj                  |      j                         |d<   |S d|v rwt        j                  d|t        j                        }
|
rP|
j                  d      j                         j                  d      s"|
j                  d      j                         |d<   |S )z)Parse # submit / # reply markdown blocks.r   r    )rawkindtimefromtextz^#\s*(submit|reply)\s*$   r4   z^time:\s*(.+)$r5   z^from:\s*(.+)$r6   z!^text:\s*\|\s*\n((?:[ \t].*\n?)*)  r(   N	
r7   ztext:z^text:\s*(.+)$|)r   r   researchMIgrouplowerstrip
splitlines
startswithappendjoinrstrip)r!   r7   outmtmfrtxbodylineslinesms              r   parse_desk_mdrR   /   s   ;;=	>>7>+Db"b"MC
		,dBDD244K@Aggaj&&(F	$dBDD	1B	hhqk'')F	$dBDD	1B	hhqk'')F	7rtt	DB	xx{OO% 	#Dt$T!"X&&T!"X&T"	# ii&--/F J 
DYY($5bhhqk'')44S9((1+++-CKJr   c                   t               }dj                  d | xs dj                         D              xs d}d| d| d| d}t        j	                  dd	       t        d
z  j                  |d       t        dz  j                  dd      5 }|j                  | d| d| j                  t        d      d      d d  d       d d d        t        dz  j                  |dz   d       |S # 1 sw Y   (xY w)Nr;   c              3  .   K   | ]  }|rd |z   nd   ywr9   Nr   .0lns     r   	<genexpr>z"write_submit_md.<locals>.<genexpr>U        UR2dRi4/U   r2   r9   z# submit
time: 
from: 	
text: |
Tr%   latest_submit.mdr   r   chat_log.mda | 
      
CHAT_READY
r   rG   rD   STATEr,   r-   openwritereplacechrr7   from_whotsrN   mdfs         r   write_submit_mdrq   R   s   	B99UDJB;R;R;TUU]Y]D	d j  	
B 
KKtK,
++B+A
-
	%	%cG	%	< M	2$c(3t||CGS'A$3'G&HKLM
\%%b4i'%BIM Ms   7C..C7c                   t               }dj                  d | xs dj                         D              xs d}d| d| d| d}t        j	                  dd	       t        d
z  j                  |d       t        dz  j                  dd      5 }|j                  | d| d| j                  t        d      d      d d  d       d d d        |S # 1 sw Y   |S xY w)Nr;   c              3  .   K   | ]  }|rd |z   nd   ywrU   r   rV   s     r   rY   z!write_reply_md.<locals>.<genexpr>f   rZ   r[   r2   r9   z# reply
time: r\   r]   Tr%   latest_reply.mdr   r   r_   r`   ra   rb   rc   rd   rf   rl   s         r   write_reply_mdru   d   s    	B99UDJB;R;R;TUU]Y]D	d j  	
B 
KKtK,
**2*@
-
	%	%cG	%	< M	2$c(3t||CGS'A$3'G&HKLMIMIs   7CCc                  r     e Zd Z fdZ fdZd ZddZd Z fdZd Z	ddZ
dd	Zdd
ZddZd Z xZS )Handlerc                B    t        |   |dt        t              i| y )N	directory)super__init__strROOT)selfargskwargs	__class__s      r   r{   zHandler.__init__u   s    $>#d)>v>r   c                    | j                  dd       | j                  dd       | j                  dd       | j                  dd       t        | 	          y )	NAccess-Control-Allow-Origin*zAccess-Control-Allow-MethodszGET, POST, OPTIONSzAccess-Control-Allow-HeadersContent-TypeCache-Controlno-store)send_headerrz   end_headers)r~   r   s    r   r   zHandler.end_headersx   sR    6<79MN7H*5r   c                F    | j                  d       | j                          y )N   )send_responser   )r~   s    r   
do_OPTIONSzHandler.do_OPTIONS   s    3r   c                0   t        j                  |      j                  d      }| j                  |       | j	                  dd       | j	                  dt        t        |                   | j                          | j                  j                  |       y )Nr   r   zapplication/jsonContent-Length)
r   r.   encoder   r   r|   lenr   wfileri   )r~   codeobjrN   s       r   _json_responsezHandler._json_response   sp    zz#%%g.4 );<)3s4y>:

r   c                   t        | j                  j                  dd            }|r| j                  j	                  |      nd}	 t        j                  |j                  d      xs d      S # t
        j                  $ r Y y w xY w)Nr   0s   {}r   z{})	intheadersgetrfilereadr   r   decodeJSONDecodeError)r~   lengthr3   s      r   
_read_bodyzHandler._read_body   sn    T\\%%&6<=)/djjoof%U	::cjj19T::## 		s   'A. .BBc                   t        | j                        j                  j                  d      xs d}|dk(  r%| j                  dt	        t
        dz  dg i            S |dk(  r%| j                  dt	        t
        dz  dg i            S |d	k(  r%| j                  dt	        t
        d
z  dg i            S |dk(  rt        t
        dz        }t
        dz  }|j                         xr |j                         j                  dkD  }| j                  dd|j                  d      xs d|j                  d      xs d|j                  d      xs dt
        dz  j                         ||rdd      S dd      S |dk(  rt
        dz  }|j                         s| j                  dd      S |j                         }| j                  d       | j                  dd       | j                  dt        t!        |                   | j                  dd       | j                  dd       | j#                          | j$                  j'                  |       y |dk(  rxt        t
        d z        }| j                  dd|j                  d      xs d|j                  d      xs d|j                  d      xs dt
        d z  j                         d!      S |d"k(  rt
        d#z  }	 d$d l}d$d%lm} d}	|j                         r0|j)                         |j                         j.                  z
  }
|
d&kD  }	|	rB |d't        t0        d(z  d)z        gt        t0              t3        d*d+      t3        d*d+      ,       |j                         s| j                  dd-d.d/d i i d0      S | j                  dt	        |d1d-i            S t6        | q         S # t4        $ r Y `w xY w)2N/z/api/workers   workers.jsonworkersz/api/chat/threadchat_thread.jsonmessagesz
/api/queuez
queue.jsonitems
/api/replyrt   zlatest_reply.mp3Tr5   r2   r6   r7   z/api/reply/audio)okr5   r6   r7   r   audio	audio_url  zNo Eve voice clip yetr   z
audio/mpegr   r   r   r   r   z/api/submit/latestr^   )r   r5   r6   r7   r   z/api/metricszmetrics.jsonr   )Popeni,  python3	analyticszfetch_plausible.pyz/tmp/plausible_fetch.logr`   )cwdstdoutstderrFno_metrics_yetzURun: python3 analytics/fetch_plausible.py (needs PLAUSIBLE_API_KEY in analytics/.env))r   errorhintrealtimetodaydays30r   )r	   r!   rH   r   r#   rg   rR   r   statst_sizer   
send_error
read_bytesr   r   r|   r   r   r   ri   r5   
subprocessr   st_mtimer}   rh   r    rz   do_GET)r~   r!   parsed
audio_path	has_audior/   metrics_path_timer   staleager   s              r   r   zHandler.do_GET   s   		"''..s3:s>!&&sIen6LyZ\o,^__%%&&sIe>P6PS]_aRb,cdd<&&sIel6JWVXM,Z[[<"5+<#<=F!33J"))+O
0A0I0IC0OI&&"JJv.4""JJv.4""JJv.4"$'88@@B&7@!3  GI  %%!33J$$&s,CDD((*Ds#^\:-s3t9~>_j9:C@JJT"''"5+=#=>F&&"JJv.4""JJv.4""JJv.4"$'99AAC	 	 >! >1L$,&&(**,):):)<)E)EEC#IE"C{(:=Q(Q$RSI#$>D#$>D	  &&(**#!1 w$(!#"$
 
 &&sIlT5M,RSSw~  s   BN; ;	OOc                   t        | j                        j                  j                  d      }| j                         }|| j	                  dddd      S |dk(  r| j                  |      S |dk(  r| j                  |      S |dk(  r| j                  |      S |d	k(  r| j                  |      S | j                  d
d       y )Nr     FzInvalid JSONr   r   z/api/submitz	/api/chatr   z/api/workers/statusr   z	Not found)
r	   r!   rH   r   r   _submit_pack_chat_reply_worker_statusr   )r~   r!   payloads      r   do_POSTzHandler.do_POST   s    		"''..s3//#?&&s5>,RSS= $$W--;::g&&<;;w''((&&w//[)r   c           	     L   t         j                  dd       t               }||d<   |j                  d      xs t	        j
                  |d      }t        t         dz  |       t        t         d|j                  d	d
       dz  |       t         dz  j                  t        |      j                  d      st        |      j                  d      r|nd| d| dd       t         dz  j                  |dz   d       | j                  dd|t        t         dz        d       y )NTr%   _submitted_atpackr(   r)   zlatest_submit.jsonsubmit_:r2   z.jsonr^   z
LAST CLICKz# submitu   LAST CLICK submit — z

r;   r   r   READY_FOR_EVEr   )r   atr!   )rg   r,   r   r   r   r.   r0   rj   r-   r|   rE   r   )r~   r   rn   r7   s       r   r   zHandler._submit_pack   s"   D40Y#% {{6"Cdjj&C5//95WRZZR%8$9??I	#	#//I((6#d):N:Nz:ZDbxy{x|  }A  BF  AG  GI  aJ 	0 	
 
	 ,,R$Y,ICBEL^D^@_!`ar   c           	        t         j                  dd       |j                  d      xs dj                         }|j                  d      xs g }|j                  d      xs dj                         xs d}|s|s| j	                  dd	d
d      S |r|sddj                  d |D              z   }t        ||      }t         dz  }t        |dg i      }t        t        j                               d|||d}|j                  dg       j                  |       t        ||       t        t         dz  dg i      }	|	j                  dg       j                  |       t        t         dz  |	       t        t         dz  dg i      }
|
j                  dg       D ]!  }|j                  d      dk(  sd|d<   d|d<   # t               |
d<   t        t         dz  |
       | j	                  dddd ||d!       y")#uP   Phone/desk send → latest_submit.md. No fake Eve reply. Phone polls /api/reply.Tr%   r7   r2   filesr6   phoner   FzEmpty messager   z(attachment) z, c              3  t   K   | ]0  }t        |t              r|j                  d       n
t        |       2 yw)nameN)
isinstancedictr   r|   )rW   rp   s     r   rY   z Handler._chat.<locals>.<genexpr>  s/      /GH*Q"5v3q6A/s   68rm   r   r   user)idroler7   r   r   zchat_inbox.jsonpendingr   r   r   evewaitingstatusz!Desk message waiting on local Evedetailupdatedr   waiting_on_local_eve)r   savedr   r5   r   N)rg   r,   r   rC   r   rG   rq   r#   r|   uuiduuid4
setdefaultrF   r0   r   )r~   r   r7   r   rm   rn   thread_paththreaduser_msginboxr   ws               r   r   zHandler._chat  s   D40F#)r002G$*KK'2799;FwE&&s5?,STT"TYY /LQ/ & D TH500;R(89djjl#
 	*b)00:;'%"33i_EB'..x85,,e4EN2YODY+ 	BAuuT{e#'(A(	B %Y	5>)730 		
r   c                   |j                  d      xs dj                         }|s| j                  dddd      S |j                  d      xs dj                         xs d}t        ||	      }t	        t
        d
z  dg i      }t        t        j                               d||d}|j                  dg       j                  |       t        t
        d
z  |       t	        t
        dz  dg i      }|j                  dg       D ]!  }|j                  d      dk(  sd|d<   d|d<   # t               |d<   t        t
        dz  |       | j                  dd||d       y)z>TUI / desk_reply.py writes Eve's answer for the phone to poll.r7   r2   r   FzEmpty replyr   r6   	eve-localr   r   r   r   )r   r   r7   r   r   r   r   herer   zIn the room with your   r   r   T)r   r5   r6   N)r   rC   r   ru   r#   rg   r|   r   r   r   rF   r0   r   )	r~   r   r7   rm   rn   r   eve_msgr   r   s	            r   r   zHandler._reply5  sM   F#)r002&&s5=,QRRKK'6;==?N;D845#55
B7GHdjjl#	
 	*b)0095--v6EN2YODY+ 	5AuuT{e#$(4(	5 %Y	5>)73Cb(!KLr   c                D   t        t        dz  dg i      }|j                  d      }|j                  dg       D ]0  }|j                  d      |k(  sd|v r|d   |d<   d|v s)|d   |d<   2 t               |d<   t	        t        dz  |       | j                  dd|d	       y )
Nr   r   r   r   r   r   r   T)r   r   )r#   rg   r   r   r0   r   )r~   r   r   widr   s        r   r   zHandler._worker_statusQ  s    EN2YODkk$Y+ 	4AuuT{c!w&")("3AhKw&")("3AhK	4 %Y	5>)73C!ABr   c                H    t        d| j                         d||z         y )N[z] )printlog_date_time_string)r~   fmtr   s      r   log_messagezHandler.log_message^  s    4446d
CDr   )r   r   returnNone)r   r   r   r   )__name__
__module____qualname__r{   r   r   r   r   r   r   r   r   r   r   r   __classcell__)r   s   @r   rw   rw   t   sF    ?Q f* b/
bM8CEr   rw   c                 d   t         dz  t         dz  fg} t        t         j                  d            D ]$  }| j                  ||j	                  d      f       & dx}}| D ],  \  }}|j                         s|j                         s(||}} n |r|st        d       yt        dt        ft              }t        j                  t        j                        }|j                  t        |      t        |             |j                  |j                   d	      |_        t        d
t         d       |S )u@   Mic needs a secure context — Tailscale MagicDNS cert on :8443.zdads-envy.tail75cbe7.ts.net.crtzdads-envy.tail75cbe7.ts.net.keyz*.crtz.keyNu\   HTTPS skip — no Tailscale cert in certs/ (run: tailscale cert dads-envy.tail75cbe7.ts.net)0.0.0.0T)server_sidez1HTTPS (mic): https://dads-envy.tail75cbe7.ts.net:z/EXEC_DESK_MOCK.html)CERT_DIRsortedglobrF   with_suffixr   r   r   
HTTPS_PORTrw   ssl
SSLContextPROTOCOL_TLS_SERVERload_cert_chainr|   wrap_socketsocket)
candidatescrtcertkeykyhttpsctxs          r   _start_httpsr  b  s    
5	5xBc7cdJ hmmG,- :3 789:D3 R::<BIIKR#D slmJ 7AE
..00
1CD	3s8,??5<<T?BEL	=j\I]
^_Lr   c                 t   t         j                  dd       t         dz  j                         st        t         dz  dg i       t         dz  j                         st         dz  j	                  dd       t        j                  d	d
       t        dt        ft              } t        dt         d       t        d       t               }|r/t        j                  |j                  d      j                          	 | j                          y # t         $ r" t        d       |r|j#                          Y y Y y w xY w)NTr%   r   r   r_   z# desk chat log
r   r   zapplication/javascriptz.jsr  zExecutive Desk: http://0.0.0.0:z(/EXEC_DESK_MOCK.html  (LAN/Tailscale OK)uM   Chat POST /api/chat → latest_submit.md · GET /api/reply · POST /api/reply)targetdaemonz	
Stopped.)rg   r,   r   r0   r-   	mimetypesadd_typer   PORTrw   r   r  	threadingThreadserve_foreverstartKeyboardInterruptshutdown)httpdr  s     r   mainr(  y  s   	KKtK,&&..05--
B/?@M!))+		**+>*Q/7D 17;E	+D61Y
Z[	
YZNE 3 3DAGGI lNN s   ;D &D76D7__main__)r   r|   )r!   r   )r!   r   r   r   )r!   r   r   r   )r   )r7   r|   rm   r|   r   r|   )r   )r   zThreadingHTTPServer | None)(__doc__
__future__r   r   r  r=   r  r!  r   r   r   http.serverr   r   pathlibr   urllib.parser	   zoneinfor
   __file__resolver+   r}   rg   r  r   r  r   r   r   r#   r0   rR   rq   ru   rw   r  r(  r  r   r   r   <module>r2     s    T "   	 
   ' E  ! H~&&w'>
 E<B
 F$ kE& kE\.. zF r   