You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

93 lines
3.4KB

  1. import base64
  2. import json as _json
  3. import six
  4. (OPEN, CLOSE, PING, PONG, MESSAGE, UPGRADE, NOOP) = (0, 1, 2, 3, 4, 5, 6)
  5. packet_names = ['OPEN', 'CLOSE', 'PING', 'PONG', 'MESSAGE', 'UPGRADE', 'NOOP']
  6. binary_types = (six.binary_type, bytearray)
  7. class Packet(object):
  8. """Engine.IO packet."""
  9. json = _json
  10. def __init__(self, packet_type=NOOP, data=None, binary=None,
  11. encoded_packet=None):
  12. self.packet_type = packet_type
  13. self.data = data
  14. if binary is not None:
  15. self.binary = binary
  16. elif isinstance(data, six.text_type):
  17. self.binary = False
  18. elif isinstance(data, binary_types):
  19. self.binary = True
  20. else:
  21. self.binary = False
  22. if encoded_packet:
  23. self.decode(encoded_packet)
  24. def encode(self, b64=False, always_bytes=True):
  25. """Encode the packet for transmission."""
  26. if self.binary and not b64:
  27. encoded_packet = six.int2byte(self.packet_type)
  28. else:
  29. encoded_packet = six.text_type(self.packet_type)
  30. if self.binary and b64:
  31. encoded_packet = 'b' + encoded_packet
  32. if self.binary:
  33. if b64:
  34. encoded_packet += base64.b64encode(self.data).decode('utf-8')
  35. else:
  36. encoded_packet += self.data
  37. elif isinstance(self.data, six.string_types):
  38. encoded_packet += self.data
  39. elif isinstance(self.data, dict) or isinstance(self.data, list):
  40. encoded_packet += self.json.dumps(self.data,
  41. separators=(',', ':'))
  42. elif self.data is not None:
  43. encoded_packet += str(self.data)
  44. if always_bytes and not isinstance(encoded_packet, binary_types):
  45. encoded_packet = encoded_packet.encode('utf-8')
  46. return encoded_packet
  47. def decode(self, encoded_packet):
  48. """Decode a transmitted package."""
  49. b64 = False
  50. if not isinstance(encoded_packet, binary_types):
  51. encoded_packet = encoded_packet.encode('utf-8')
  52. elif not isinstance(encoded_packet, bytes):
  53. encoded_packet = bytes(encoded_packet)
  54. self.packet_type = six.byte2int(encoded_packet[0:1])
  55. if self.packet_type == 98: # 'b' --> binary base64 encoded packet
  56. self.binary = True
  57. encoded_packet = encoded_packet[1:]
  58. self.packet_type = six.byte2int(encoded_packet[0:1])
  59. self.packet_type -= 48
  60. b64 = True
  61. elif self.packet_type >= 48:
  62. self.packet_type -= 48
  63. self.binary = False
  64. else:
  65. self.binary = True
  66. self.data = None
  67. if len(encoded_packet) > 1:
  68. if self.binary:
  69. if b64:
  70. self.data = base64.b64decode(encoded_packet[1:])
  71. else:
  72. self.data = encoded_packet[1:]
  73. else:
  74. try:
  75. self.data = self.json.loads(
  76. encoded_packet[1:].decode('utf-8'))
  77. if isinstance(self.data, int):
  78. # do not allow integer payloads, see
  79. # github.com/miguelgrinberg/python-engineio/issues/75
  80. # for background on this decision
  81. raise ValueError
  82. except ValueError:
  83. self.data = encoded_packet[1:].decode('utf-8')