src/eric7/Debugger/DebuggerInterfacePython.py

branch
eric7-maintenance
changeset 10616
4aa36fcd4a30
parent 10534
783d835d7fe4
parent 10552
c5b0c8a5fa7d
child 10659
43ead32943ca
equal deleted inserted replaced
10558:e3381757d40d 10616:4aa36fcd4a30
10 import contextlib 10 import contextlib
11 import json 11 import json
12 import logging 12 import logging
13 import os 13 import os
14 import shlex 14 import shlex
15 import struct
16 import zlib
15 17
16 from PyQt6.QtCore import QObject, QProcess, QProcessEnvironment, QTimer 18 from PyQt6.QtCore import QObject, QProcess, QProcessEnvironment, QTimer
17 19
18 from eric7 import Preferences, Utilities 20 from eric7 import Preferences, Utilities
19 from eric7.EricWidgets import EricMessageBox 21 from eric7.EricWidgets import EricMessageBox
51 self.debugServer = debugServer 53 self.debugServer = debugServer
52 self.passive = passive 54 self.passive = passive
53 self.process = None 55 self.process = None
54 self.__startedVenv = "" 56 self.__startedVenv = ""
55 57
56 self.queue = [] 58 self.__commandQueue = []
57 self.__mainDebugger = None 59 self.__mainDebugger = None
58 self.__connections = {} 60 self.__connections = {}
59 self.__pendingConnections = [] 61 self.__pendingConnections = []
60 self.__inShutdown = False 62 self.__inShutdown = False
61 63
206 str(configOverride["redirect"]) 208 str(configOverride["redirect"])
207 if configOverride and configOverride["enable"] 209 if configOverride and configOverride["enable"]
208 else str(Preferences.getDebugger("Python3Redirect")) 210 else str(Preferences.getDebugger("Python3Redirect"))
209 ) 211 )
210 noencoding = ( 212 noencoding = (
211 Preferences.getDebugger("Python3NoEncoding") and "--no-encoding" or "" 213 "--no-encoding" if Preferences.getDebugger("Python3NoEncoding") else ""
212 ) 214 )
213 multiprocessEnabled = ( 215 multiprocessEnabled = (
214 "--multiprocess" if Preferences.getDebugger("MultiProcessEnabled") else "" 216 "--multiprocess" if Preferences.getDebugger("MultiProcessEnabled") else ""
215 ) 217 )
216 callTraceOptimization = ( 218 callTraceOptimization = (
704 Private slot to flush the queue. 706 Private slot to flush the queue.
705 """ 707 """
706 if self.__mainDebugger: 708 if self.__mainDebugger:
707 # Send commands that were waiting for the connection. 709 # Send commands that were waiting for the connection.
708 conn = self.__connections[self.__mainDebugger] 710 conn = self.__connections[self.__mainDebugger]
709 for cmd in self.queue: 711 for jsonStr in self.__commandQueue:
710 self.__writeJsonCommandToSocket(cmd, conn) 712 self.__writeJsonCommandToSocket(jsonStr, conn)
711 713
712 self.queue = [] 714 self.__commandQueue.clear()
713 715
714 def shutdown(self): 716 def shutdown(self):
715 """ 717 """
716 Public method to cleanly shut down. 718 Public method to cleanly shut down.
717 719
730 while self.__pendingConnections: 732 while self.__pendingConnections:
731 sock = self.__pendingConnections.pop() 733 sock = self.__pendingConnections.pop()
732 self.__shutdownSocket(sock) 734 self.__shutdownSocket(sock)
733 735
734 # reinitialize 736 # reinitialize
735 self.queue = [] 737 self.__commandQueue.clear()
736 738
737 self.__mainDebugger = None 739 self.__mainDebugger = None
738 740
739 def __shutdownSocket(self, sock): 741 def __shutdownSocket(self, sock):
740 """ 742 """
1399 Private method to handle data from the client. 1401 Private method to handle data from the client.
1400 1402
1401 @param sock reference to the socket to read data from 1403 @param sock reference to the socket to read data from
1402 @type QTcpSocket 1404 @type QTcpSocket
1403 """ 1405 """
1404 while sock and sock.canReadLine(): 1406 while sock and sock.bytesAvailable():
1405 qs = sock.readLine() 1407 header = sock.read(struct.calcsize(b"!II"))
1406 line = bytes(qs).decode(encoding=Preferences.getSystem("StringEncoding")) 1408 length, datahash = struct.unpack(b"!II", header)
1407 1409
1408 logging.debug("<Debug-Server> %s", line) 1410 data = bytearray()
1409 ##print("Server: ", line) ## debug # __IGNORE_WARNING_M891__ 1411 while len(data) < length:
1410 1412 maxSize = length - len(data)
1411 self.__handleJsonCommand(line, sock) 1413 if sock.bytesAvailable() < maxSize:
1414 sock.waitForReadyRead(50)
1415 data += sock.read(maxSize)
1416
1417 if zlib.adler32(data) & 0xFFFFFFFF != datahash:
1418 # corrupted data -> discard and continue
1419 continue
1420
1421 jsonStr = data.decode("utf-8", "backslashreplace")
1422
1423 logging.debug("<Debug-Server> %s", jsonStr)
1424 ##print("Server: ", jsonStr) ## debug # __IGNORE_WARNING_M891__
1425
1426 self.__handleJsonCommand(jsonStr, sock)
1412 1427
1413 def __handleJsonCommand(self, jsonStr, sock): 1428 def __handleJsonCommand(self, jsonStr, sock):
1414 """ 1429 """
1415 Private method to handle a command or response serialized as a 1430 Private method to handle a command or response serialized as a
1416 JSON string. 1431 JSON string.
1644 commandDict = { 1659 commandDict = {
1645 "jsonrpc": "2.0", 1660 "jsonrpc": "2.0",
1646 "method": command, 1661 "method": command,
1647 "params": params, 1662 "params": params,
1648 } 1663 }
1649 cmd = json.dumps(commandDict) + "\n" 1664 jsonStr = json.dumps(commandDict)
1650 1665
1651 if debuggerId and debuggerId in self.__connections: 1666 if debuggerId and debuggerId in self.__connections:
1652 sock = self.__connections[debuggerId] 1667 sock = self.__connections[debuggerId]
1653 elif sock is None and self.__mainDebugger is not None: 1668 elif sock is None and self.__mainDebugger is not None:
1654 sock = self.__connections[self.__mainDebugger] 1669 sock = self.__connections[self.__mainDebugger]
1655 if sock is not None: 1670 if sock is not None:
1656 self.__writeJsonCommandToSocket(cmd, sock) 1671 self.__writeJsonCommandToSocket(jsonStr, sock)
1657 else: 1672 else:
1658 self.queue.append(cmd) 1673 self.__commandQueue.append(jsonStr)
1659 1674
1660 def __writeJsonCommandToSocket(self, cmd, sock): 1675 def __writeJsonCommandToSocket(self, jsonCommand, sock):
1661 """ 1676 """
1662 Private method to write a JSON command to the socket. 1677 Private method to write a JSON command to the socket.
1663 1678
1664 @param cmd JSON command to be sent 1679 @param jsonCommand JSON encoded command to be sent
1665 @type str 1680 @type str
1666 @param sock reference to the socket to write to 1681 @param sock reference to the socket to write to
1667 @type QTcpSocket 1682 @type QTcpSocket
1668 """ 1683 """
1669 data = cmd.encode("utf8", "backslashreplace") 1684 data = jsonCommand.encode("utf8", "backslashreplace")
1670 length = "{0:09d}".format(len(data)) 1685 header = struct.pack(b"!II", len(data), zlib.adler32(data) & 0xFFFFFFFF)
1671 sock.write(length.encode() + data) 1686 sock.write(header)
1687 sock.write(data)
1672 sock.flush() 1688 sock.flush()
1673 1689
1674 1690
1675 def createDebuggerInterfacePython3(debugServer, passive): 1691 def createDebuggerInterfacePython3(debugServer, passive):
1676 """ 1692 """

eric ide

mercurial