-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmessage.py
124 lines (101 loc) · 4.57 KB
/
message.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
"""websocket 协议消息封装"""
import ujson as json
import ubinascii as binascii
class ProtoVersion(object):
V1 = 0b0001
class MessageType(object):
FULL_CLIENT_REQUEST = 0b0001
AUDIO_ONLY_REQUEST = 0b0010
FULL_SERVER_RESPONSE = 0b1001
AUDIO_ONLY_SERVER_RESPONSE = 0b1011
ERROR_RESPONSE = 0b1111
class MessageTypeSpecificFlags(object):
NONE = 0b0000
AUDIO_ONLY_REQUEST_LAST_PACKAGE = 0b0010
class MessageSerializationMethod(object):
NONE = 0b0000
JSON = 0b0001
class MessageCompression(object):
NONE = 0b0000
GZIP = 0b0001
class Message(object):
def __init__(self, proto_version, header_size, message_type, message_type_specific_flags,
message_serialization_method, message_compression, payload=b""):
"""generate protocol header
Args:
proto_version (int): 0b0001 - version 1 (目前只有该版本)
header_size (int): 0b0001 - header size = 4 (1 x 4)
message_type (int): 0b0001 - 端上发送包含请求参数的 full client request
0b0010 - 端上发送包含音频数据的 audio only request
0b1001 - 服务端下发包含识别结果的 full server response
0b1111 - 服务端处理错误时下发的消息类型(如无效的消息格式,不支持的序列化方法等)
message_type_specific_flags (int): 0b0000 - full client request 或包含非最后一包音频数据的 audio only request 中设置
b0010 - 包含最后一包音频数据的 audio only request 中设置
message_serialization_method (int): 0b0000 - 无序列化
0b0001 - JSON 格式
message_compression (int): 0b0000 - no compression
0b0001 - Gzip 压缩
"""
self.proto_version = proto_version
self.header_size = header_size
self.message_type = message_type
self.message_type_specific_flags = message_type_specific_flags
self.message_serialization_method = message_serialization_method
self.message_compression = message_compression
self.payload = payload
def __str__(self):
s = "proto_version: 0b{:04b}\n" \
"header_size: 0b{:04b}\n" \
"message_type: 0b{:04b}\n" \
"message_type_specific_flags: 0b{:04b}\n" \
"message_serialization_method: 0b{:04b}\n" \
"message_compression: 0b{:04b}\n".format(
self.proto_version,
self.header_size,
self.message_type,
self.message_type_specific_flags,
self.message_serialization_method,
self.message_compression
)
return s
def to_bytes(self):
header_bytes = bytes(
[
(self.proto_version << 4) | self.header_size,
(self.message_type << 4) | self.message_type_specific_flags,
(self.message_serialization_method << 4) | self.message_compression,
0x00
]
)
return header_bytes + self.payload
@classmethod
def from_bytes(cls, raw):
return cls(
proto_version=raw[0] >> 4,
header_size=raw[0] & 0x0F,
message_type=raw[1] >> 4,
message_type_specific_flags=raw[1] & 0x0F,
message_serialization_method=raw[2] >> 4,
message_compression=raw[2] & 0x0F,
payload=raw[(raw[0] & 0x0F) * 4:]
)
def to_hex(self):
return binascii.hexlify(self.to_bytes()).decode()
@classmethod
def from_hex(cls, string):
return cls.from_bytes(binascii.unhexlify(string))
def MessageWrapper(msg):
if msg.message_type == MessageType.FULL_SERVER_RESPONSE:
msg.payload_size = int.from_bytes(msg.payload[:4], "big")
msg.payload = json.loads(msg.payload[4:])
elif msg.message_type == MessageType.ERROR_RESPONSE:
msg.err_code = int.from_bytes(msg.payload[:4], "big")
msg.err_msg_size = int.from_bytes(msg.payload[4:8], "big")
msg.message = json.loads(msg.payload[8:])
elif msg.message_type == MessageType.AUDIO_ONLY_SERVER_RESPONSE:
msg.sequence_number = int.from_bytes(msg.payload[:4], "big")
msg.payload_size = int.from_bytes(msg.payload[4:8], "big")
msg.payload = msg.payload[8:]
else:
raise ValueError("unknow message type: 0b{:04b}".format(msg.message_type))
return msg