50 commandDict = { |
52 commandDict = { |
51 "jsonrpc": "2.0", |
53 "jsonrpc": "2.0", |
52 "method": command, |
54 "method": command, |
53 "params": params, |
55 "params": params, |
54 } |
56 } |
55 cmd = json.dumps(commandDict) + "\n" |
57 data = json.dumps(commandDict).encode("utf8", "backslashreplace") |
56 self.__connection.sendall(cmd.encode("utf8", "backslashreplace")) |
58 header = struct.pack(b"!II", len(data), zlib.adler32(data) & 0xFFFFFFFF) |
57 |
59 self.__connection.sendall(header) |
58 def __receiveJson(self): |
60 self.__connection.sendall(data) |
59 """ |
61 |
60 Private method to receive a JSON encoded command and data from the |
62 def __receiveBytes(self, length): |
61 server. |
63 """ |
62 |
64 Private method to receive the given length of bytes. |
63 @return tuple containing the received command and a dictionary |
65 |
64 containing the associated data |
66 @param length bytes to receive |
65 @rtype tuple of (str, dict) |
67 @type int |
66 """ |
68 @return received bytes or None if connection closed |
67 # step 1: receive the data |
69 @rtype bytes |
68 # The JSON RPC string is prefixed by a 9 character long length field. |
70 """ |
69 length = self.__connection.recv(9) |
|
70 if len(length) < 9: |
|
71 # invalid length string received |
|
72 return None, None |
|
73 |
|
74 length = int(length) |
|
75 data = bytearray() |
71 data = bytearray() |
76 while len(data) < length: |
72 while len(data) < length: |
77 newData = self.__connection.recv(length - len(data)) |
73 newData = self.__connection.recv(length - len(data)) |
78 if not newData: |
74 if not newData: |
79 return None, None |
75 return None |
80 |
76 |
81 data += newData |
77 data += newData |
|
78 return data |
|
79 |
|
80 def __receiveJson(self): |
|
81 """ |
|
82 Private method to receive a JSON encoded command and data from the |
|
83 server. |
|
84 |
|
85 @return tuple containing the received command and a dictionary |
|
86 containing the associated data |
|
87 @rtype tuple of (str, dict) |
|
88 """ |
|
89 # step 1: receive the data |
|
90 header = self.__receiveBytes(struct.calcsize(b"!II")) |
|
91 if not header: |
|
92 return None, None |
|
93 |
|
94 length, datahash = struct.unpack(b"!II", header) |
|
95 |
|
96 length = int(length) |
|
97 data = self.__receiveBytes(length) |
|
98 if not data or zlib.adler32(data) & 0xFFFFFFFF != datahash: |
|
99 self.sendJson( |
|
100 "ClientException", |
|
101 { |
|
102 "ExceptionType": "ProtocolError", |
|
103 "ExceptionValue": "The checksum of the data does not match.", |
|
104 "ProtocolData": data.decode("utf8", "backslashreplace"), |
|
105 }, |
|
106 ) |
|
107 return None, None |
82 |
108 |
83 # step 2: decode and convert the data |
109 # step 2: decode and convert the data |
84 line = data.decode("utf8", "backslashreplace") |
110 jsonString = data.decode("utf8", "backslashreplace") |
85 try: |
111 try: |
86 commandDict = json.loads(line.strip()) |
112 commandDict = json.loads(jsonString.strip()) |
87 except (TypeError, ValueError) as err: |
113 except (TypeError, ValueError) as err: |
88 self.sendJson( |
114 self.sendJson( |
89 "ClientException", |
115 "ClientException", |
90 { |
116 { |
91 "ExceptionType": "ProtocolError", |
117 "ExceptionType": "ProtocolError", |
92 "ExceptionValue": str(err), |
118 "ExceptionValue": str(err), |
93 "ProtocolData": line.strip(), |
119 "ProtocolData": jsonString.strip(), |
94 }, |
120 }, |
95 ) |
121 ) |
96 return None, None |
122 return None, None |
97 |
123 |
98 method = commandDict["method"] |
124 method = commandDict["method"] |