diff --git a/LaunchScript/VirtualAcousticsStarterServer.py b/LaunchScript/VirtualAcousticsStarterServer.py index 557686c353c53ddda5621e23c2e669a94c7f0f93..e5b5acb0b95458f5d74db0e1e76e7f9674890ea6 100644 --- a/LaunchScript/VirtualAcousticsStarterServer.py +++ b/LaunchScript/VirtualAcousticsStarterServer.py @@ -12,6 +12,7 @@ class ErrorCodes(Enum): ERROR_MISSING_VA_INI = 5 ERROR_INVALID_REPRODUCTION_ID = 6 ERROR_INCOMPLETE_VA_INI = 7 + ERROR_UNDEFINED_LAUNCHER_STATE = 8 # Class representing the VA-Launcher config (.json) file class LauncherConfig: @@ -51,6 +52,7 @@ class VAComposedIniParser: def link_renderer_ini(self): if not self.sRendererIniPath: + print("No renderer ini-file sent by client, using default one.") self.sRendererIniPath = "VARenderer.Default.ini" sMainInifile = self.get_main_inifile() @@ -103,6 +105,8 @@ class VirtualAcousticsLauncher: self.oLauncherServerSocket = None self.oLauncherConnection = None self.sCurrentScriptsDirectory = os.path.dirname( os.path.realpath( sys.argv[0] ) ) + self.sVAServerID = None + self.sVAServerDir = None self.start() @@ -111,7 +115,7 @@ class VirtualAcousticsLauncher: print( "VirtualAcoustics Starter script - press ctrl+c to quit" ) self.read_config() self.open_server_socket() - self.run() + self.main_loop() #Reads the launcher config and initializes all respective class parameters @@ -153,44 +157,67 @@ class VirtualAcousticsLauncher: sys.exit( ErrorCodes.ERROR_BINDING_SOCKET ) self.oLauncherServerSocket.settimeout( 1.0 ) - #Actually starts the launcher listening for VAServer start requests - def run(self): + def _reset_connection(self): + if self.oLauncherConnection: + self.oLauncherConnection.close() + self.oLauncherConnection = None + self.sVAServerDir = None + self.sVAServerID = None + + def _close_va_and_reset_connection(self): + if self.oVAProcess: + print( "Closing VA instance" ) + self.oVAProcess.terminate() + time.sleep( 1 ) + self.oVAProcess.kill() + self.oVAProcess = None + self._reset_connection() + + def main_loop(self): try: #TODO-PSC: Receive file and name from client self.vaIniParser.sRendererIniPath = None self.vaIniParser.prepare_inis() while True: - print( "Waiting for launcher connection..." ) - - self.oLauncherConnection = None - - while not self.oLauncherConnection: - try: - self.oLauncherConnection, sAddress = self.oLauncherServerSocket.accept() - except socket.timeout: - self.oLauncherConnection = None - except socket.error: - print( "Error while listening for launcher connection" ) - sys.exit( ErrorCodes.ERROR_CONNECTING_SOCKET ) - except (KeyboardInterrupt, SystemExit): - raise #re-raising the received exception + if not self.oLauncherConnection: + self.wait_for_connection() - print( "Connection received from " + sAddress[0] ) - - if self.oVAProcess: - print( "Closing current VA instance" ) - self.oVAProcess.kill() - self.oVAProcess = None - - sVAServerDir = self.receive_va_server_id() - if not sVAServerDir: - continue - - self.start_va_server(sVAServerDir) + elif self.sVAServerDir and not self.oVAProcess: + self.start_va_server() + + elif self.oVAProcess: + self.listen_for_requests() + + else: + print("ERROR: Undefined state launcher state leading to infinite loop") + sys.exit( ErrorCodes.ERROR_UNDEFINED_LAUNCHER_STATE ) + except KeyboardInterrupt: print( "Caught keyboard interrupt, quitting" ) - self.oLauncherServerSocket.close() + self._reset_connection() + + def wait_for_connection(self): + print( "Waiting for launcher connection..." ) + while not self.oLauncherConnection: + try: + self.oLauncherConnection, sAddress = self.oLauncherServerSocket.accept() + except socket.timeout: + self.oLauncherConnection = None + except socket.error: + print( "Error while listening for launcher connection" ) + sys.exit( ErrorCodes.ERROR_CONNECTING_SOCKET ) + except (KeyboardInterrupt, SystemExit): + raise #re-raising the received exception + + print( "Connection received from " + sAddress[0] ) + + if self.oVAProcess: + print( "Closing current VA instance" ) + self.oVAProcess.kill() + self.oVAProcess = None + + self.receive_va_server_id() #Checks for a message containing the ID of the VAServer instance to be started and returns the respective VAServer directory @@ -202,42 +229,42 @@ class VirtualAcousticsLauncher: print( "Received launch request for variant: " + self.sVAServerID ) except socket.error: print( "Error while reading variant" ) - self.oLauncherConnection.close() - return None + self._reset_connection() + return False else: try: - sVAServerDir = self.oConfig.dVirtualAcousticDirectories[self.sVAServerID] + self.sVAServerDir = self.oConfig.dVirtualAcousticDirectories[self.sVAServerID] except KeyError: - sVAServerDir = None + self.sVAServerDir = None - if not sVAServerDir: + if not self.sVAServerDir: print( 'Requested VA Instance "' + self.sVAServerID + '" not available' ) self.oLauncherConnection.send( b'f' ) #answer 'requested version not available - self.oLauncherConnection.close() - return None + self._reset_connection() + return False - return sVAServerDir + return True #Starts the VAServer from given directory - def start_va_server(self, sVAServerDir): + def start_va_server(self): # Check for VAServer.exe sVAExecutableFile = "bin/VAServer.exe" try: if not os.path.isfile( sVAExecutableFile ): - if sVAServerDir and os.path.isfile( sVAServerDir + "/" + sVAExecutableFile ): - sVAExecutableFile = sVAServerDir + "/" + sVAExecutableFile + if self.sVAServerDir and os.path.isfile( self.sVAServerDir + "/" + sVAExecutableFile ): + sVAExecutableFile = self.sVAServerDir + "/" + sVAExecutableFile else: print( "ERROR: Invalid config for " + self.sVAServerID + " -- file " + sVAExecutableFile + " does not exist" ) self.oLauncherConnection.send( b'n' ) #answer 'binary file cannot be found or invalid' return - elif sVAServerDir == None: - sVAServerDir = os.path.dirname( sVAExecutableFile ) #TODO-PSC: VAServer should always be started from its main directory, not the "bin" folder + elif self.sVAServerDir == None: + self.sVAServerDir = os.path.dirname( sVAExecutableFile ) #TODO-PSC: VAServer should always be started from its main directory, not the "bin" folder except KeyError: sVAExecutableFile = None print( "ERROR: config for " + self.sVAServerID + " has no valid \"file\" entry" ) self.oLauncherConnection.send( b'i' ) #answer 'invalid file entry in the config' - self.oLauncherConnection.close() + self._reset_connection() return if not sVAExecutableFile: @@ -252,7 +279,7 @@ class VirtualAcousticsLauncher: # start instance print( 'executing "' + sCommand + '"' ) - self.oVAProcess = subprocess.Popen( sCommand, cwd = sVAServerDir, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP ) + self.oVAProcess = subprocess.Popen( sCommand, cwd = self.sVAServerDir, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP ) # wait for requested duration before sending the go signal time.sleep( self.oConfig.nDefaultSleep ) @@ -260,22 +287,12 @@ class VirtualAcousticsLauncher: if self.oVAProcess.poll() != None: print( "VA Process died - sending abort token" ) self.oLauncherConnection.send( b'a' ) #answer 'VAServer was aborted - self.oLauncherConnection.close() + self._reset_connection() return else: print( "sending go token" ) self.oLauncherConnection.send( b'g' )#answer 'go, VAServer is correctly started' - self.listen_for_requests() - - #if the above terminates a quit request was received: - # kill VA instance - print( "Closing VA instance" ) - self.oVAProcess.terminate() - time.sleep( 1 ) - self.oVAProcess.kill() - self.oVAProcess = None - #Listens for requests while the VAServer is running def listen_for_requests(self): while True: @@ -289,6 +306,7 @@ class VirtualAcousticsLauncher: self.receive_file(sMessage) else: #NOT sMessage.startswith("file") print( "Received quit event: "+sMessage ) + self._close_va_and_reset_connection() break except socket.timeout: @@ -299,7 +317,8 @@ class VirtualAcousticsLauncher: break except (KeyboardInterrupt, SystemExit): raise #re-raise for higher instance to catch - + + def receive_file(self, sMessage): aMessageParts = sMessage.split(":") iBytesToReceive = int(aMessageParts[2]) @@ -349,9 +368,8 @@ class VirtualAcousticsLauncher: print("File receive failed") + #create an instance of the class oLauncher = VirtualAcousticsLauncher() - -