219 @param clientArgs list of arguments for the client |
219 @param clientArgs list of arguments for the client |
220 @param idString id of the client to be started |
220 @param idString id of the client to be started |
221 @type str |
221 @type str |
222 @param environment dictionary of environment settings to pass |
222 @param environment dictionary of environment settings to pass |
223 @type dict |
223 @type dict |
224 @return flag indicating a successful client start |
224 @return flag indicating a successful client start and the exit code |
225 @rtype bool |
225 in case of an issue |
|
226 @rtype bool, int |
226 """ |
227 """ |
227 if interpreter == "" or not Utilities.isinpath(interpreter): |
228 if interpreter == "" or not Utilities.isinpath(interpreter): |
228 return False |
229 return False |
|
230 |
|
231 exitCode = None |
229 |
232 |
230 proc = QProcess() |
233 proc = QProcess() |
231 proc.setProcessChannelMode(QProcess.ForwardedChannels) |
234 proc.setProcessChannelMode(QProcess.ForwardedChannels) |
232 if environment is not None: |
235 if environment is not None: |
233 env = QProcessEnvironment() |
236 env = QProcessEnvironment() |
246 self.__clientProcesses[idString] = proc |
249 self.__clientProcesses[idString] = proc |
247 if proc: |
250 if proc: |
248 timer = QTimer() |
251 timer = QTimer() |
249 timer.setSingleShot(True) |
252 timer.setSingleShot(True) |
250 timer.start(30000) # 30s timeout |
253 timer.start(30000) # 30s timeout |
251 while (idString not in self.connectionNames() |
254 while ( |
252 and timer.isActive() |
255 idString not in self.connectionNames() and |
|
256 timer.isActive() |
253 ): |
257 ): |
254 # Give the event loop the chance to process the new |
258 # Give the event loop the chance to process the new |
255 # connection of the client (= slow start). |
259 # connection of the client (= slow start). |
256 QCoreApplication.processEvents( |
260 QCoreApplication.processEvents( |
257 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents) |
261 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents) |
258 else: |
262 |
|
263 # check if client exited prematurely |
|
264 if proc.state() == QProcess.ProcessState.NotRunning: |
|
265 exitCode = proc.exitCode() |
|
266 proc = None |
|
267 self.__clientProcesses[idString] = None |
|
268 break |
|
269 else: |
|
270 if proc: |
|
271 timer = QTimer() |
|
272 timer.setSingleShot(True) |
|
273 timer.start(1000) # 1s timeout |
|
274 while timer.isActive(): |
|
275 # check if client exited prematurely |
|
276 QCoreApplication.processEvents( |
|
277 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents) |
|
278 if proc.state() == QProcess.ProcessState.NotRunning: |
|
279 exitCode = proc.exitCode() |
|
280 proc = None |
|
281 break |
259 self.__clientProcess = proc |
282 self.__clientProcess = proc |
260 |
283 |
261 return proc is not None |
284 return proc is not None, exitCode |
262 |
285 |
263 def stopClient(self, idString=""): |
286 def stopClient(self, idString=""): |
264 """ |
287 """ |
265 Public method to stop a client process. |
288 Public method to stop a client process. |
266 |
289 |
279 if connection is not None: |
302 if connection is not None: |
280 connection.waitForDisconnected() |
303 connection.waitForDisconnected() |
281 |
304 |
282 if idString: |
305 if idString: |
283 with contextlib.suppress(KeyError): |
306 with contextlib.suppress(KeyError): |
284 self .__clientProcesses[idString].close() |
307 if self .__clientProcesses[idString] is not None: |
|
308 self .__clientProcesses[idString].close() |
285 del self.__clientProcesses[idString] |
309 del self.__clientProcesses[idString] |
286 else: |
310 else: |
287 if self.__clientProcess is not None: |
311 if self.__clientProcess is not None: |
288 self.__clientProcess.close() |
312 self.__clientProcess.close() |
289 self.__clientProcess = None |
313 self.__clientProcess = None |