eric6/Debugger/DebuggerInterfacePython.py

branch
multi_processing
changeset 7372
021f0252afac
parent 7360
9190402e4505
child 7373
d036d72f457c
equal deleted inserted replaced
7371:067f717c5a80 7372:021f0252afac
58 self.__variant = pythonVariant 58 self.__variant = pythonVariant
59 self.__startedVenv = "" 59 self.__startedVenv = ""
60 60
61 self.qsock = None 61 self.qsock = None
62 self.queue = [] 62 self.queue = []
63 self.__connections = {}
64 self.__pendingConnections = []
63 65
64 # set default values for capabilities of clients 66 # set default values for capabilities of clients
65 self.clientCapabilities = ClientDefaultCapabilities 67 self.clientCapabilities = ClientDefaultCapabilities
66 68
67 # set translation function 69 # set translation function
499 Public slot to handle a new connection. 501 Public slot to handle a new connection.
500 502
501 @param sock reference to the socket object (QTcpSocket) 503 @param sock reference to the socket object (QTcpSocket)
502 @return flag indicating success (boolean) 504 @return flag indicating success (boolean)
503 """ 505 """
504 # If we already have a connection, refuse this one. It will be closed
505 # automatically.
506 if self.qsock is not None:
507 return False
508
509 sock.disconnected.connect(self.debugServer.startClient) 506 sock.disconnected.connect(self.debugServer.startClient)
510 sock.readyRead.connect(self.__parseClientLine) 507 sock.readyRead.connect(lambda: self.__parseClientLine(sock))
511 508
512 self.qsock = sock 509 if self.qsock is None:
510 # first connection is the main one
511 self.qsock = sock
512 self.__pendingConnections.append(sock)
513 513
514 # Get the remote clients capabilities 514 # Get the remote clients capabilities
515 self.remoteCapabilities() 515 self.remoteCapabilities()
516 return True 516 return True
517 517
518 def __assignDebuggerId(self, sock, debuggerId):
519 """
520 Private method to set the debugger id for a recent debugger connection
521 attempt.
522
523 @param sock reference to the socket object
524 @type QTcpSocket
525 @param debuggerId id of the connected debug client
526 @type str
527 """
528 if sock in self.__pendingConnections:
529 self.__connections[debuggerId] = sock
530 self.__pendingConnections.remove(sock)
531
518 def flush(self): 532 def flush(self):
519 """ 533 """
520 Public slot to flush the queue. 534 Public slot to flush the queue.
521 """ 535 """
522 # Send commands that were waiting for the connection. 536 if self.qsock:
523 for cmd in self.queue: 537 # Send commands that were waiting for the connection.
524 self.__writeJsonCommandToSocket(cmd) 538 for cmd in self.queue:
539 self.__writeJsonCommandToSocket(cmd, self.qsock)
525 540
526 self.queue = [] 541 self.queue = []
527 542
528 def shutdown(self): 543 def shutdown(self):
529 """ 544 """
533 the debug client. (Needed on Win OS) 548 the debug client. (Needed on Win OS)
534 """ 549 """
535 if self.qsock is None: 550 if self.qsock is None:
536 return 551 return
537 552
538 # do not want any slots called during shutdown 553 for sock in (
539 self.qsock.disconnected.disconnect(self.debugServer.startClient) 554 list(self.__connections.values()) + self.__pendingConnections
540 self.qsock.readyRead.disconnect(self.__parseClientLine) 555 ):
541 556 # do not want any slots called during shutdown
542 # close down socket, and shut down client as well. 557 sock.disconnected.disconnect()
543 self.__sendJsonCommand("RequestShutdown", {}) 558 sock.readyRead.disconnect()
544 self.qsock.flush() 559
545 self.qsock.close() 560 # close down socket, and shut down client as well.
561 self.__sendJsonCommand("RequestShutdown", {}, sock=sock)
562 sock.flush()
563 sock.close()
546 564
547 # reinitialize 565 # reinitialize
548 self.qsock = None 566 self.qsock = None
549 self.queue = [] 567 self.queue = []
568
569 self.__pendingConnections = []
570 self.__connections = {}
550 571
551 def isConnected(self): 572 def isConnected(self):
552 """ 573 """
553 Public method to test, if a debug client has connected. 574 Public method to test, if a debug client has connected.
554 575
1043 else: 1064 else:
1044 self.__sendJsonCommand("ResponseForkTo", { 1065 self.__sendJsonCommand("ResponseForkTo", {
1045 "target": "child", 1066 "target": "child",
1046 }) 1067 })
1047 1068
1048 def __parseClientLine(self): 1069 def __parseClientLine(self, sock):
1049 """ 1070 """
1050 Private method to handle data from the client. 1071 Private method to handle data from the client.
1051 """ 1072
1052 while self.qsock and self.qsock.canReadLine(): 1073 @param sock reference to the socket to read data from
1053 qs = self.qsock.readLine() 1074 @type QTcpSocket
1075 """
1076 while sock and sock.canReadLine():
1077 qs = sock.readLine()
1054 if self.codec is not None: 1078 if self.codec is not None:
1055 line = self.codec.toUnicode(qs) 1079 line = self.codec.toUnicode(qs)
1056 else: 1080 else:
1057 line = bytes(qs).decode() 1081 line = bytes(qs).decode()
1058 1082
1059 logging.debug("<Debug-Server> %s", line) 1083 logging.debug("<Debug-Server> %s", line)
1060 ## print("Server: ", line) ##debug 1084 ## print("Server: ", line) ##debug
1061 1085
1062 self.__handleJsonCommand(line) 1086 self.__handleJsonCommand(line, sock)
1063 continue 1087 continue
1064 1088
1065 def __handleJsonCommand(self, jsonStr): 1089 def __handleJsonCommand(self, jsonStr, sock):
1066 """ 1090 """
1067 Private method to handle a command or response serialized as a 1091 Private method to handle a command or response serialized as a
1068 JSON string. 1092 JSON string.
1069 1093
1070 @param jsonStr string containing the command or response received 1094 @param jsonStr string containing the command or response received
1071 from the debug backend 1095 from the debug backend
1072 @type str 1096 @type str
1097 @param sock reference to the socket the data was received from
1098 @type QTcpSocket
1073 """ 1099 """
1074 import json 1100 import json
1075 1101
1076 try: 1102 try:
1077 commandDict = json.loads(jsonStr.strip()) 1103 commandDict = json.loads(jsonStr.strip())
1091 return 1117 return
1092 1118
1093 method = commandDict["method"] 1119 method = commandDict["method"]
1094 params = commandDict["params"] 1120 params = commandDict["params"]
1095 1121
1096 if method == "ClientOutput": 1122 if method == "DebuggerId":
1123 self.__assignDebuggerId(sock, params["id"])
1124
1125 elif method == "ClientOutput":
1097 self.debugServer.signalClientOutput(params["text"]) 1126 self.debugServer.signalClientOutput(params["text"])
1098 1127
1099 elif method in ["ResponseLine", "ResponseStack"]: 1128 elif method in ["ResponseLine", "ResponseStack"]:
1100 # Check if obsolet thread was clicked 1129 # Check if obsolet thread was clicked
1101 if params["stack"] == []: 1130 if params["stack"] == []:
1267 params["testname"], params["id"]) 1296 params["testname"], params["id"])
1268 1297
1269 elif method == "RequestForkTo": 1298 elif method == "RequestForkTo":
1270 self.__askForkTo() 1299 self.__askForkTo()
1271 1300
1272 def __sendJsonCommand(self, command, params): 1301 def __sendJsonCommand(self, command, params, debuggerId="", sock=None):
1273 """ 1302 """
1274 Private method to send a single command to the client. 1303 Private method to send a single command to the client.
1275 1304
1276 @param command command name to be sent 1305 @param command command name to be sent
1277 @type str 1306 @type str
1278 @param params dictionary of named parameters for the command 1307 @param params dictionary of named parameters for the command
1279 @type dict 1308 @type dict
1309 @param debuggerId id of the debug client to send the command to
1310 @type str
1311 @param sock reference to the socket object to be used (only used if
1312 debuggerId is not given)
1313 @type QTcpSocket
1280 """ 1314 """
1281 import json 1315 import json
1282 1316
1283 commandDict = { 1317 commandDict = {
1284 "jsonrpc": "2.0", 1318 "jsonrpc": "2.0",
1285 "method": command, 1319 "method": command,
1286 "params": params, 1320 "params": params,
1287 } 1321 }
1288 cmd = json.dumps(commandDict) + '\n' 1322 cmd = json.dumps(commandDict) + '\n'
1289 if self.qsock is not None: 1323
1290 self.__writeJsonCommandToSocket(cmd) 1324 if debuggerId and debuggerId in self.__connections:
1325 sock = self.__connections[debuggerId]
1326 elif sock is None and self.qsock is not None:
1327 sock = self.qsock
1328 if sock is not None:
1329 self.__writeJsonCommandToSocket(cmd, sock)
1291 else: 1330 else:
1292 self.queue.append(cmd) 1331 self.queue.append(cmd)
1293 1332
1294 def __writeJsonCommandToSocket(self, cmd): 1333 def __writeJsonCommandToSocket(self, cmd, sock):
1295 """ 1334 """
1296 Private method to write a JSON command to the socket. 1335 Private method to write a JSON command to the socket.
1297 1336
1298 @param cmd JSON command to be sent 1337 @param cmd JSON command to be sent
1299 @type str 1338 @type str
1339 @param sock reference to the socket to write to
1340 @type QTcpSocket
1300 """ 1341 """
1301 data = cmd.encode('utf8', 'backslashreplace') 1342 data = cmd.encode('utf8', 'backslashreplace')
1302 length = "{0:09d}".format(len(data)) 1343 length = "{0:09d}".format(len(data))
1303 self.qsock.write(length.encode() + data) 1344 sock.write(length.encode() + data)
1304 self.qsock.flush() 1345 sock.flush()
1305 1346
1306 1347
1307 def createDebuggerInterfacePython2(debugServer, passive): 1348 def createDebuggerInterfacePython2(debugServer, passive):
1308 """ 1349 """
1309 Module function to create a debugger interface instance. 1350 Module function to create a debugger interface instance.

eric ide

mercurial