RefactoringRope/JsonServer.py

branch
server_client_variant
changeset 163
6a9e7b37a18b
child 166
6fc202183b3b
equal deleted inserted replaced
162:55eaaed9d590 163:6a9e7b37a18b
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2017 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the JSON based server base class.
8 """
9
10 from __future__ import unicode_literals
11
12 import json
13
14 from PyQt5.QtCore import pyqtSlot, QProcess
15 from PyQt5.QtNetwork import QTcpServer, QHostAddress
16
17 from E5Gui import E5MessageBox
18
19 import Preferences
20 import Utilities
21
22
23 class JsonServer(QTcpServer):
24 """
25 Class implementing the JSON based server base class.
26 """
27 def __init__(self, parent=None):
28 """
29 Constructor
30
31 @param parent parent object
32 @type QObject
33 """
34 super(JsonServer, self).__init__(parent)
35
36 self.__clientProcess = None
37 self.__connection = None
38
39 # setup the network interface
40 networkInterface = Preferences.getDebugger("NetworkInterface")
41 if networkInterface == "all" or '.' in networkInterface:
42 # IPv4
43 self.__hostAddress = '127.0.0.1'
44 else:
45 # IPv6
46 self.__hostAddress = '::1'
47 self.listen(QHostAddress(self.__hostAddress))
48
49 self.newConnection.connect(self.__handleNewConnection)
50
51 port = self.serverPort()
52 ## Note: Need the port if started external in debugger:
53 print('Refactoring server listening on: {0:d}'.format(port))
54 # __IGNORE_WARNING__
55
56 @pyqtSlot()
57 def __handleNewConnection(self):
58 """
59 Private slot for new incomming connections from the refactoring client.
60 """
61 if self.__connection is not None:
62 self.__connection.close()
63 self.__connection = None
64
65 connection = self.nextPendingConnection()
66 if not connection.isValid():
67 return
68
69 self.__connection = connection
70 connection.readyRead.connect(self.__receiveJson)
71 connection.disconnected.connect(self.__handleDisconnect)
72
73 self.sendJson("ping", {})
74
75 @pyqtSlot()
76 def __handleDisconnect(self):
77 """
78 Private slot handling a disconnect of the refactoring client.
79 """
80 if self.__connection is not None:
81 self.__connection.close()
82
83 self.__connection = None
84
85 @pyqtSlot()
86 def __receiveJson(self):
87 """
88 Private slot handling received data from the client.
89 """
90 while self.__connection and self.__connection.canReadLine():
91 data = self.__connection.readLine()
92 jsonLine = bytes(data).decode("utf-8", 'backslashreplace')
93
94 print("JSON Server: ", jsonLine) ##debug
95
96 try:
97 clientDict = json.loads(jsonLine.strip())
98 except (TypeError, ValueError) as err:
99 E5MessageBox.critical(
100 None,
101 self.tr("JSON Protocol Error"),
102 self.tr("""<p>The response received from the client"""
103 """ could not be decoded. Please report"""
104 """ this issue with the received data to the"""
105 """ eric bugs email address.</p>"""
106 """<p>Error: {0}</p>"""
107 """<p>Data:<br/>{0}</p>""").format(
108 str(err), Utilities.html_encode(jsonLine.strip())),
109 E5MessageBox.StandardButtons(
110 E5MessageBox.Ok))
111 return
112
113 method = clientDict["method"]
114 params = clientDict["params"]
115
116 # TODO: remove these once done
117 print("Method:", method)
118 print("Params:", params)
119
120 self.handleCall(method, params)
121
122 def handleCall(self, method, params):
123 """
124 Public method to handle a method call from the client.
125
126 Note: This is an empty implementation that must be overridden in
127 derived classes.
128
129 @param method requested method name
130 @type str
131 @param params dictionary with method specific parameters
132 @type dict
133 """
134 pass
135
136 def sendJson(self, command, params):
137 """
138 Public method to send a single refactoring command to the client.
139
140 @param command command name to be sent
141 @type str
142 @param params dictionary of named parameters for the command
143 @type dict
144 """
145 commandDict = {
146 "jsonrpc": "2.0",
147 "method": command,
148 "params": params,
149 }
150 cmd = json.dumps(commandDict) + '\n'
151
152 if self.__connection is not None:
153 self.__connection.write(cmd.encode('utf8', 'backslashreplace'))
154
155 def startClient(self, interpreter, clientScript, clientArgs):
156 """
157 Public method to start the client process.
158
159 @param interpreter interpreter to be used for the client
160 @type str
161 @param clientScript path to the client script
162 @type str
163 @param clientArgs list of arguments for the client
164 @return flag indicating a successful client start
165 @rtype bool
166 """
167 if interpreter == "" or not Utilities.isinpath(interpreter):
168 return False
169
170 proc = QProcess()
171 proc.setProcessChannelMode(QProcess.ForwardedChannels)
172 args = [clientScript, self.__hostAddress, str(self.serverPort())]
173 args.extend(clientArgs)
174 proc.start(interpreter, args)
175 if not proc.waitForStarted(10000):
176 proc = None
177
178 self.__clientProcess = proc
179
180 return proc is not None
181
182 def stopClient(self):
183 """
184 Public method to stop the client process.
185 """
186 self.__clientProcess.close()
187 self.__clientProcess = None
188
189 #
190 # eflag: noqa = M801

eric ide

mercurial