Sun, 08 May 2022 19:58:27 +0200
Added classes to realize a JSON based stream between two processes.
--- a/eric7.epj Sun May 08 15:44:29 2022 +0200 +++ b/eric7.epj Sun May 08 19:58:27 2022 +0200 @@ -1094,6 +1094,8 @@ "eric7/EricNetwork/EricGoogleMailHelpers.py", "eric7/EricNetwork/EricJsonClient.py", "eric7/EricNetwork/EricJsonServer.py", + "eric7/EricNetwork/EricJsonStreamReader.py", + "eric7/EricNetwork/EricJsonStreamWriter.py", "eric7/EricNetwork/EricNetworkIcon.py", "eric7/EricNetwork/EricNetworkProxyFactory.py", "eric7/EricNetwork/EricSslCertificateSelectionDialog.py",
--- a/eric7/EricNetwork/EricJsonClient.py Sun May 08 15:44:29 2022 +0200 +++ b/eric7/EricNetwork/EricJsonClient.py Sun May 08 19:58:27 2022 +0200 @@ -24,7 +24,7 @@ """ Constructor - @param host ip address the background service is listening + @param host IP address the background service is listening @type str @param port port of the background service @type int
--- a/eric7/EricNetwork/EricJsonServer.py Sun May 08 15:44:29 2022 +0200 +++ b/eric7/EricNetwork/EricJsonServer.py Sun May 08 19:58:27 2022 +0200 @@ -60,10 +60,9 @@ self.newConnection.connect(self.handleNewConnection) - port = self.serverPort() ## Note: Need the port if client is started external in debugger. print('JSON server ({1}) listening on: {0:d}' # __IGNORE_WARNING__ - .format(port, self.__name)) + .format(self.serverPort(), self.__name)) @pyqtSlot() def handleNewConnection(self): @@ -131,7 +130,7 @@ """ Private slot handling received data from the client. - @param idString id of the connection been disconnected + @param idString id of the connection @type str """ if idString:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/EricNetwork/EricJsonStreamReader.py Sun May 08 19:58:27 2022 +0200 @@ -0,0 +1,142 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a JSON based reader class. +""" + +import json + +from PyQt6.QtCore import pyqtSignal, pyqtSlot +from PyQt6.QtNetwork import QTcpServer, QHostAddress + +from EricWidgets import EricMessageBox + +import Preferences +import Utilities + + +class EricJsonReader(QTcpServer): + """ + Class implementing a JSON based reader class. + + The reader is responsible for opening a socket to listen for writer + connections. + + @signal dataReceived(object) emitted after a data object was received + """ + dataReceived = pyqtSignal(object) + + def __init__(self, name="", ip=None, parent=None): + """ + Constructor + + @param name name of the server (used for output only) + @type str + @param ip IP address to listen at + @type str + @param parent parent object + @type QObject + """ + super().__init__(parent) + + self.__name = name + self.__connection = None + + # setup the network interface + if ip is None: + networkInterface = Preferences.getDebugger("NetworkInterface") + if networkInterface == "all" or '.' in networkInterface: + # IPv4 + self.__hostAddress = '127.0.0.1' + else: + # IPv6 + self.__hostAddress = '::1' + else: + self.__hostAddress = ip + self.listen(QHostAddress(self.__hostAddress)) + + self.newConnection.connect(self.handleNewConnection) + + ## Note: Need the port if writer is started external in debugger. + print('JSON reader ({1}) listening on: {0:d}' # __IGNORE_WARNING__ + .format(self.serverPort(), self.__name)) + + def address(self): + """ + Public method to get the host address. + + @return host address + @rtype str + """ + return self.__hostAddress + + def port(self): + """ + Public method to get the port number to connect to. + + @return port number + @rtype int + """ + return self.serverPort() + + @pyqtSlot() + def handleNewConnection(self): + """ + Public slot for new incoming connections from a writer. + """ + connection = self.nextPendingConnection() + if not connection.isValid(): + return + + if self.__connection is not None: + self.__connection.close() + + self.__connection = connection + + connection.readyRead.connect(self.__receiveJson) + connection.disconnected.connect(self.__handleDisconnect) + + @pyqtSlot() + def __handleDisconnect(self): + """ + Private slot handling a disconnect of the writer. + """ + if self.__connection is not None: + self.__connection.close() + + self.__connection = None + + @pyqtSlot() + def __receiveJson(self): + """ + Private slot handling received data from the writer. + """ + connection = self.__connection + + while connection and connection.canReadLine(): + dataStr = connection.readLine() + jsonLine = bytes(dataStr).decode("utf-8", 'backslashreplace') + + #- print("JSON Reader ({0}): {1}".format(self.__name, jsonLine)) + #- this is for debugging only + + try: + data = json.loads(jsonLine.strip()) + except (TypeError, ValueError) as err: + EricMessageBox.critical( + None, + self.tr("JSON Protocol Error"), + self.tr("""<p>The data received from the writer""" + """ could not be decoded. Please report""" + """ this issue with the received data to the""" + """ eric bugs email address.</p>""" + """<p>Error: {0}</p>""" + """<p>Data:<br/>{1}</p>""").format( + str(err), Utilities.html_encode(jsonLine.strip())), + EricMessageBox.Ok) + return + + self.dataReceived.emit(data)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eric7/EricNetwork/EricJsonStreamWriter.py Sun May 08 19:58:27 2022 +0200 @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2022 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a JSON based writer class. +""" + +import json +import socket + + +class EricJsonWriter: + """ + Class implementing a JSON based writer class. + """ + def __init__(self, host, port): + """ + Constructor + + @param host IP address the reader is listening on + @type str + @param port port the reader is listening on + @type int + """ + self.__connection = socket.create_connection((host, port)) + + def write(self, data): + """ + Public method to send JSON serializable data. + + @param data JSON serializable object to be sent + @type object + """ + dataStr = json.dumps(data) + '\n' + self.__connection.sendall(dataStr.encode('utf8', 'backslashreplace')) + + def close(self): + """ + Public method to close the stream. + """ + self.__connection.close()