protocol.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. import gzip
  2. import json
  3. PROTOCOL_VERSION = 0b0001
  4. DEFAULT_HEADER_SIZE = 0b0001
  5. PROTOCOL_VERSION_BITS = 4
  6. HEADER_BITS = 4
  7. MESSAGE_TYPE_BITS = 4
  8. MESSAGE_TYPE_SPECIFIC_FLAGS_BITS = 4
  9. MESSAGE_SERIALIZATION_BITS = 4
  10. MESSAGE_COMPRESSION_BITS = 4
  11. RESERVED_BITS = 8
  12. # Message Type:
  13. CLIENT_FULL_REQUEST = 0b0001
  14. CLIENT_AUDIO_ONLY_REQUEST = 0b0010
  15. SERVER_FULL_RESPONSE = 0b1001
  16. SERVER_ACK = 0b1011
  17. SERVER_ERROR_RESPONSE = 0b1111
  18. # Message Type Specific Flags
  19. NO_SEQUENCE = 0b0000 # no check sequence
  20. POS_SEQUENCE = 0b0001
  21. NEG_SEQUENCE = 0b0010
  22. NEG_SEQUENCE_1 = 0b0011
  23. MSG_WITH_EVENT = 0b0100
  24. # Message Serialization
  25. NO_SERIALIZATION = 0b0000
  26. JSON = 0b0001
  27. THRIFT = 0b0011
  28. CUSTOM_TYPE = 0b1111
  29. # Message Compression
  30. NO_COMPRESSION = 0b0000
  31. GZIP = 0b0001
  32. CUSTOM_COMPRESSION = 0b1111
  33. def generate_header(
  34. version=PROTOCOL_VERSION,
  35. message_type=CLIENT_FULL_REQUEST,
  36. message_type_specific_flags=MSG_WITH_EVENT,
  37. serial_method=JSON,
  38. compression_type=GZIP,
  39. reserved_data=0x00,
  40. extension_header=bytes()
  41. ):
  42. """
  43. protocol_version(4 bits), header_size(4 bits),
  44. message_type(4 bits), message_type_specific_flags(4 bits)
  45. serialization_method(4 bits) message_compression(4 bits)
  46. reserved (8bits) 保留字段
  47. header_extensions 扩展头(大小等于 8 * 4 * (header_size - 1) )
  48. """
  49. header = bytearray()
  50. header_size = int(len(extension_header) / 4) + 1
  51. header.append((version << 4) | header_size)
  52. header.append((message_type << 4) | message_type_specific_flags)
  53. header.append((serial_method << 4) | compression_type)
  54. header.append(reserved_data)
  55. header.extend(extension_header)
  56. return header
  57. def parse_response(res):
  58. """
  59. - header
  60. - (4bytes)header
  61. - (4bits)version(v1) + (4bits)header_size
  62. - (4bits)messageType + (4bits)messageTypeFlags
  63. -- 0001 CompleteClient | -- 0001 hasSequence
  64. -- 0010 audioonly | -- 0010 isTailPacket
  65. | -- 0100 hasEvent
  66. - (4bits)payloadFormat + (4bits)compression
  67. - (8bits) reserve
  68. - payload
  69. - [optional 4 bytes] event
  70. - [optional] session ID
  71. -- (4 bytes)session ID len
  72. -- session ID data
  73. - (4 bytes)data len
  74. - data
  75. """
  76. if isinstance(res, str):
  77. return {}
  78. protocol_version = res[0] >> 4
  79. header_size = res[0] & 0x0f
  80. message_type = res[1] >> 4
  81. message_type_specific_flags = res[1] & 0x0f
  82. serialization_method = res[2] >> 4
  83. message_compression = res[2] & 0x0f
  84. reserved = res[3]
  85. header_extensions = res[4:header_size * 4]
  86. payload = res[header_size * 4:]
  87. result = {}
  88. payload_msg = None
  89. payload_size = 0
  90. start = 0
  91. if message_type == SERVER_FULL_RESPONSE or message_type == SERVER_ACK:
  92. result['message_type'] = 'SERVER_FULL_RESPONSE'
  93. if message_type == SERVER_ACK:
  94. result['message_type'] = 'SERVER_ACK'
  95. if message_type_specific_flags & NEG_SEQUENCE > 0:
  96. result['seq'] = int.from_bytes(payload[:4], "big", signed=False)
  97. start += 4
  98. if message_type_specific_flags & MSG_WITH_EVENT > 0:
  99. result['event'] = int.from_bytes(payload[:4], "big", signed=False)
  100. start += 4
  101. payload = payload[start:]
  102. session_id_size = int.from_bytes(payload[:4], "big", signed=True)
  103. session_id = payload[4:session_id_size+4]
  104. result['session_id'] = str(session_id)
  105. payload = payload[4 + session_id_size:]
  106. payload_size = int.from_bytes(payload[:4], "big", signed=False)
  107. payload_msg = payload[4:]
  108. elif message_type == SERVER_ERROR_RESPONSE:
  109. code = int.from_bytes(payload[:4], "big", signed=False)
  110. result['code'] = code
  111. payload_size = int.from_bytes(payload[4:8], "big", signed=False)
  112. payload_msg = payload[8:]
  113. if payload_msg is None:
  114. return result
  115. if message_compression == GZIP:
  116. payload_msg = gzip.decompress(payload_msg)
  117. if serialization_method == JSON:
  118. payload_msg = json.loads(str(payload_msg, "utf-8"))
  119. elif serialization_method != NO_SERIALIZATION:
  120. payload_msg = str(payload_msg, "utf-8")
  121. result['payload_msg'] = payload_msg
  122. result['payload_size'] = payload_size
  123. return result