
    )joR                        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Zd dlZd dlZd dl	m
Z
 d dlmZ d dlmZ  ej        e          ZdZdZdZdZd	Zd
 Zd Zd Zd Zd Zd Zd Zd Zd Z G d d          Z  G d d          Z! G d de!          Z" G d d          Z# G d d          Z$d Z%d Z&d$d Z'd%d"Z(ed#k    r e'             dS dS )&    N)Path)choice)backends   i  i  i  a  
Here is a sample of what a configuration file could look like:

    {
        // ===============================
        // General launcher configuration
        // ===============================

        "configuration": {
            "host" : "localhost",
            "port" : 8080,
            "endpoint": "paraview",                   // SessionManager Endpoint
            "content": "/.../www",                    // Optional: Directory shared over HTTP
            "proxy_file" : "/.../proxy-mapping.txt",  // Proxy-Mapping file for Apache
            "sessionURL" : "ws://${host}:${port}/ws", // ws url used by the client to connect to the started process
            "timeout" : 25,                           // Wait time in second after process start
            "log_dir" : "/.../viz-logs",              // Directory for log files
            "fields" : ["file", "host", "port"]       // List of fields that should be send back to client
                                                             // include "secret" if you provide it as an --authKey to the app
            "sanitize": {                             // Check information coming from the client
                "cmd": {
                    "type": "inList",                 // 'cmd' must be one of the strings in 'list'
                    "list": [
                        "me", "you", "something/else/altogether", "nothing-to-do"
                    ],
                    "default": "nothing-to-do"        // If the string doesn't match, replace it with the default.
                                                      // Include the default in your list
                },
                "cmd2": {                             // 'cmd2' must match the regexp provided, example: not a quote
                    "type": "regexp",
                    "regexp": "^[^"]*$",             // Make sure to include '^' and '$' to match the entire string!
                    "default": "nothing"
                }
            }
        },

        // ===============================
        // Useful session vars for client
        // ===============================

        "sessionData" : { "key": "value" },      // Dictionary of values interesting to the client

        // ===============================
        // Resources list for applications
        // ===============================

        "resources" : [ { "host" : "localhost", "port_range" : [9001, 9003] } ],

        // ===============================
        // Set of properties for cmd line
        // ===============================

        "properties" : {
            "vtkpython" : "/.../VTK/build/bin/vtkpython",
            "pvpython" : "/.../ParaView/build/bin/pvpython",
            "vtk_python_path": "/.../VTK/build/Wrapping/Python/vtk/web",
            "pv_python_path": "/.../ParaView/build/lib/site-packages/paraview/web",
            "plugins_path": "/.../ParaView/build/lib",
            "dataDir": "/.../path/to/data/directory"
        },

        // ===============================
        // Application list with cmd lines
        // ===============================

        "apps" : {
            "cone" : {
                "cmd" : [
                    "${vtkpython}", "${vtk_python_path}/vtk_web_cone.py", "--port", "$port" ],
                "ready_line" : "Starting factory"
            },
            "graph" : {
                "cmd" : [
                    "${vtkpython}", "${vtk_python_path}/vtk_web_graph.py", "--port", "$port",
                    "--vertices", "${numberOfVertices}", "--edges", "${numberOfEdges}" ],
                "ready_line" : "Starting factory"
            },
            "phylotree" : {
                "cmd" : [
                    "${vtkpython}", "${vtk_python_path}/vtk_web_phylogenetic_tree.py", "--port", "$port",
                    "--tree", "${dataDir}/visomics/${treeFile}", "--table", "${dataDir}/visomics/${tableFile}" ],
                "ready_line" : "Starting factory"
            },
            "filebrowser" : {
                "cmd" : [
                    "${vtkpython}", "${vtk_python_path}/vtk_web_filebrowser.py",
                    "--port", "${port}", "--data-dir", "${dataDir}" ],
                "ready_line" : "Starting factory"
            },
            "data_prober": {
                "cmd": [
                    "${pvpython}", "-dr", "${pv_python_path}/pv_web_data_prober.py",
                    "--port", "${port}", "--data-dir", "${dataDir}", "-f" ],
                "ready_line" : "Starting factory"
            },
            "visualizer": {
                "cmd": [
                    "${pvpython}", "-dr", "${pv_python_path}/pv_web_visualizer.py",
                    "--plugins", "${plugins_path}/libPointSprite_Plugin.so", "--port", "${port}",
                    "--data-dir", "${dataDir}", "--load-file", "${dataDir}/${fileToLoad}",
                    "--authKey", "${secret}", "-f" ],  // Use of ${secret} means it needs to be provided to the client, in "fields", above.
                "ready_line" : "Starting factory"
            },
            "loader": {
                "cmd": [
                    "${pvpython}", "-dr", "${pv_python_path}/pv_web_file_loader.py",
                    "--port", "${port}", "--data-dir", "${dataDir}",
                    "--load-file", "${dataDir}/${fileToLoad}", "-f" ],
                "ready_line" : "Starting factory"
            },
            "launcher" : {
                "cmd": [
                    "/.../ParaView/Web/Applications/Parallel/server/launcher.sh",
                    "${port}", "${client}", "${resources}", "${file}" ],
                "ready_line" : "Starting factory"
            },
            "your_app": {
                "cmd": [
                    "your_shell_script.sh", "--resource-host", "${host}", "--resource-port", "${port}",
                    "--session-id", "${id}", "--generated-password", "${secret}",
                    "--application-key", "${application}" ],
                "ready_line": "Output line from your shell script indicating process is ready"
        }
    }
c                     t          j        dt           j        t           j        z            }d }|                    ||           S )a  
    Removes C-style comments from *json_like* and returns the result.  Example::
        >>> test_json = '''        {
            "foo": "bar", // This is a single-line comment
            "baz": "blah" /* Multi-line
            Comment */
        }'''
        >>> remove_comments('{"foo":"bar","baz":"blah",}')
        '{
    "foo":"bar",
    "baz":"blah"
}'

        From: https://gist.github.com/liftoff/ee7b81659673eca23cd9fc0d8b8e68b7
    z7//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"c                 L    |                      d          }|d         dk    rdS |S )Nr   / )group)matchss     I/DATA/AppData/hermes/venv/lib/python3.11/site-packages/wslink/launcher.pyreplacerz!remove_comments.<locals>.replacer   s(    KKNNQ43;;2    )recompileDOTALL	MULTILINEsub)	json_likecomments_rer   s      r   remove_commentsr      sI     *B
	BL  K
   ??8Y///r   c                  Z    d                     d t          d          D                       S )Nr
   c              3   b   K   | ]*}t          t          j        t          j        z             V  +d S N)r   stringascii_lettersdigits).0_s     r   	<genexpr>z#generatePassword.<locals>.<genexpr>   s4      SSA6&.>??SSSSSSr      )joinrange r   r   generatePasswordr&      s)    77SSrSSSSSSr   c                 L    d}|D ]}|| vrt          d| d| d           d}|S )NTzERROR: z is missing z key.F)print)objexpected_keysobject_nameall_key_foundkeys        r   validateKeySetr.      sM    M " "c>>?K??S???@@@!Mr   c                    |sd S |D ]}|| v r||         }| |         }|d         dk    r8||d         vr-t                               d|| |                    |d         | |<   Z|d         dk    rid|vrt          j        |d                   |d<   |d                             |          -t                               d|| |                    |d         | |<   d S )NtypeinListlistz key %s: sanitize %s with defaultdefaultregexpcompiled)loggerwarningr   r   r   )key_pairsanitizer-   	checkItemvalues        r   checkSanitizer<      s     9 9(?? ISME H,,	& 111NN:C#   %.i$8HSM6"h..Y..,.Jy7J,K,KIj)Z(..u55=NN:C#   %.i$8HSM%9 9r   c                     |D ];}t          ||           t          j        |           }|                    |          } <d| v rt                              d|            | S )N$z)Some properties could not be resolved: %s)r<   r   Templatesafe_substituter6   error)template_strvariable_listr9   r8   item_templates        r   replaceVariablesrE      sk    ! ? ?h)))55$44X>>
l@,OOOr   c                 \    g }| D ]&}|                     t          |||                     '|S r   )appendrE   )template_listrC   r9   result_listrB   s        r   replaceListrJ      sB    K% T T+L-RRSSSSr   c                 `    |                     g d           i }| D ]}||v r| |         ||<   |S )N)id
sessionURLsessionManagerURL)extend)r)   public_keysfiltered_outputfields       r   filterResponserS      sQ    @@@AAAO 0 0K%(ZOE"r   c                     | j                             d          }t          |          dk     rd S t          |d                   S )Nr	         )pathsplitlenstr)requestrW   s     r   extractSessionIdr\     s;    <c""D
4yy1}}ttAw<<r   c                 T    t          j        | d                              d          S )NF)ensure_asciiutf8)jsondumpsencode)payloads    r   jsonResponserd     s%    :gE22299&AAAr   c                   &    e Zd Zd Zd Zd Zd ZdS )SessionManagerc                     i | _         || _        t          |d                   | _        || _        |d         d         | _        d S )N	resourcesconfigurationr9   )sessionsconfigResourceManagerrh   mappingr9   )selfrk   rm   s      r   __init__zSessionManager.__init__  s@    ()<==/
;r   c                    t          t          j                              }| j                                        \  }}|r||d<   ||d<   ||d<   d|vrt                      |d<   t          | j        d         d         || j        d         g| j                  |d<   t          | j        d         |d	                  d
         || j        d         g| j                  |d
<   d| j        v rG| j        d         D ]9}t          | j        d         |         || j        d         g| j                  ||<   :|| j
        |<   | j                            | j
                   |S d S )NrL   hostportsecretri   rM   
propertiesappsapplicationcmdsessionData)rZ   uuiduuid1rh   getNextResourcer&   rE   rk   r9   rJ   rj   rm   update)rn   optionsrL   rq   rr   r-   s         r   createSessionzSessionManager.createSession  st    ^3355
d  	GDM"GFO"GFOw&&$4$6$6!$4O,\:$+l34% %GL!
 )F#GM$:;EB$+l34 GEN ++;}5  C#3M237 $+l";<$ $GCLL !(DM"L...Ntr   c                     | j         |         d         }| j         |         d         }| j                            ||           | j         |= | j                            | j                    d S )Nrq   rr   )rj   rh   freeResourcerm   r|   )rn   rL   rq   rr   s       r   deleteSessionzSessionManager.deleteSessionF  sd    }R (}R (##D$///M"DM*****r   c                 2    || j         v r| j         |         S d S r   rj   rn   rL   s     r   
getSessionzSessionManager.getSessionM  s!    =$$tr   N)__name__
__module____qualname__ro   r~   r   r   r%   r   r   rf   rf     sQ        < < <% % %N+ + +    r   rf   c                       e Zd Zd ZdS )ProxyMappingManagerc                     d S r   r%   r   s    r   r|   zProxyMappingManager.updateY  s    r   N)r   r   r   r|   r%   r   r   r   r   X  s#            r   r   c                       e Zd ZddZd ZdS )ProxyMappingManagerTXT	%s %s:%d
c                 "    || _         || _        d S r   )	file_pathpattern)rn   r   r   s      r   ro   zProxyMappingManagerTXT.__init__^  s    "r   c                      t           j                                      d                     fdD                       d           d S )Nr
   c              3   b   K   | ])}j         ||         d          |         d         fz  V  *dS )rq   rr   N)r   )r   rL   rn   rj   s     r   r!   z0ProxyMappingManagerTXT.update.<locals>.<genexpr>d  sW         HRL$8(2,v:NOO     r   utf-8encoding)r   r   
write_textr#   )rn   rj   s   ``r   r|   zProxyMappingManagerTXT.updateb  sv    T^''GG     "      	( 	
 	
 	
 	
 	
r   N)r   )r   r   r   ro   r|   r%   r   r   r   r   ]  s7           
 
 
 
 
r   r   c                   $    e Zd ZdZd Zd Zd ZdS )rl   zV
    Class that provides methods to keep track on available resources (host/port)
    c                    i | _         |D ]}|d         }t          t          |d         d         |d         d         dz                       }|| j         v r'| j         |         d                             |           r|g d| j         |<   d S )Nrq   
port_ranger      	available)r   used)rh   r2   r$   rO   )rn   resourceListresourcerq   portLists        r   ro   zResourceManager.__init__v  s    $ 	K 	KHF#Dh|,Q/,1G1JQ1NOO H t~%%t$[188BBBB5=r'J'Jt$$	K 	Kr   c                 P   d}d}| j         D ]H}|t          | j         |         d                   k     r"t          | j         |         d                   }|}I|rO| j         |         d                                         }| j         |         d                             |           ||fS dS )zX
        Return a (host, port) pair if any available otherwise will return None
        Nr   r   r   )NN)rh   rY   poprG   )rn   winneravailibilityCountrq   rr   s        r   r{   zResourceManager.getNextResource  s    
 N 	 	D 3t~d';K'H#I#III$'t(<[(I$J$J! 	">&)+6::<<DN6"6*11$777D>!|r   c                     || j         v rc|| j         |         d         v rP| j         |         d                             |           | j         |         d                             |           dS dS dS )z5
        Free a previously reserved resource
        r   r   N)rh   removerG   )rn   rq   rr   s      r   r   zResourceManager.freeResource  s{     4>!!ddnT.B6.J&J&JN4 (//555N4 -44T::::: "!&J&Jr   N)r   r   r   __doc__ro   r{   r   r%   r   r   rl   rl   q  sN         
K 
K 
K  &; ; ; ; ;r   rl   c                   @    e Zd Zd Zd Zd Zd Zd Zd Zd Z	dd	Z
d
S )ProcessManagerc                 H    || _         |d         d         | _        i | _        d S )Nri   log_dir)rk   r   	processes)rn   ri   s     r   ro   zProcessManager.__init__  s%    #$_5i@r   c                 X    | j         D ]!}| j         |                                          "d S r   )r   	terminater   s     r   __del__zProcessManager.__del__  s9    . 	+ 	+BN2((****	+ 	+r   c                 6    t          | j                  | dz  S )Nz.txt)r   r   r   s     r   _getLogFilePathzProcessManager._getLogFilePath  s    DL!!rKKK//r   c                    d }|                      |d                   }|                    ddd          5 }	 t          j        |d         ||          }|| j        |d         <   ns#  t
                              d           t
                              d	                    t          t          |d                                        Y d d d            d S xY w	 d d d            n# 1 swxY w Y   |S )
NrL   za+r   r   )mode	bufferingr   rw   )stdoutstderrzThe command line failed )
r   open
subprocessPopenr   r6   rA   r#   maprZ   )rn   sessionproclogFilePathlog_files        r   startProcesszProcessManager.startProcess  sH    **74=9941wGG 		8!'EN8H   15wt}--6777SXXc#wu~&>&>??@@@		 		 		 		 		 		 		 		
 .		 		 		 		 		 		 		 		 		 		 		 		 		 		 		 s/   C&-A&%C&&A"CC&C&&C*-C*c                     | j         |         }| j         |= t          j        t                    5  |                                 d d d            d S # 1 swxY w Y   d S r   )r   
contextlibsuppress	Exceptionr   )rn   rL   r   s      r   stopProcesszProcessManager.stopProcess  s    ~b!N2 ++ 	 	NN	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	s   AAAc                     g }| j         D ]6}| j         |                                         |                    |           7|S r   )r   pollrG   )rn   session_to_releaserL   s      r   listEndedProcesszProcessManager.listEndedProcess  sM    . 	. 	.B~b!&&((4"))"---!!r   c                 D    | j         |                                         d u S r   )r   r   r   s     r   	isRunningzProcessManager.isRunning  s     ~b!&&((D00r   r   c                    |d         }|                      |          s|dk     rdS |                      |          sdS | j        d         |d                  }|                    dd           }|sdS d}|                     |d                   }|                    d	          5 }|                                D ]
}	||	v rd} nd d d            n# 1 swxY w Y   |S )
NrL   <   FTru   rv   
ready_liner   r   )r   rk   getr   r   	readlines)
rn   r   countrL   rv   r   readyr   r   lines
             r   isReadyzProcessManager.isReady  sD   T] ~~b!! 	ebjj5 ~~b!! 	4k&)'-*@A __\488
  	5 **74=99w// 	8 **,,  %% EE &	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 s   # CCCN)r   )r   r   r   ro   r   r   r   r   r   r   r   r%   r   r   r   r     s          
+ + +0 0 0  $  " " "1 1 1     r   r   c                 "   	 t          t          | j        d                                       d                    }t	          j        |          }n#  d}|t          t          j                    d                   dz   t          t          j                    d                   z   z  }t          |           t          t                     t          j        d           Y nxY wg d}t          ||d	          s(t          t                     t          j        d           g d
}t          |d         |d          s(t          t                     t          j        d           d|d         vrd|d         d<   d|d         vri |d         d<   |S )Nr   r   r   z#ERROR: Unable to read config file.
r   
rV   )ri   ru   rt   rh   zConfig file)endpointrq   rr   
proxy_filerM   timeoutr   fieldsri   zfile.configurationcontentr
   r9   )r   r   rk   	read_textr`   loadsrZ   sysexc_infor(   sample_config_fileexitr.   )r}   config_commentsrk   messager*   s        r   parseConfigr     s   
)"##--w-??
 
 O,,83s|~~a())D03s|~~a7H3I3IIIg !!!HHHM&-??  !!!	 	 	M &1=BVWW  !!!///-/	*000.0
+Ms   AA BC"c                     |                      dt          dd           |                      dddd	           |                      d
dd           | S )Nrk   r   z#configuration file for the launcher)r0   nargshelpz-dz--debugz log debugging messages to stdout
store_true)r   actionz	--backendz&Server implementation to use (aiohttp)aiohttp)r   r3   )add_argumentrZ   )parsers    r   add_argumentsr   -  s    
s!*O     i@     BI     Mr   wslink Web Launcherc                     t          j        |t           j        t                    }t	          |           |                    |           }t          |          }t          j        |||j	                   d S )N)descriptionformatter_classepilogbackend)
argparseArgumentParserRawDescriptionHelpFormatterr   r   
parse_argsr   r   launcher_startr   )argvr   r   argsrk   s        r   startr   @  su    $ <!  F
 &T""DFD&$,??????r   r   c                 0    t          j        | ||          S )Nr   )r   r   )r   rk   r   s      r   startWebServerr   O  s    "4AAAAr   __main__)Nr   )r   ))r   r   r`   loggingr   r   r   r   ry   pathlibr   randomr   wslinkr   	getLoggerr   r6   	STATUS_OKSTATUS_BAD_REQUESTSTATUS_NOT_FOUNDSTATUS_SERVICE_UNAVAILABLEr   r   r&   r.   r<   rE   rJ   rS   r\   rd   rf   r   r   rl   r   r   r   r   r   r%   r   r   <module>r	     s          				      



                   		8	$	$	    | F0 0 08T T T  9 9 9:	 	 	      B B B9 9 9 9 9 9 9 9B       

 
 
 
 
0 
 
 
(*; *; *; *; *; *; *; *;dR R R R R R R Rt& & &`  &	@ 	@ 	@ 	@B B B B z	EGGGGG r   