Added classes to realize a JSON based stream between two processes. unittest

Sun, 08 May 2022 19:58:27 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sun, 08 May 2022 19:58:27 +0200
branch
unittest
changeset 9057
ddc46e93ccc4
parent 9056
af7c8c7b7c62
child 9059
e7fd342f8bfc

Added classes to realize a JSON based stream between two processes.

eric7.epj file | annotate | diff | comparison | revisions
eric7/EricNetwork/EricJsonClient.py file | annotate | diff | comparison | revisions
eric7/EricNetwork/EricJsonServer.py file | annotate | diff | comparison | revisions
eric7/EricNetwork/EricJsonStreamReader.py file | annotate | diff | comparison | revisions
eric7/EricNetwork/EricJsonStreamWriter.py file | annotate | diff | comparison | revisions
--- 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()

eric ide

mercurial