Fri, 02 May 2025 16:19:35 +0200
Added code to suppress some output needed during development when the application is operated in release mode.
8300 | 1 | # -*- coding: utf-8 -*- |
2 | ||
11090
f5f5f5803935
Updated copyright for 2025.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10928
diff
changeset
|
3 | # Copyright (c) 2017 - 2025 Detlev Offenbach <detlev@die-offenbachs.de> |
8300 | 4 | # |
5 | ||
6 | """ | |
7 | Module implementing the JSON based server base class. | |
8 | """ | |
9 | ||
10 | import contextlib | |
11 | import json | |
10928
46651e194fbe
Refactored some packages, modules and code to allow extracting the 'EricXxx' packages into a library project.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10697
diff
changeset
|
12 | import shutil |
10524
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
13 | import struct |
10697
8a609e4c71b6
Made the various JSON based client-server interface a bit more resilient against slow data transfer.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10524
diff
changeset
|
14 | import time |
10524
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
15 | import zlib |
8300 | 16 | |
8318
962bce857696
Replaced all imports of PyQt5 to PyQt6 and started to replace code using obsoleted methods and adapt to the PyQt6 enum usage.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8312
diff
changeset
|
17 | from PyQt6.QtCore import ( |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
18 | QCoreApplication, |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
19 | QEventLoop, |
9473
3f23dbf37dbe
Resorted the import statements using isort.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9413
diff
changeset
|
20 | QProcess, |
3f23dbf37dbe
Resorted the import statements using isort.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9413
diff
changeset
|
21 | QProcessEnvironment, |
3f23dbf37dbe
Resorted the import statements using isort.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9413
diff
changeset
|
22 | QThread, |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
23 | QTimer, |
9473
3f23dbf37dbe
Resorted the import statements using isort.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9413
diff
changeset
|
24 | pyqtSlot, |
8300 | 25 | ) |
9473
3f23dbf37dbe
Resorted the import statements using isort.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9413
diff
changeset
|
26 | from PyQt6.QtNetwork import QHostAddress, QTcpServer |
8300 | 27 | |
10928
46651e194fbe
Refactored some packages, modules and code to allow extracting the 'EricXxx' packages into a library project.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10697
diff
changeset
|
28 | from eric7 import EricUtilities |
9473
3f23dbf37dbe
Resorted the import statements using isort.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9413
diff
changeset
|
29 | from eric7.EricWidgets import EricMessageBox |
8300 | 30 | |
31 | ||
8354
12ebd3934fef
Renamed 'E5Utilities' to 'EricUtilities' and 'E5Network' to 'EricNetwork'.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8322
diff
changeset
|
32 | class EricJsonServer(QTcpServer): |
8300 | 33 | """ |
34 | Class implementing a JSON based server base class. | |
35 | """ | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
36 | |
11255
1c2bd52f2002
Added code to suppress some output needed during development when the application is operated in release mode.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
11148
diff
changeset
|
37 | def __init__( |
1c2bd52f2002
Added code to suppress some output needed during development when the application is operated in release mode.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
11148
diff
changeset
|
38 | self, |
1c2bd52f2002
Added code to suppress some output needed during development when the application is operated in release mode.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
11148
diff
changeset
|
39 | name="", |
1c2bd52f2002
Added code to suppress some output needed during development when the application is operated in release mode.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
11148
diff
changeset
|
40 | interface="127.0.0.1", |
1c2bd52f2002
Added code to suppress some output needed during development when the application is operated in release mode.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
11148
diff
changeset
|
41 | multiplex=False, |
1c2bd52f2002
Added code to suppress some output needed during development when the application is operated in release mode.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
11148
diff
changeset
|
42 | parent=None, |
1c2bd52f2002
Added code to suppress some output needed during development when the application is operated in release mode.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
11148
diff
changeset
|
43 | releaseMode=False, |
1c2bd52f2002
Added code to suppress some output needed during development when the application is operated in release mode.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
11148
diff
changeset
|
44 | ): |
8300 | 45 | """ |
46 | Constructor | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
47 | |
10928
46651e194fbe
Refactored some packages, modules and code to allow extracting the 'EricXxx' packages into a library project.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10697
diff
changeset
|
48 | @param name name of the server (used for output only) (defaults to "") |
46651e194fbe
Refactored some packages, modules and code to allow extracting the 'EricXxx' packages into a library project.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10697
diff
changeset
|
49 | @type str (optional) |
46651e194fbe
Refactored some packages, modules and code to allow extracting the 'EricXxx' packages into a library project.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10697
diff
changeset
|
50 | @param interface network interface to be used (IP address or one of "all", |
46651e194fbe
Refactored some packages, modules and code to allow extracting the 'EricXxx' packages into a library project.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10697
diff
changeset
|
51 | "allv4", "allv6", "localv4" or "localv6") (defaults to "127.0.0.1") |
46651e194fbe
Refactored some packages, modules and code to allow extracting the 'EricXxx' packages into a library project.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10697
diff
changeset
|
52 | @type str (optional) |
46651e194fbe
Refactored some packages, modules and code to allow extracting the 'EricXxx' packages into a library project.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10697
diff
changeset
|
53 | @param multiplex flag indicating a multiplexing server (defaults to False) |
46651e194fbe
Refactored some packages, modules and code to allow extracting the 'EricXxx' packages into a library project.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10697
diff
changeset
|
54 | @type bool (optional) |
46651e194fbe
Refactored some packages, modules and code to allow extracting the 'EricXxx' packages into a library project.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10697
diff
changeset
|
55 | @param parent reference to the parent object (defaults to None) |
46651e194fbe
Refactored some packages, modules and code to allow extracting the 'EricXxx' packages into a library project.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10697
diff
changeset
|
56 | @type QObject (optional) |
11255
1c2bd52f2002
Added code to suppress some output needed during development when the application is operated in release mode.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
11148
diff
changeset
|
57 | @param releaseMode flag indicating the mode of operations (defaults to False) |
1c2bd52f2002
Added code to suppress some output needed during development when the application is operated in release mode.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
11148
diff
changeset
|
58 | @type bool (optional) |
8300 | 59 | """ |
60 | super().__init__(parent) | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
61 | |
8300 | 62 | self.__name = name |
63 | self.__multiplex = multiplex | |
64 | if self.__multiplex: | |
65 | self.__clientProcesses = {} | |
66 | self.__connections = {} | |
67 | else: | |
68 | self.__clientProcess = None | |
69 | self.__connection = None | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
70 | |
8300 | 71 | # setup the network interface |
10928
46651e194fbe
Refactored some packages, modules and code to allow extracting the 'EricXxx' packages into a library project.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10697
diff
changeset
|
72 | if interface in ("allv4", "localv4") or "." in interface: |
8300 | 73 | # IPv4 |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
74 | self.__hostAddress = "127.0.0.1" |
10928
46651e194fbe
Refactored some packages, modules and code to allow extracting the 'EricXxx' packages into a library project.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10697
diff
changeset
|
75 | elif interface in ("all", "allv6", "localv6"): |
8300 | 76 | # IPv6 |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
77 | self.__hostAddress = "::1" |
9521 | 78 | else: |
10928
46651e194fbe
Refactored some packages, modules and code to allow extracting the 'EricXxx' packages into a library project.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10697
diff
changeset
|
79 | self.__hostAddress = interface |
8300 | 80 | self.listen(QHostAddress(self.__hostAddress)) |
81 | ||
82 | self.newConnection.connect(self.handleNewConnection) | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
83 | |
11255
1c2bd52f2002
Added code to suppress some output needed during development when the application is operated in release mode.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
11148
diff
changeset
|
84 | if not releaseMode: |
1c2bd52f2002
Added code to suppress some output needed during development when the application is operated in release mode.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
11148
diff
changeset
|
85 | ## Note: Need the address and port if client is started external in |
1c2bd52f2002
Added code to suppress some output needed during development when the application is operated in release mode.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
11148
diff
changeset
|
86 | ## debugger. |
1c2bd52f2002
Added code to suppress some output needed during development when the application is operated in release mode.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
11148
diff
changeset
|
87 | hostAddressStr = ( |
1c2bd52f2002
Added code to suppress some output needed during development when the application is operated in release mode.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
11148
diff
changeset
|
88 | "[{0}]".format(self.__hostAddress) |
1c2bd52f2002
Added code to suppress some output needed during development when the application is operated in release mode.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
11148
diff
changeset
|
89 | if ":" in self.__hostAddress |
1c2bd52f2002
Added code to suppress some output needed during development when the application is operated in release mode.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
11148
diff
changeset
|
90 | else self.__hostAddress |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
91 | ) |
11255
1c2bd52f2002
Added code to suppress some output needed during development when the application is operated in release mode.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
11148
diff
changeset
|
92 | print( # __IGNORE_WARNING_M-801__ |
1c2bd52f2002
Added code to suppress some output needed during development when the application is operated in release mode.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
11148
diff
changeset
|
93 | f"JSON server ({self.__name}) listening on:" |
1c2bd52f2002
Added code to suppress some output needed during development when the application is operated in release mode.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
11148
diff
changeset
|
94 | f" {hostAddressStr}:{self.serverPort():d}" |
1c2bd52f2002
Added code to suppress some output needed during development when the application is operated in release mode.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
11148
diff
changeset
|
95 | ) |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
96 | |
8300 | 97 | @pyqtSlot() |
98 | def handleNewConnection(self): | |
99 | """ | |
100 | Public slot for new incoming connections from a client. | |
101 | """ | |
102 | connection = self.nextPendingConnection() | |
103 | if not connection.isValid(): | |
104 | return | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
105 | |
8300 | 106 | if self.__multiplex: |
107 | if not connection.waitForReadyRead(3000): | |
108 | return | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
109 | idString = ( |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
110 | bytes(connection.readLine()).decode("utf-8", "backslashreplace").strip() |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
111 | ) |
8300 | 112 | if idString in self.__connections: |
113 | self.__connections[idString].close() | |
114 | self.__connections[idString] = connection | |
115 | else: | |
116 | idString = "" | |
117 | if self.__connection is not None: | |
118 | self.__connection.close() | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
119 | |
8300 | 120 | self.__connection = connection |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
121 | |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
122 | connection.readyRead.connect(lambda: self.__receiveJson(idString)) |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
123 | connection.disconnected.connect(lambda: self.__handleDisconnect(idString)) |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
124 | |
8300 | 125 | @pyqtSlot() |
126 | def __handleDisconnect(self, idString): | |
127 | """ | |
128 | Private slot handling a disconnect of the client. | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
129 | |
8300 | 130 | @param idString id of the connection been disconnected |
131 | @type str | |
132 | """ | |
133 | if idString: | |
134 | if idString in self.__connections: | |
135 | self.__connections[idString].close() | |
136 | del self.__connections[idString] | |
137 | else: | |
138 | if self.__connection is not None: | |
139 | self.__connection.close() | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
140 | |
8300 | 141 | self.__connection = None |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
142 | |
8300 | 143 | def connectionNames(self): |
144 | """ | |
145 | Public method to get the list of active connection names. | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
146 | |
8300 | 147 | If this is not a multiplexing server, an empty list is returned. |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
148 | |
8300 | 149 | @return list of active connection names |
150 | @rtype list of str | |
151 | """ | |
152 | if self.__multiplex: | |
10373
093dcebe5ecb
Corrected some uses of dict.keys(), dict.values() and dict.items().
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10205
diff
changeset
|
153 | return list(self.__connections) |
8300 | 154 | else: |
155 | return [] | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
156 | |
8300 | 157 | @pyqtSlot() |
158 | def __receiveJson(self, idString): | |
159 | """ | |
160 | Private slot handling received data from the client. | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
161 | |
9057
ddc46e93ccc4
Added classes to realize a JSON based stream between two processes.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8943
diff
changeset
|
162 | @param idString id of the connection |
8300 | 163 | @type str |
164 | """ | |
10697
8a609e4c71b6
Made the various JSON based client-server interface a bit more resilient against slow data transfer.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10524
diff
changeset
|
165 | headerSize = struct.calcsize(b"!II") |
8a609e4c71b6
Made the various JSON based client-server interface a bit more resilient against slow data transfer.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10524
diff
changeset
|
166 | |
8300 | 167 | if idString: |
168 | try: | |
169 | connection = self.__connections[idString] | |
170 | except KeyError: | |
171 | connection = None | |
172 | else: | |
173 | connection = self.__connection | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
174 | |
10524
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
175 | while connection and connection.bytesAvailable(): |
10697
8a609e4c71b6
Made the various JSON based client-server interface a bit more resilient against slow data transfer.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10524
diff
changeset
|
176 | now = time.monotonic() |
8a609e4c71b6
Made the various JSON based client-server interface a bit more resilient against slow data transfer.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10524
diff
changeset
|
177 | while connection.bytesAvailable() < headerSize: |
8a609e4c71b6
Made the various JSON based client-server interface a bit more resilient against slow data transfer.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10524
diff
changeset
|
178 | connection.waitForReadyRead(50) |
8a609e4c71b6
Made the various JSON based client-server interface a bit more resilient against slow data transfer.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10524
diff
changeset
|
179 | if time.monotonic() - now > 2.0: # 2 seconds timeout |
8a609e4c71b6
Made the various JSON based client-server interface a bit more resilient against slow data transfer.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10524
diff
changeset
|
180 | return |
8a609e4c71b6
Made the various JSON based client-server interface a bit more resilient against slow data transfer.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10524
diff
changeset
|
181 | header = connection.read(headerSize) |
10524
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
182 | length, datahash = struct.unpack(b"!II", header) |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
183 | |
10524
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
184 | data = bytearray() |
10697
8a609e4c71b6
Made the various JSON based client-server interface a bit more resilient against slow data transfer.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10524
diff
changeset
|
185 | now = time.monotonic() |
10524
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
186 | while len(data) < length: |
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
187 | maxSize = length - len(data) |
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
188 | if connection.bytesAvailable() < maxSize: |
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
189 | connection.waitForReadyRead(50) |
10697
8a609e4c71b6
Made the various JSON based client-server interface a bit more resilient against slow data transfer.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10524
diff
changeset
|
190 | newData = connection.read(maxSize) |
8a609e4c71b6
Made the various JSON based client-server interface a bit more resilient against slow data transfer.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10524
diff
changeset
|
191 | if newData: |
8a609e4c71b6
Made the various JSON based client-server interface a bit more resilient against slow data transfer.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10524
diff
changeset
|
192 | data += newData |
8a609e4c71b6
Made the various JSON based client-server interface a bit more resilient against slow data transfer.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10524
diff
changeset
|
193 | else: |
8a609e4c71b6
Made the various JSON based client-server interface a bit more resilient against slow data transfer.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10524
diff
changeset
|
194 | if time.monotonic() - now > 2.0: # 2 seconds timeout |
8a609e4c71b6
Made the various JSON based client-server interface a bit more resilient against slow data transfer.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10524
diff
changeset
|
195 | break |
10524
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
196 | |
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
197 | if zlib.adler32(data) & 0xFFFFFFFF != datahash: |
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
198 | # corrupted data -> discard and continue |
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
199 | continue |
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
200 | |
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
201 | jsonString = data.decode("utf-8", "backslashreplace") |
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
202 | |
11255
1c2bd52f2002
Added code to suppress some output needed during development when the application is operated in release mode.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
11148
diff
changeset
|
203 | # - print(f"JSON Server ({self.__name}): {jsonString}") |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
204 | # - this is for debugging only |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
205 | |
8300 | 206 | try: |
10524
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
207 | clientDict = json.loads(jsonString.strip()) |
8300 | 208 | except (TypeError, ValueError) as err: |
8356
68ec9c3d4de5
Renamed the modules and classes of the E5Gui package to have the prefix 'Eric' instead of 'E5'.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8354
diff
changeset
|
209 | EricMessageBox.critical( |
8300 | 210 | None, |
211 | self.tr("JSON Protocol Error"), | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
212 | self.tr( |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
213 | """<p>The response received from the client""" |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
214 | """ could not be decoded. Please report""" |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
215 | """ this issue with the received data to the""" |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
216 | """ eric bugs email address.</p>""" |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
217 | """<p>Error: {0}</p>""" |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
218 | """<p>Data:<br/>{1}</p>""" |
10928
46651e194fbe
Refactored some packages, modules and code to allow extracting the 'EricXxx' packages into a library project.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10697
diff
changeset
|
219 | ).format(str(err), EricUtilities.html_encode(jsonString.strip())), |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
220 | EricMessageBox.Ok, |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
221 | ) |
8300 | 222 | return |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
223 | |
8300 | 224 | self.handleCall(clientDict["method"], clientDict["params"]) |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
225 | |
8300 | 226 | def sendJson(self, command, params, flush=False, idString=""): |
227 | """ | |
228 | Public method to send a single command to a client. | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
229 | |
8300 | 230 | @param command command name to be sent |
231 | @type str | |
232 | @param params dictionary of named parameters for the command | |
233 | @type dict | |
234 | @param flush flag indicating to flush the data to the socket | |
235 | @type bool | |
236 | @param idString id of the connection to send data to | |
237 | @type str | |
238 | """ | |
239 | commandDict = { | |
240 | "jsonrpc": "2.0", | |
241 | "method": command, | |
242 | "params": params, | |
243 | } | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
244 | cmd = json.dumps(commandDict) + "\n" |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
245 | |
8300 | 246 | if idString: |
247 | try: | |
248 | connection = self.__connections[idString] | |
249 | except KeyError: | |
250 | connection = None | |
251 | else: | |
252 | connection = self.__connection | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
253 | |
8300 | 254 | if connection is not None: |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
255 | data = cmd.encode("utf8", "backslashreplace") |
10524
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
256 | header = struct.pack(b"!II", len(data), zlib.adler32(data) & 0xFFFFFFFF) |
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
257 | connection.write(header) |
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
258 | connection.write(data) |
8300 | 259 | if flush: |
260 | connection.flush() | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
261 | |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
262 | def startClient( |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
263 | self, interpreter, clientScript, clientArgs, idString="", environment=None |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
264 | ): |
8300 | 265 | """ |
266 | Public method to start a client process. | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
267 | |
8300 | 268 | @param interpreter interpreter to be used for the client |
269 | @type str | |
270 | @param clientScript path to the client script | |
271 | @type str | |
272 | @param clientArgs list of arguments for the client | |
10423
299802979277
Converted some source code documentation to the new style.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10373
diff
changeset
|
273 | @type list of str |
8300 | 274 | @param idString id of the client to be started |
275 | @type str | |
276 | @param environment dictionary of environment settings to pass | |
277 | @type dict | |
8301
952a05857e81
E5JsonServer: changed code to return the exit code in case of a premature exit.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8300
diff
changeset
|
278 | @return flag indicating a successful client start and the exit code |
952a05857e81
E5JsonServer: changed code to return the exit code in case of a premature exit.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8300
diff
changeset
|
279 | in case of an issue |
952a05857e81
E5JsonServer: changed code to return the exit code in case of a premature exit.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8300
diff
changeset
|
280 | @rtype bool, int |
8300 | 281 | """ |
10928
46651e194fbe
Refactored some packages, modules and code to allow extracting the 'EricXxx' packages into a library project.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10697
diff
changeset
|
282 | if interpreter == "" or not bool(shutil.which(interpreter)): |
10205
6889b666ddef
Corrected an issue in the EricJsonServer code.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9653
diff
changeset
|
283 | return False, -1 |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
284 | |
8301
952a05857e81
E5JsonServer: changed code to return the exit code in case of a premature exit.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8300
diff
changeset
|
285 | exitCode = None |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
286 | |
8300 | 287 | proc = QProcess() |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
288 | proc.setProcessChannelMode(QProcess.ProcessChannelMode.ForwardedChannels) |
8300 | 289 | if environment is not None: |
290 | env = QProcessEnvironment() | |
10373
093dcebe5ecb
Corrected some uses of dict.keys(), dict.values() and dict.items().
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10205
diff
changeset
|
291 | for key, value in environment.items(): |
8300 | 292 | env.insert(key, value) |
293 | proc.setProcessEnvironment(env) | |
294 | args = [clientScript, self.__hostAddress, str(self.serverPort())] | |
295 | if idString: | |
296 | args.append(idString) | |
297 | args.extend(clientArgs) | |
298 | proc.start(interpreter, args) | |
299 | if not proc.waitForStarted(10000): | |
300 | proc = None | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
301 | |
8300 | 302 | if idString: |
303 | self.__clientProcesses[idString] = proc | |
304 | if proc: | |
305 | timer = QTimer() | |
306 | timer.setSingleShot(True) | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
307 | timer.start(30000) # 30s timeout |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
308 | while idString not in self.connectionNames() and timer.isActive(): |
8300 | 309 | # Give the event loop the chance to process the new |
310 | # connection of the client (= slow start). | |
311 | QCoreApplication.processEvents( | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
312 | QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
313 | ) |
8934
d3798915e0d2
Changed some code to not call QCoreApplication.processEvents() too often.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8881
diff
changeset
|
314 | QThread.msleep(100) |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
315 | |
8301
952a05857e81
E5JsonServer: changed code to return the exit code in case of a premature exit.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8300
diff
changeset
|
316 | # check if client exited prematurely |
8303
0cbba94590d2
E5JsonServer: fixed an issue introduced by the latest change.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8302
diff
changeset
|
317 | if proc.state() == QProcess.ProcessState.NotRunning: |
8301
952a05857e81
E5JsonServer: changed code to return the exit code in case of a premature exit.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8300
diff
changeset
|
318 | exitCode = proc.exitCode() |
952a05857e81
E5JsonServer: changed code to return the exit code in case of a premature exit.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8300
diff
changeset
|
319 | proc = None |
952a05857e81
E5JsonServer: changed code to return the exit code in case of a premature exit.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8300
diff
changeset
|
320 | self.__clientProcesses[idString] = None |
952a05857e81
E5JsonServer: changed code to return the exit code in case of a premature exit.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8300
diff
changeset
|
321 | break |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
322 | |
8936
dca47d2dde1c
Some performance optimizations.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8934
diff
changeset
|
323 | QThread.msleep(500) |
8300 | 324 | else: |
8303
0cbba94590d2
E5JsonServer: fixed an issue introduced by the latest change.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8302
diff
changeset
|
325 | if proc: |
0cbba94590d2
E5JsonServer: fixed an issue introduced by the latest change.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8302
diff
changeset
|
326 | timer = QTimer() |
0cbba94590d2
E5JsonServer: fixed an issue introduced by the latest change.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8302
diff
changeset
|
327 | timer.setSingleShot(True) |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
328 | timer.start(1000) # 1s timeout |
8303
0cbba94590d2
E5JsonServer: fixed an issue introduced by the latest change.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8302
diff
changeset
|
329 | while timer.isActive(): |
0cbba94590d2
E5JsonServer: fixed an issue introduced by the latest change.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8302
diff
changeset
|
330 | # check if client exited prematurely |
0cbba94590d2
E5JsonServer: fixed an issue introduced by the latest change.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8302
diff
changeset
|
331 | QCoreApplication.processEvents( |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
332 | QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
333 | ) |
8943
23f9c7b9e18e
Implemented some performance improvements.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8936
diff
changeset
|
334 | QThread.msleep(100) |
8303
0cbba94590d2
E5JsonServer: fixed an issue introduced by the latest change.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8302
diff
changeset
|
335 | if proc.state() == QProcess.ProcessState.NotRunning: |
0cbba94590d2
E5JsonServer: fixed an issue introduced by the latest change.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8302
diff
changeset
|
336 | exitCode = proc.exitCode() |
0cbba94590d2
E5JsonServer: fixed an issue introduced by the latest change.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8302
diff
changeset
|
337 | proc = None |
0cbba94590d2
E5JsonServer: fixed an issue introduced by the latest change.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8302
diff
changeset
|
338 | break |
8300 | 339 | self.__clientProcess = proc |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
340 | |
8301
952a05857e81
E5JsonServer: changed code to return the exit code in case of a premature exit.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8300
diff
changeset
|
341 | return proc is not None, exitCode |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
342 | |
8300 | 343 | def stopClient(self, idString=""): |
344 | """ | |
345 | Public method to stop a client process. | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
346 | |
8300 | 347 | @param idString id of the client to be stopped |
348 | @type str | |
349 | """ | |
350 | self.sendJson("Exit", {}, flush=True, idString=idString) | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
351 | |
8300 | 352 | if idString: |
353 | try: | |
354 | connection = self.__connections[idString] | |
355 | except KeyError: | |
356 | connection = None | |
357 | else: | |
358 | connection = self.__connection | |
359 | if connection is not None: | |
360 | connection.waitForDisconnected() | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
361 | |
8300 | 362 | if idString: |
363 | with contextlib.suppress(KeyError): | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
364 | if self.__clientProcesses[idString] is not None: |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
365 | self.__clientProcesses[idString].close() |
8300 | 366 | del self.__clientProcesses[idString] |
367 | else: | |
368 | if self.__clientProcess is not None: | |
369 | self.__clientProcess.close() | |
370 | self.__clientProcess = None | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
371 | |
8300 | 372 | def stopAllClients(self): |
373 | """ | |
374 | Public method to stop all clients. | |
375 | """ | |
376 | clientNames = self.connectionNames()[:] | |
377 | for clientName in clientNames: | |
378 | self.stopClient(clientName) | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
379 | |
8300 | 380 | ####################################################################### |
381 | ## The following methods should be overridden by derived classes | |
382 | ####################################################################### | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
383 | |
8300 | 384 | def handleCall(self, method, params): |
385 | """ | |
386 | Public method to handle a method call from the client. | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
387 | |
8300 | 388 | Note: This is an empty implementation that must be overridden in |
389 | derived classes. | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
390 | |
8300 | 391 | @param method requested method name |
392 | @type str | |
393 | @param params dictionary with method specific parameters | |
394 | @type dict | |
395 | """ | |
396 | pass |