dubbo-ssl-python 0.9.0__tar.gz → 0.9.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (23) hide show
  1. {dubbo_ssl_python-0.9.0 → dubbo_ssl_python-0.9.1}/PKG-INFO +4 -4
  2. {dubbo_ssl_python-0.9.0 → dubbo_ssl_python-0.9.1}/README.md +1 -1
  3. dubbo_ssl_python-0.9.1/dubbo_ssl/codec/__init__.py +1 -0
  4. dubbo_ssl_python-0.9.1/dubbo_ssl/codec/decoder.py +468 -0
  5. dubbo_ssl_python-0.9.1/dubbo_ssl/codec/encoder.py +404 -0
  6. dubbo_ssl_python-0.9.1/dubbo_ssl/common/__init__.py +1 -0
  7. dubbo_ssl_python-0.9.1/dubbo_ssl/common/constants.py +41 -0
  8. dubbo_ssl_python-0.9.1/dubbo_ssl/common/exceptions.py +34 -0
  9. dubbo_ssl_python-0.9.1/dubbo_ssl/common/util.py +95 -0
  10. dubbo_ssl_python-0.9.1/dubbo_ssl/connection/__init__.py +2 -0
  11. dubbo_ssl_python-0.9.1/dubbo_ssl/connection/connections.py +409 -0
  12. {dubbo_ssl_python-0.9.0 → dubbo_ssl_python-0.9.1}/dubbo_ssl_python.egg-info/PKG-INFO +4 -4
  13. dubbo_ssl_python-0.9.1/dubbo_ssl_python.egg-info/SOURCES.txt +20 -0
  14. {dubbo_ssl_python-0.9.0 → dubbo_ssl_python-0.9.1}/pyproject.toml +4 -4
  15. dubbo_ssl_python-0.9.0/dubbo_ssl_python.egg-info/SOURCES.txt +0 -11
  16. {dubbo_ssl_python-0.9.0 → dubbo_ssl_python-0.9.1}/LICENSE +0 -0
  17. {dubbo_ssl_python-0.9.0 → dubbo_ssl_python-0.9.1}/dubbo_ssl/__init__.py +0 -0
  18. {dubbo_ssl_python-0.9.0 → dubbo_ssl_python-0.9.1}/dubbo_ssl/client.py +0 -0
  19. {dubbo_ssl_python-0.9.0 → dubbo_ssl_python-0.9.1}/dubbo_ssl_python.egg-info/dependency_links.txt +0 -0
  20. {dubbo_ssl_python-0.9.0 → dubbo_ssl_python-0.9.1}/dubbo_ssl_python.egg-info/requires.txt +0 -0
  21. {dubbo_ssl_python-0.9.0 → dubbo_ssl_python-0.9.1}/dubbo_ssl_python.egg-info/top_level.txt +0 -0
  22. {dubbo_ssl_python-0.9.0 → dubbo_ssl_python-0.9.1}/setup.cfg +0 -0
  23. {dubbo_ssl_python-0.9.0 → dubbo_ssl_python-0.9.1}/tests/test_client.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dubbo-ssl-python
3
- Version: 0.9.0
3
+ Version: 0.9.1
4
4
  Summary: Python client for Apache Dubbo RPC protocol, with Hessian2 serialization and SSL/TLS support.
5
5
  Author-email: gigi wang <gigiwgoo@gmail.com>
6
6
  License: Apache License
@@ -205,8 +205,8 @@ License: Apache License
205
205
  See the License for the specific language governing permissions and
206
206
  limitations under the License.
207
207
 
208
- Project-URL: Homepage, https://github.com/iocoo/dubbo-ssl-python
209
- Project-URL: url, https://github.com/iocoo/dubbo-ssl-python/
208
+ Project-URL: Homepage, https://iocoo.github.io
209
+ Project-URL: Repository, https://github.com/iocoo/dubbo-ssl-python/
210
210
  Classifier: Programming Language :: Python :: 3
211
211
  Classifier: License :: OSI Approved :: Apache Software License
212
212
  Classifier: Operating System :: OS Independent
@@ -224,7 +224,7 @@ Base on https://github.com/apache/dubbo-python2 and https://github.com/huisongya
224
224
  ## Features
225
225
 
226
226
  - Full Hessian2 serialization/deserialization (primitives, objects, lists, maps, dates, null, circular references)
227
- - TCP and SSL/TCP connections with custom CA certificate support
227
+ - TCP and SSL/TLS connections with custom CA certificate support
228
228
  - Zookeeper-based services discovery with weighted load balancing
229
229
  - Connection pooling with automatic heartbeat and reconnection
230
230
  - Support `group` settings for Dubbo, Compatible with Dubbo 2.x
@@ -6,7 +6,7 @@ Base on https://github.com/apache/dubbo-python2 and https://github.com/huisongya
6
6
  ## Features
7
7
 
8
8
  - Full Hessian2 serialization/deserialization (primitives, objects, lists, maps, dates, null, circular references)
9
- - TCP and SSL/TCP connections with custom CA certificate support
9
+ - TCP and SSL/TLS connections with custom CA certificate support
10
10
  - Zookeeper-based services discovery with weighted load balancing
11
11
  - Connection pooling with automatic heartbeat and reconnection
12
12
  - Support `group` settings for Dubbo, Compatible with Dubbo 2.x
@@ -0,0 +1 @@
1
+ # -*- coding: utf-8 -*-
@@ -0,0 +1,468 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ /*
4
+ * Licensed to the Apache Software Foundation (ASF) under one or more
5
+ * contributor license agreements. See the NOTICE file distributed with
6
+ * this work for additional information regarding copyright ownership.
7
+ * The ASF licenses this file to You under the Apache License, Version 2.0
8
+ * (the "License"); you may not use this file except in compliance with
9
+ * the License. You may obtain a copy of the License at
10
+ *
11
+ * http://www.apache.org/licenses/LICENSE-2.0
12
+ *
13
+ * Unless required by applicable law or agreed to in writing, software
14
+ * distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and
17
+ * limitations under the License.
18
+ */
19
+ """
20
+
21
+ from datetime import datetime
22
+ from struct import unpack
23
+
24
+ from dubbo_ssl.common.exceptions import HessianTypeError, DubboException, DubboResponseException
25
+ from dubbo_ssl.common.constants import response_status_message
26
+
27
+ functions = {}
28
+
29
+
30
+ def ranges(*defined_ranges):
31
+ """
32
+ 根据hessian协议,把处理方法交给其定义好的范围
33
+ :param defined_ranges:
34
+ :return:
35
+ """
36
+
37
+ def decorator(func):
38
+ # 遍历所有的范围
39
+ for defined_range in defined_ranges:
40
+ if isinstance(defined_range, (tuple, list)):
41
+ if not len(defined_range) == 2:
42
+ raise ValueError('Invalid range {}'.format(defined_range))
43
+ nums = range(defined_range[0], defined_range[1] + 1)
44
+ for num in nums:
45
+ functions[num] = func
46
+ elif isinstance(defined_range, int):
47
+ functions[defined_range] = func
48
+ else:
49
+ raise ValueError('Defined value {} illegal'.format(defined_ranges))
50
+
51
+ def wrapper(*args, **kwargs):
52
+ return func(*args, **kwargs) # 原始方法正常执行
53
+
54
+ return wrapper
55
+
56
+ return decorator
57
+
58
+
59
+ class Response(object):
60
+ """
61
+ A class for parsing dubbo response body.
62
+ All types can be parsed:
63
+ * byte
64
+ * boolean
65
+ * int
66
+ * long
67
+ * double
68
+ * string
69
+ * object
70
+ * class
71
+ * generic type
72
+ * list
73
+ * map
74
+ * date
75
+ * null
76
+ """
77
+
78
+ def __init__(self, data):
79
+ self.__data = data # data是字节数组
80
+ self.__index = 0
81
+ self.types = []
82
+ self.objects = []
83
+ # 对于一个类来说,有path的地方就应该有field_name
84
+ self.paths = []
85
+ self.field_names = []
86
+
87
+ def get_byte(self):
88
+ """
89
+ 获取到头部的字节数据,只是获取并不移动指针
90
+ :return:
91
+ """
92
+ return self.__data[self.__index]
93
+
94
+ def length(self):
95
+ """
96
+ 当前的字节长度
97
+ :return:
98
+ """
99
+ return len(self.__data) - self.__index
100
+
101
+ def read_byte(self):
102
+ """
103
+ 读取一个字节并向后移动一位指针
104
+ :return:
105
+ """
106
+ if self.__index >= len(self.__data):
107
+ raise ValueError('Index {} bigger than data length {}'.format(self.__index, len(self.__data)))
108
+ value = self.__data[self.__index]
109
+ self.__index += 1
110
+ return value
111
+
112
+ def read_bytes(self, num):
113
+ """
114
+ 读取n个字节并向后移动n位指针
115
+ :param num:
116
+ :return:
117
+ """
118
+ value = self.__data[self.__index:self.__index + num]
119
+ self.__index += num
120
+ return value
121
+
122
+ @ranges(ord('T'), ord('F'))
123
+ def read_boolean(self):
124
+ """
125
+ 读取一个布尔类型
126
+ :return:
127
+ """
128
+ value = self.read_byte()
129
+ if value == ord('T'):
130
+ return True
131
+ elif value == ord('F'):
132
+ return False
133
+ else:
134
+ raise HessianTypeError('illegal boolean value: {0}'.format(value))
135
+
136
+ @ranges((0x80, 0xd7), ord('I'))
137
+ def read_int(self):
138
+ """
139
+ 读取一个整型数据
140
+ :return:
141
+ """
142
+ value = self.read_byte()
143
+ if 0x80 <= value <= 0xbf:
144
+ result = value - 0x90
145
+ elif 0xc0 <= value <= 0xcf:
146
+ i = (value - 0xc8) << 8
147
+ i |= self.read_byte()
148
+ result = i
149
+ elif 0xd0 <= value <= 0xd7:
150
+ i = (value - 0xd4) << 16
151
+ i |= self.read_byte() << 8
152
+ i |= self.read_byte()
153
+ result = i
154
+ else:
155
+ result = unpack('!i', self.read_bytes(4))[0]
156
+ return result
157
+
158
+ @ranges((0x5b, 0x5f), ord('D'))
159
+ def read_double(self):
160
+ """
161
+ 读取一个浮点类型
162
+ :return:
163
+ """
164
+ value = self.read_byte()
165
+ if value == 0x5b:
166
+ result = 0.0
167
+ elif value == 0x5c:
168
+ result = 1.0
169
+ elif value == 0x5d:
170
+ result = float(unpack('!b', self.read_bytes(1))[0])
171
+ elif value == 0x5e:
172
+ result = float(unpack('!h', self.read_bytes(2))[0])
173
+ elif value == 0x5f:
174
+ result = float(unpack('!i', self.read_bytes(4))[0]) * 0.001
175
+ elif value == ord('D'):
176
+ result = float(unpack('!d', self.read_bytes(8))[0])
177
+ else:
178
+ raise HessianTypeError('{0} is not a float'.format(value))
179
+ return result
180
+
181
+ def _read_utf(self, length):
182
+ """
183
+ 读取n个字符
184
+ :param length:
185
+ :return:
186
+ """
187
+ value = u''
188
+ for i in range(length):
189
+ ch = self.read_byte()
190
+ if ch < 0x80:
191
+ value += chr(ch)
192
+ elif (ch & 0xe0) == 0xc0:
193
+ ch1 = self.read_byte()
194
+ value += chr(((ch & 0x1f) << 6) + (ch1 & 0x3f))
195
+ elif (ch & 0xf0) == 0xe0:
196
+ ch1 = self.read_byte()
197
+ ch2 = self.read_byte()
198
+ value += chr(((ch & 0x0f) << 12) + ((ch1 & 0x3f) << 6) + (ch2 & 0x3f))
199
+ else:
200
+ raise ValueError('Can\'t parse utf-8 char {}'.format(ch))
201
+ return value # 将unicode转化为str类型
202
+
203
+ @ranges((0x00, 0x1f), (0x30, 0x33), 0x52, ord('S'))
204
+ def read_string(self):
205
+ """
206
+ 读取一个字符串
207
+ :return:
208
+ """
209
+ value = self.read_byte()
210
+ string = ''
211
+ while value == 'R':
212
+ length = unpack('!h', self.read_bytes(2))[0]
213
+ string += self._read_utf(length)
214
+ value = self.read_byte()
215
+
216
+ if value == ord('S'):
217
+ length = unpack('!h', self.read_bytes(2))[0]
218
+ elif 0x00 <= value <= 0x1f:
219
+ length = value
220
+ else:
221
+ length = (value - 0x30) << 8 | self.read_byte()
222
+
223
+ string += self._read_utf(length)
224
+ return string
225
+
226
+ @ranges((0x60, 0x6f), ord('O'))
227
+ def read_object(self):
228
+ """
229
+ 读取一个对象
230
+ :return:
231
+ """
232
+ result = {}
233
+ self.objects.append(result)
234
+ value = self.read_byte()
235
+ if 0x60 <= value <= 0x6f:
236
+ ref = value - 0x60
237
+ else:
238
+ ref = self.read_int()
239
+ field_names = self.field_names[ref]
240
+ for field_name in field_names:
241
+ field_value = self.read_next()
242
+ result[field_name] = field_value
243
+
244
+ path = self.paths[ref]
245
+ if path == 'java.math.BigDecimal':
246
+ result = float(result['value']) or 0
247
+ self.objects[-1] = result
248
+ elif path == 'java.math.BigInteger':
249
+ result = int(result['value'])
250
+ self.objects[-1] = result
251
+
252
+ return result
253
+
254
+ @ranges(ord('C'))
255
+ def read_class(self):
256
+ """
257
+ 读取一个类的类属性,主要是类名和类中的变量名
258
+ :return:
259
+ """
260
+ self.read_byte()
261
+ path = self.read_string()
262
+ self.paths.append(path)
263
+
264
+ field_length = self.read_int()
265
+ field_names = []
266
+ for i in range(field_length):
267
+ field_names.append(self.read_string())
268
+ self.field_names.append(field_names)
269
+ return self.read_object()
270
+
271
+ def read_type(self):
272
+ """
273
+ type代表了list或者map中泛型的类型,在Python中此类型无意义
274
+ :return:
275
+ """
276
+ _type = self.read_next()
277
+ if isinstance(_type, int):
278
+ return self.types[_type]
279
+ elif isinstance(_type, str):
280
+ self.types.append(_type)
281
+ return _type
282
+ else:
283
+ raise HessianTypeError('Unknown _type type for value: {0}'.format(_type))
284
+
285
+ @ranges((0x70, 0x7f), (0x55, 0x58))
286
+ def read_list(self):
287
+ """
288
+ 读取一个列表
289
+ :return:
290
+ """
291
+ result = []
292
+ self.objects.append(result)
293
+ value = self.read_byte()
294
+ # 固定长度的有类型短小列表
295
+ if 0x70 <= value <= 0x77:
296
+ _type = self.read_type() # type对于Python来说没有用处
297
+ length = value - 0x70
298
+ for i in range(length):
299
+ result.append(self.read_next())
300
+ # 固定长度的无类型短小列表
301
+ elif 0x78 <= value <= 0x7f:
302
+ length = value - 0x78
303
+ for i in range(length):
304
+ result.append(self.read_next())
305
+ # 固定长度的有类型列表
306
+ elif value == 0x56:
307
+ _type = self.read_type()
308
+ length = self.read_int()
309
+ for i in range(length):
310
+ result.append(self.read_next())
311
+ # 固定长度的无类型列表
312
+ elif value == 0x58:
313
+ length = self.read_int()
314
+ for i in range(length):
315
+ result.append(self.read_next())
316
+ # 可变长度的有类型列表
317
+ elif value == 0x55:
318
+ _type = self.read_type()
319
+ # 可变长度的无类型列表
320
+ elif value == 0x57:
321
+ pass
322
+ return result
323
+
324
+ @ranges((0xd8, 0xff), (0x38, 0x3f), 0x59, ord('L'))
325
+ def read_long(self):
326
+ """
327
+ 读取一个long类型的数字
328
+ :return:
329
+ """
330
+ value = self.read_byte()
331
+ if 0xd8 <= value <= 0xef:
332
+ result = value - 0xe0
333
+ elif 0xf0 <= value <= 0xff:
334
+ result = ((value - 0xf8) << 8) | self.read_byte()
335
+ elif 0x38 <= value <= 0x3f:
336
+ i = (value - 0x3c) << 16
337
+ i |= self.read_byte() << 8
338
+ i |= self.read_byte()
339
+ result = i
340
+ elif value == 0x59:
341
+ result = unpack('!i', self.read_bytes(4))[0]
342
+ elif value == ord('L'):
343
+ result = unpack('!q', self.read_bytes(8))[0]
344
+ else:
345
+ raise HessianTypeError('{0} is not long type'.format(value))
346
+ return result
347
+
348
+ @ranges(ord('N'))
349
+ def read_null(self):
350
+ """
351
+ 读取一个None
352
+ :return:
353
+ """
354
+ value = self.read_byte()
355
+ if value == ord('N'):
356
+ return None
357
+ else:
358
+ raise HessianTypeError('{0} is not null'.format(value))
359
+
360
+ @ranges(ord('H'), ord('M'))
361
+ def read_map(self):
362
+ """
363
+ 读取一个dict
364
+ :return:
365
+ """
366
+ value = self.read_byte()
367
+
368
+ if value == ord('M') or value == ord('H'):
369
+ result = {}
370
+ self.objects.append(result)
371
+ while self.get_byte() != ord('Z'):
372
+ key = self.read_next()
373
+ value = self.read_next()
374
+ result[key] = value
375
+ self.read_byte() # 干掉最后一个'Z'字符
376
+ return result
377
+ else:
378
+ raise HessianTypeError('{0} is not a map.'.format(value))
379
+
380
+ @ranges(0x4a, 0x4b)
381
+ def read_date(self):
382
+ """
383
+ 读取一个date类型的值
384
+ :return:
385
+ """
386
+ value = self.read_byte()
387
+ if value == 0x4a:
388
+ timestamp = unpack('!q', self.read_bytes(8))[0]
389
+ elif value == 0x4b:
390
+ timestamp = unpack('!i', self.read_bytes(4))[0]
391
+ timestamp *= 60000
392
+ else:
393
+ raise HessianTypeError('{0} is not date type'.format(value))
394
+ return datetime.fromtimestamp(timestamp / 1e3).strftime("%Y-%m-%dT%H:%M:%S.%f+0800")
395
+
396
+ @ranges(0x51)
397
+ def read_ref(self):
398
+ """
399
+ 读取一个已知的object/list/map
400
+ :return:
401
+ """
402
+ self.read_byte() # 干掉0x51
403
+ ref_id = self.read_int()
404
+ return self.objects[ref_id]
405
+
406
+ def read_next(self):
407
+ """
408
+ 读取下一个变量,自动识别变量类型
409
+ :return:
410
+ """
411
+ data_type = self.get_byte()
412
+ func = functions[data_type]
413
+ return func(self)
414
+
415
+ def read_error(self):
416
+ """
417
+ 解析Java的错误信息,因为需要知道错误的类型,所以需要单独处理
418
+ :return:
419
+ """
420
+ self.read_byte()
421
+ error_type = self.read_string()
422
+ self.paths.append(error_type)
423
+
424
+ field_length = self.read_int()
425
+ field_names = []
426
+ for i in range(field_length):
427
+ field_names.append(self.read_string())
428
+ self.field_names.append(field_names)
429
+
430
+ error = self.read_object()
431
+ error['cause'] = error_type
432
+ return error
433
+
434
+ def __repr__(self):
435
+ return str(self.__data)
436
+
437
+
438
+ def parse_response_head(response_head):
439
+ """
440
+ 对响应头部的字节做解析
441
+ :param response_head:
442
+ :return:
443
+ """
444
+ # Magic number
445
+ if not (response_head[0] == 0xda and response_head[1] == 0xbb):
446
+ raise DubboException('illegal response')
447
+
448
+ # 第三位为1表示这是一个心跳包
449
+ if response_head[2] & 0x20 == 0x20:
450
+ if response_head[2] & 0x80 == 0x80:
451
+ # 第一位为1,一个心跳请求的包
452
+ heartbeat = 2
453
+ else:
454
+ # 第一位为0,一个心跳响应的包
455
+ heartbeat = 1
456
+ response_status = response_head[3]
457
+ if response_status != 20:
458
+ raise DubboException(response_status_message[response_status])
459
+ else:
460
+ heartbeat = 0
461
+ response_status = response_head[3]
462
+ if response_status != 20:
463
+ raise DubboResponseException(response_status_message[response_status])
464
+ return heartbeat, unpack('!i', response_head[12:])[0]
465
+
466
+
467
+ if __name__ == '__main__':
468
+ pass