Mon, 24 Feb 2025 15:43:49 +0100
Adjusted the code to the modified issue codes.
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 | |
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
|
37 | def __init__(self, name="", interface="127.0.0.1", multiplex=False, parent=None): |
8300 | 38 | """ |
39 | Constructor | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
40 | |
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
|
41 | @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
|
42 | @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
|
43 | @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
|
44 | "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
|
45 | @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
|
46 | @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
|
47 | @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
|
48 | @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
|
49 | @type QObject (optional) |
8300 | 50 | """ |
51 | super().__init__(parent) | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
52 | |
8300 | 53 | self.__name = name |
54 | self.__multiplex = multiplex | |
55 | if self.__multiplex: | |
56 | self.__clientProcesses = {} | |
57 | self.__connections = {} | |
58 | else: | |
59 | self.__clientProcess = None | |
60 | self.__connection = None | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
61 | |
8300 | 62 | # 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
|
63 | if interface in ("allv4", "localv4") or "." in interface: |
8300 | 64 | # IPv4 |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
65 | 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
|
66 | elif interface in ("all", "allv6", "localv6"): |
8300 | 67 | # IPv6 |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
68 | self.__hostAddress = "::1" |
9521 | 69 | 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
|
70 | self.__hostAddress = interface |
8300 | 71 | self.listen(QHostAddress(self.__hostAddress)) |
72 | ||
73 | 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
|
74 | |
9521 | 75 | ## Note: Need the address and port if client is started external in debugger. |
76 | hostAddressStr = ( | |
77 | "[{0}]".format(self.__hostAddress) | |
78 | if ":" in self.__hostAddress | |
79 | else self.__hostAddress | |
80 | ) | |
11148
15e30f0c76a8
Adjusted the code to the modified issue codes.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
11090
diff
changeset
|
81 | print( # __IGNORE_WARNING_M-801__ |
9521 | 82 | "JSON server ({2}) listening on: {0}:{1:d}".format( |
83 | hostAddressStr, self.serverPort(), self.__name | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
84 | ) |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
85 | ) |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
86 | |
8300 | 87 | @pyqtSlot() |
88 | def handleNewConnection(self): | |
89 | """ | |
90 | Public slot for new incoming connections from a client. | |
91 | """ | |
92 | connection = self.nextPendingConnection() | |
93 | if not connection.isValid(): | |
94 | return | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
95 | |
8300 | 96 | if self.__multiplex: |
97 | if not connection.waitForReadyRead(3000): | |
98 | return | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
99 | idString = ( |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
100 | 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
|
101 | ) |
8300 | 102 | if idString in self.__connections: |
103 | self.__connections[idString].close() | |
104 | self.__connections[idString] = connection | |
105 | else: | |
106 | idString = "" | |
107 | if self.__connection is not None: | |
108 | self.__connection.close() | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
109 | |
8300 | 110 | self.__connection = connection |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
111 | |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
112 | 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
|
113 | 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
|
114 | |
8300 | 115 | @pyqtSlot() |
116 | def __handleDisconnect(self, idString): | |
117 | """ | |
118 | 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
|
119 | |
8300 | 120 | @param idString id of the connection been disconnected |
121 | @type str | |
122 | """ | |
123 | if idString: | |
124 | if idString in self.__connections: | |
125 | self.__connections[idString].close() | |
126 | del self.__connections[idString] | |
127 | else: | |
128 | if self.__connection is not None: | |
129 | self.__connection.close() | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
130 | |
8300 | 131 | self.__connection = None |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
132 | |
8300 | 133 | def connectionNames(self): |
134 | """ | |
135 | 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
|
136 | |
8300 | 137 | 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
|
138 | |
8300 | 139 | @return list of active connection names |
140 | @rtype list of str | |
141 | """ | |
142 | 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
|
143 | return list(self.__connections) |
8300 | 144 | else: |
145 | return [] | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
146 | |
8300 | 147 | @pyqtSlot() |
148 | def __receiveJson(self, idString): | |
149 | """ | |
150 | 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
|
151 | |
9057
ddc46e93ccc4
Added classes to realize a JSON based stream between two processes.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8943
diff
changeset
|
152 | @param idString id of the connection |
8300 | 153 | @type str |
154 | """ | |
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
|
155 | 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
|
156 | |
8300 | 157 | if idString: |
158 | try: | |
159 | connection = self.__connections[idString] | |
160 | except KeyError: | |
161 | connection = None | |
162 | else: | |
163 | connection = self.__connection | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
164 | |
10524
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
165 | 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
|
166 | 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
|
167 | 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
|
168 | 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
|
169 | 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
|
170 | 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
|
171 | header = connection.read(headerSize) |
10524
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
172 | 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
|
173 | |
10524
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
174 | 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
|
175 | now = time.monotonic() |
10524
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
176 | while len(data) < length: |
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
177 | maxSize = length - len(data) |
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
178 | if connection.bytesAvailable() < maxSize: |
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
179 | 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
|
180 | 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
|
181 | 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
|
182 | 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
|
183 | 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
|
184 | 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
|
185 | break |
10524
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
186 | |
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
187 | if zlib.adler32(data) & 0xFFFFFFFF != datahash: |
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
188 | # corrupted data -> discard and continue |
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
189 | continue |
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
190 | |
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
191 | jsonString = data.decode("utf-8", "backslashreplace") |
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
192 | |
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
193 | # - print("JSON Server ({0}): {1}".format(self.__name, jsonString)) |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
194 | # - this is for debugging only |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
195 | |
8300 | 196 | try: |
10524
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
197 | clientDict = json.loads(jsonString.strip()) |
8300 | 198 | 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
|
199 | EricMessageBox.critical( |
8300 | 200 | None, |
201 | 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
|
202 | self.tr( |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
203 | """<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
|
204 | """ 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
|
205 | """ 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
|
206 | """ eric bugs email address.</p>""" |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
207 | """<p>Error: {0}</p>""" |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
208 | """<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
|
209 | ).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
|
210 | EricMessageBox.Ok, |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
211 | ) |
8300 | 212 | return |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
213 | |
8300 | 214 | 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
|
215 | |
8300 | 216 | def sendJson(self, command, params, flush=False, idString=""): |
217 | """ | |
218 | 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
|
219 | |
8300 | 220 | @param command command name to be sent |
221 | @type str | |
222 | @param params dictionary of named parameters for the command | |
223 | @type dict | |
224 | @param flush flag indicating to flush the data to the socket | |
225 | @type bool | |
226 | @param idString id of the connection to send data to | |
227 | @type str | |
228 | """ | |
229 | commandDict = { | |
230 | "jsonrpc": "2.0", | |
231 | "method": command, | |
232 | "params": params, | |
233 | } | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
234 | cmd = json.dumps(commandDict) + "\n" |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
235 | |
8300 | 236 | if idString: |
237 | try: | |
238 | connection = self.__connections[idString] | |
239 | except KeyError: | |
240 | connection = None | |
241 | else: | |
242 | connection = self.__connection | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
243 | |
8300 | 244 | 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
|
245 | data = cmd.encode("utf8", "backslashreplace") |
10524
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
246 | 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
|
247 | connection.write(header) |
ed4fd87c4d4c
JSON server and client
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
10439
diff
changeset
|
248 | connection.write(data) |
8300 | 249 | if flush: |
250 | connection.flush() | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
251 | |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
252 | def startClient( |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
253 | 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
|
254 | ): |
8300 | 255 | """ |
256 | 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
|
257 | |
8300 | 258 | @param interpreter interpreter to be used for the client |
259 | @type str | |
260 | @param clientScript path to the client script | |
261 | @type str | |
262 | @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
|
263 | @type list of str |
8300 | 264 | @param idString id of the client to be started |
265 | @type str | |
266 | @param environment dictionary of environment settings to pass | |
267 | @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
|
268 | @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
|
269 | 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
|
270 | @rtype bool, int |
8300 | 271 | """ |
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
|
272 | 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
|
273 | return False, -1 |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
274 | |
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
|
275 | exitCode = None |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
276 | |
8300 | 277 | proc = QProcess() |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
278 | proc.setProcessChannelMode(QProcess.ProcessChannelMode.ForwardedChannels) |
8300 | 279 | if environment is not None: |
280 | 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
|
281 | for key, value in environment.items(): |
8300 | 282 | env.insert(key, value) |
283 | proc.setProcessEnvironment(env) | |
284 | args = [clientScript, self.__hostAddress, str(self.serverPort())] | |
285 | if idString: | |
286 | args.append(idString) | |
287 | args.extend(clientArgs) | |
288 | proc.start(interpreter, args) | |
289 | if not proc.waitForStarted(10000): | |
290 | proc = None | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
291 | |
8300 | 292 | if idString: |
293 | self.__clientProcesses[idString] = proc | |
294 | if proc: | |
295 | timer = QTimer() | |
296 | timer.setSingleShot(True) | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
297 | timer.start(30000) # 30s timeout |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
298 | while idString not in self.connectionNames() and timer.isActive(): |
8300 | 299 | # Give the event loop the chance to process the new |
300 | # connection of the client (= slow start). | |
301 | QCoreApplication.processEvents( | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
302 | QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
303 | ) |
8934
d3798915e0d2
Changed some code to not call QCoreApplication.processEvents() too often.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8881
diff
changeset
|
304 | QThread.msleep(100) |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
305 | |
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
|
306 | # 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
|
307 | 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
|
308 | 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
|
309 | 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
|
310 | 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
|
311 | break |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
312 | |
8936
dca47d2dde1c
Some performance optimizations.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8934
diff
changeset
|
313 | QThread.msleep(500) |
8300 | 314 | else: |
8303
0cbba94590d2
E5JsonServer: fixed an issue introduced by the latest change.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8302
diff
changeset
|
315 | if proc: |
0cbba94590d2
E5JsonServer: fixed an issue introduced by the latest change.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8302
diff
changeset
|
316 | timer = QTimer() |
0cbba94590d2
E5JsonServer: fixed an issue introduced by the latest change.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8302
diff
changeset
|
317 | timer.setSingleShot(True) |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
318 | 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
|
319 | while timer.isActive(): |
0cbba94590d2
E5JsonServer: fixed an issue introduced by the latest change.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8302
diff
changeset
|
320 | # 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
|
321 | QCoreApplication.processEvents( |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
322 | QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents |
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
323 | ) |
8943
23f9c7b9e18e
Implemented some performance improvements.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8936
diff
changeset
|
324 | QThread.msleep(100) |
8303
0cbba94590d2
E5JsonServer: fixed an issue introduced by the latest change.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8302
diff
changeset
|
325 | 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
|
326 | exitCode = proc.exitCode() |
0cbba94590d2
E5JsonServer: fixed an issue introduced by the latest change.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8302
diff
changeset
|
327 | proc = None |
0cbba94590d2
E5JsonServer: fixed an issue introduced by the latest change.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
8302
diff
changeset
|
328 | break |
8300 | 329 | self.__clientProcess = proc |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
330 | |
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
|
331 | 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
|
332 | |
8300 | 333 | def stopClient(self, idString=""): |
334 | """ | |
335 | 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
|
336 | |
8300 | 337 | @param idString id of the client to be stopped |
338 | @type str | |
339 | """ | |
340 | 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
|
341 | |
8300 | 342 | if idString: |
343 | try: | |
344 | connection = self.__connections[idString] | |
345 | except KeyError: | |
346 | connection = None | |
347 | else: | |
348 | connection = self.__connection | |
349 | if connection is not None: | |
350 | connection.waitForDisconnected() | |
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 | with contextlib.suppress(KeyError): | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
354 | 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
|
355 | self.__clientProcesses[idString].close() |
8300 | 356 | del self.__clientProcesses[idString] |
357 | else: | |
358 | if self.__clientProcess is not None: | |
359 | self.__clientProcess.close() | |
360 | self.__clientProcess = None | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
361 | |
8300 | 362 | def stopAllClients(self): |
363 | """ | |
364 | Public method to stop all clients. | |
365 | """ | |
366 | clientNames = self.connectionNames()[:] | |
367 | for clientName in clientNames: | |
368 | self.stopClient(clientName) | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
369 | |
8300 | 370 | ####################################################################### |
371 | ## The following methods should be overridden by derived classes | |
372 | ####################################################################### | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
373 | |
8300 | 374 | def handleCall(self, method, params): |
375 | """ | |
376 | 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
|
377 | |
8300 | 378 | Note: This is an empty implementation that must be overridden in |
379 | derived classes. | |
9221
bf71ee032bb4
Reformatted the source code using the 'Black' utility.
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
9209
diff
changeset
|
380 | |
8300 | 381 | @param method requested method name |
382 | @type str | |
383 | @param params dictionary with method specific parameters | |
384 | @type dict | |
385 | """ | |
386 | pass |