Toolbox/SingleApplication.py

changeset 6622
3dfcbe478fd3
parent 6048
82ad8ec9548c
child 6625
a67fee7bc09c
equal deleted inserted replaced
6621:db2ec0feca8a 6622:3dfcbe478fd3
7 Module implementing the single application server and client. 7 Module implementing the single application server and client.
8 """ 8 """
9 9
10 from __future__ import unicode_literals 10 from __future__ import unicode_literals
11 11
12 import json
13
12 from PyQt5.QtCore import QByteArray 14 from PyQt5.QtCore import QByteArray
13 from PyQt5.QtNetwork import QLocalServer, QLocalSocket 15 from PyQt5.QtNetwork import QLocalServer, QLocalSocket
16
17 from E5Gui import E5MessageBox
18
19 import Utilities
14 20
15 21
16 class SingleApplicationServer(QLocalServer): 22 class SingleApplicationServer(QLocalServer):
17 """ 23 """
18 Class implementing the single application server base class. 24 Class implementing the single application server base class.
39 """ 45 """
40 Private slot to handle a new connection. 46 Private slot to handle a new connection.
41 """ 47 """
42 sock = self.nextPendingConnection() 48 sock = self.nextPendingConnection()
43 49
44 # If we already have a connection, refuse this one. It will be closed 50 # If we already have a connection, refuse this one. It will be closed
45 # automatically. 51 # automatically.
46 if self.qsock is not None: 52 if self.qsock is not None:
47 return 53 return
48 54
49 self.qsock = sock 55 self.qsock = sock
50 56
51 self.qsock.readyRead.connect(self.__parseLine) 57 self.qsock.readyRead.connect(self.__receiveJson)
52 self.qsock.disconnected.connect(self.__disconnected) 58 self.qsock.disconnected.connect(self.__disconnected)
53 59
54 def __parseLine(self): 60 def __receiveJson(self):
55 """ 61 """
56 Private method to handle data from the client. 62 Private method to receive the data from the client.
57 """ 63 """
58 while self.qsock and self.qsock.canReadLine(): 64 while self.qsock and self.qsock.canReadLine():
59 line = bytes(self.qsock.readLine()).decode() 65 line = bytes(self.qsock.readLine()).decode()
60 66
61 ## print(line) ##debug 67 ## print(line) ##debug
62 68
63 eoc = line.find('<') + 1 69 try:
64 70 commandDict = json.loads(line.strip())
65 boc = line.find('>') 71 except (TypeError, ValueError) as err:
66 if boc >= 0 and eoc > boc: 72 E5MessageBox.critical(
67 # handle the command sent by the client. 73 None,
68 cmd = line[boc:eoc] 74 self.tr("Single Application Protocol Error"),
69 params = line[eoc:-1] 75 self.tr("""<p>The response received from the single"""
70 76 """ application client could not be decoded."""
71 self.handleCommand(cmd, params) 77 """ Please report this issue with the received"""
78 """ data to the eric bugs email address.</p>"""
79 """<p>Error: {0}</p>"""
80 """<p>Data:<br/>{0}</p>""").format(
81 str(err), Utilities.html_encode(line.strip())),
82 E5MessageBox.StandardButtons(
83 E5MessageBox.Ok))
84 return
85
86 command = commandDict["command"]
87 arguments = commandDict["arguments"]
88
89 self.handleCommand(command, arguments)
72 90
73 def __disconnected(self): 91 def __disconnected(self):
74 """ 92 """
75 Private method to handle the closure of the socket. 93 Private method to handle the closure of the socket.
76 """ 94 """
86 104
87 self.qsock = None 105 self.qsock = None
88 106
89 self.close() 107 self.close()
90 108
91 def handleCommand(self, cmd, params): 109 def handleCommand(self, command, arguments):
92 """ 110 """
93 Public slot to handle the command sent by the client. 111 Public slot to handle the command sent by the client.
94 112
95 <b>Note</b>: This method must be overridden by subclasses. 113 <b>Note</b>: This method must be overridden by subclasses.
96 114
97 @param cmd commandstring (string) 115 @param command command sent by the client
98 @param params parameterstring (string) 116 @type str
117 @param arguments list of command arguments
118 @type list of str
99 @exception RuntimeError raised to indicate that this method must be 119 @exception RuntimeError raised to indicate that this method must be
100 implemented by a subclass 120 implemented by a subclass
101 """ 121 """
102 raise RuntimeError("'handleCommand' must be overridden") 122 raise RuntimeError("'handleCommand' must be overridden")
103 123
154 @exception RuntimeError raised to indicate that this method must be 174 @exception RuntimeError raised to indicate that this method must be
155 implemented by a subclass 175 implemented by a subclass
156 """ 176 """
157 raise RuntimeError("'processArgs' must be overridden") 177 raise RuntimeError("'processArgs' must be overridden")
158 178
159 def sendCommand(self, cmd): 179 def sendCommand(self, command, arguments):
160 """ 180 """
161 Public method to send the command to the application server. 181 Public method to send the command to the application server.
162 182
163 @param cmd command to be sent (string) 183 @param command command to be sent to the server
184 @type str
185 @param arguments list of command arguments
186 @type list of str
164 """ 187 """
165 if self.connected: 188 if self.connected:
166 self.sock.write(QByteArray(cmd.encode())) 189 commandDict = {
190 "command": command,
191 "arguments": arguments,
192 }
193 self.sock.write(QByteArray(
194 "{0}\n".format(json.dumps(commandDict)).encode()
195 ))
167 self.sock.flush() 196 self.sock.flush()
168 197
169 def errstr(self): 198 def errstr(self):
170 """ 199 """
171 Public method to return a meaningful error string for the last error. 200 Public method to return a meaningful error string for the last error.

eric ide

mercurial