eric6/E5Network/E5JsonServer.py

Sun, 09 May 2021 14:53:27 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sun, 09 May 2021 14:53:27 +0200
changeset 8300
72ba9635ec5c
child 8301
952a05857e81
permissions
-rw-r--r--

E5Network
- added base classes for a JSON based server and client (examples see rope and jedi plug-in)

8300
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1 # -*- coding: utf-8 -*-
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
2
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
3 # Copyright (c) 2017 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
4 #
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
5
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
6 """
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
7 Module implementing the JSON based server base class.
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
8 """
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
9
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
10 import contextlib
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
11 import json
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
12
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
13 from PyQt5.QtCore import (
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
14 pyqtSlot, QProcess, QProcessEnvironment, QCoreApplication, QEventLoop,
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
15 QTimer
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
16 )
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
17 from PyQt5.QtNetwork import QTcpServer, QHostAddress
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
18
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
19 from E5Gui import E5MessageBox
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
20
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
21 import Preferences
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
22 import Utilities
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
23
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
24
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
25 class E5JsonServer(QTcpServer):
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
26 """
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
27 Class implementing a JSON based server base class.
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
28 """
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
29 def __init__(self, name="", multiplex=False, parent=None):
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
30 """
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
31 Constructor
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
32
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
33 @param name name of the server (used for output only)
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
34 @type str
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
35 @param multiplex flag indicating a multiplexing server
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
36 @type bool
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
37 @param parent parent object
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
38 @type QObject
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
39 """
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
40 super().__init__(parent)
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
41
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
42 self.__name = name
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
43 self.__multiplex = multiplex
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
44 if self.__multiplex:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
45 self.__clientProcesses = {}
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
46 self.__connections = {}
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
47 else:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
48 self.__clientProcess = None
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
49 self.__connection = None
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
50
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
51 # setup the network interface
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
52 networkInterface = Preferences.getDebugger("NetworkInterface")
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
53 if networkInterface == "all" or '.' in networkInterface:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
54 # IPv4
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
55 self.__hostAddress = '127.0.0.1'
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
56 else:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
57 # IPv6
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
58 self.__hostAddress = '::1'
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
59 self.listen(QHostAddress(self.__hostAddress))
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
60
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
61 self.newConnection.connect(self.handleNewConnection)
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
62
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
63 port = self.serverPort()
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
64 ## Note: Need the port if client is started external in debugger.
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
65 print('JSON server ({1}) listening on: {0:d}' # __IGNORE_WARNING__
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
66 .format(port, self.__name))
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
67
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
68 @pyqtSlot()
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
69 def handleNewConnection(self):
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
70 """
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
71 Public slot for new incoming connections from a client.
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
72 """
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
73 connection = self.nextPendingConnection()
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
74 if not connection.isValid():
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
75 return
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
76
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
77 if self.__multiplex:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
78 if not connection.waitForReadyRead(3000):
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
79 return
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
80 idString = bytes(connection.readLine()).decode(
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
81 "utf-8", 'backslashreplace').strip()
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
82 if idString in self.__connections:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
83 self.__connections[idString].close()
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
84 self.__connections[idString] = connection
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
85 else:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
86 idString = ""
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
87 if self.__connection is not None:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
88 self.__connection.close()
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
89
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
90 self.__connection = connection
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
91
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
92 connection.readyRead.connect(
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
93 lambda: self.__receiveJson(idString))
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
94 connection.disconnected.connect(
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
95 lambda: self.__handleDisconnect(idString))
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
96
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
97 @pyqtSlot()
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
98 def __handleDisconnect(self, idString):
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
99 """
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
100 Private slot handling a disconnect of the client.
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
101
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
102 @param idString id of the connection been disconnected
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
103 @type str
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
104 """
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
105 if idString:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
106 if idString in self.__connections:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
107 self.__connections[idString].close()
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
108 del self.__connections[idString]
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
109 else:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
110 if self.__connection is not None:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
111 self.__connection.close()
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
112
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
113 self.__connection = None
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
114
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
115 def connectionNames(self):
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
116 """
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
117 Public method to get the list of active connection names.
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
118
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
119 If this is not a multiplexing server, an empty list is returned.
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
120
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
121 @return list of active connection names
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
122 @rtype list of str
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
123 """
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
124 if self.__multiplex:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
125 return list(self.__connections.keys())
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
126 else:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
127 return []
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
128
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
129 @pyqtSlot()
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
130 def __receiveJson(self, idString):
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
131 """
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
132 Private slot handling received data from the client.
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
133
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
134 @param idString id of the connection been disconnected
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
135 @type str
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
136 """
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
137 if idString:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
138 try:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
139 connection = self.__connections[idString]
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
140 except KeyError:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
141 connection = None
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
142 else:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
143 connection = self.__connection
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
144
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
145 while connection and connection.canReadLine():
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
146 data = connection.readLine()
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
147 jsonLine = bytes(data).decode("utf-8", 'backslashreplace')
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
148
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
149 #- print("JSON Server ({0}): {1}".format(self.__name, jsonLine))
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
150 #- this is for debugging only
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
151
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
152 try:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
153 clientDict = json.loads(jsonLine.strip())
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
154 except (TypeError, ValueError) as err:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
155 E5MessageBox.critical(
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
156 None,
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
157 self.tr("JSON Protocol Error"),
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
158 self.tr("""<p>The response received from the client"""
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
159 """ could not be decoded. Please report"""
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
160 """ this issue with the received data to the"""
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
161 """ eric bugs email address.</p>"""
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
162 """<p>Error: {0}</p>"""
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
163 """<p>Data:<br/>{1}</p>""").format(
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
164 str(err), Utilities.html_encode(jsonLine.strip())),
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
165 E5MessageBox.StandardButtons(
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
166 E5MessageBox.Ok))
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
167 return
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
168
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
169 self.handleCall(clientDict["method"], clientDict["params"])
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
170
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
171 def sendJson(self, command, params, flush=False, idString=""):
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
172 """
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
173 Public method to send a single command to a client.
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
174
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
175 @param command command name to be sent
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
176 @type str
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
177 @param params dictionary of named parameters for the command
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
178 @type dict
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
179 @param flush flag indicating to flush the data to the socket
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
180 @type bool
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
181 @param idString id of the connection to send data to
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
182 @type str
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
183 """
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
184 commandDict = {
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
185 "jsonrpc": "2.0",
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
186 "method": command,
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
187 "params": params,
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
188 }
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
189 cmd = json.dumps(commandDict) + '\n'
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
190
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
191 if idString:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
192 try:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
193 connection = self.__connections[idString]
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
194 except KeyError:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
195 connection = None
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
196 else:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
197 connection = self.__connection
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
198
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
199 if connection is not None:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
200 data = cmd.encode('utf8', 'backslashreplace')
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
201 length = "{0:09d}".format(len(data))
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
202 connection.write(length.encode() + data)
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
203 if flush:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
204 connection.flush()
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
205
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
206 def startClient(self, interpreter, clientScript, clientArgs, idString="",
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
207 environment=None):
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
208 """
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
209 Public method to start a client process.
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
210
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
211 @param interpreter interpreter to be used for the client
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
212 @type str
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
213 @param clientScript path to the client script
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
214 @type str
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
215 @param clientArgs list of arguments for the client
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
216 @param idString id of the client to be started
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
217 @type str
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
218 @param environment dictionary of environment settings to pass
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
219 @type dict
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
220 @return flag indicating a successful client start
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
221 @rtype bool
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
222 """
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
223 if interpreter == "" or not Utilities.isinpath(interpreter):
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
224 return False
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
225
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
226 proc = QProcess()
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
227 proc.setProcessChannelMode(
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
228 QProcess.ProcessChannelMode.ForwardedChannels)
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
229 if environment is not None:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
230 env = QProcessEnvironment()
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
231 for key, value in list(environment.items()):
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
232 env.insert(key, value)
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
233 proc.setProcessEnvironment(env)
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
234 args = [clientScript, self.__hostAddress, str(self.serverPort())]
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
235 if idString:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
236 args.append(idString)
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
237 args.extend(clientArgs)
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
238 proc.start(interpreter, args)
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
239 if not proc.waitForStarted(10000):
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
240 proc = None
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
241
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
242 if idString:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
243 self.__clientProcesses[idString] = proc
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
244 if proc:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
245 timer = QTimer()
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
246 timer.setSingleShot(True)
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
247 timer.start(30000) # 30s timeout
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
248 while (
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
249 idString not in self.connectionNames() and
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
250 timer.isActive()
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
251 ):
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
252 # Give the event loop the chance to process the new
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
253 # connection of the client (= slow start).
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
254 QCoreApplication.processEvents(
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
255 QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents)
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
256 else:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
257 self.__clientProcess = proc
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
258
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
259 return proc is not None
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
260
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
261 def stopClient(self, idString=""):
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
262 """
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
263 Public method to stop a client process.
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
264
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
265 @param idString id of the client to be stopped
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
266 @type str
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
267 """
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
268 self.sendJson("Exit", {}, flush=True, idString=idString)
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
269
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
270 if idString:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
271 try:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
272 connection = self.__connections[idString]
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
273 except KeyError:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
274 connection = None
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
275 else:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
276 connection = self.__connection
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
277 if connection is not None:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
278 connection.waitForDisconnected()
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
279
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
280 if idString:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
281 with contextlib.suppress(KeyError):
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
282 self .__clientProcesses[idString].close()
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
283 del self.__clientProcesses[idString]
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
284 else:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
285 if self.__clientProcess is not None:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
286 self.__clientProcess.close()
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
287 self.__clientProcess = None
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
288
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
289 def stopAllClients(self):
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
290 """
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
291 Public method to stop all clients.
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
292 """
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
293 clientNames = self.connectionNames()[:]
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
294 for clientName in clientNames:
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
295 self.stopClient(clientName)
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
296
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
297 #######################################################################
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
298 ## The following methods should be overridden by derived classes
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
299 #######################################################################
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
300
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
301 def handleCall(self, method, params):
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
302 """
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
303 Public method to handle a method call from the client.
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
304
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
305 Note: This is an empty implementation that must be overridden in
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
306 derived classes.
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
307
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
308 @param method requested method name
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
309 @type str
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
310 @param params dictionary with method specific parameters
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
311 @type dict
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
312 """
72ba9635ec5c E5Network
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
313 pass

eric ide

mercurial