|
|
@ -29,7 +29,7 @@ class Packet: |
|
|
|
self.namespace = namespace |
|
|
|
self.id = id |
|
|
|
if self.uses_binary_events and \ |
|
|
|
(binary or (binary is None and self._data_is_binary( |
|
|
|
(binary or (binary is None and self.data_is_binary( |
|
|
|
self.data))): |
|
|
|
if self.packet_type == EVENT: |
|
|
|
self.packet_type = BINARY_EVENT |
|
|
@ -51,7 +51,7 @@ class Packet: |
|
|
|
""" |
|
|
|
encoded_packet = str(self.packet_type) |
|
|
|
if self.packet_type == BINARY_EVENT or self.packet_type == BINARY_ACK: |
|
|
|
data, attachments = self._deconstruct_binary(self.data) |
|
|
|
data, attachments = self.deconstruct_binary(self.data) |
|
|
|
encoded_packet += str(len(attachments)) + '-' |
|
|
|
else: |
|
|
|
data = self.data |
|
|
@ -119,61 +119,65 @@ class Packet: |
|
|
|
raise ValueError('Unexpected binary attachment') |
|
|
|
self.attachments.append(attachment) |
|
|
|
if self.attachment_count == len(self.attachments): |
|
|
|
self.reconstruct_binary(self.attachments) |
|
|
|
self.data = self.reconstruct_binary(self.data, self.attachments) |
|
|
|
return True |
|
|
|
return False |
|
|
|
|
|
|
|
def reconstruct_binary(self, attachments): |
|
|
|
@classmethod |
|
|
|
def reconstruct_binary(cls, data, attachments): |
|
|
|
"""Reconstruct a decoded packet using the given list of binary |
|
|
|
attachments. |
|
|
|
""" |
|
|
|
self.data = self._reconstruct_binary_internal(self.data, |
|
|
|
self.attachments) |
|
|
|
return cls._reconstruct_binary_internal(data, attachments) |
|
|
|
|
|
|
|
def _reconstruct_binary_internal(self, data, attachments): |
|
|
|
@classmethod |
|
|
|
def _reconstruct_binary_internal(cls, data, attachments): |
|
|
|
if isinstance(data, list): |
|
|
|
return [self._reconstruct_binary_internal(item, attachments) |
|
|
|
return [cls._reconstruct_binary_internal(item, attachments) |
|
|
|
for item in data] |
|
|
|
elif isinstance(data, dict): |
|
|
|
if data.get('_placeholder') and 'num' in data: |
|
|
|
return attachments[data['num']] |
|
|
|
else: |
|
|
|
return {key: self._reconstruct_binary_internal(value, |
|
|
|
attachments) |
|
|
|
return {key: cls._reconstruct_binary_internal(value, |
|
|
|
attachments) |
|
|
|
for key, value in data.items()} |
|
|
|
else: |
|
|
|
return data |
|
|
|
|
|
|
|
def _deconstruct_binary(self, data): |
|
|
|
@classmethod |
|
|
|
def deconstruct_binary(cls, data): |
|
|
|
"""Extract binary components in the packet.""" |
|
|
|
attachments = [] |
|
|
|
data = self._deconstruct_binary_internal(data, attachments) |
|
|
|
data = cls._deconstruct_binary_internal(data, attachments) |
|
|
|
return data, attachments |
|
|
|
|
|
|
|
def _deconstruct_binary_internal(self, data, attachments): |
|
|
|
@classmethod |
|
|
|
def _deconstruct_binary_internal(cls, data, attachments): |
|
|
|
if isinstance(data, bytes): |
|
|
|
attachments.append(data) |
|
|
|
return {'_placeholder': True, 'num': len(attachments) - 1} |
|
|
|
elif isinstance(data, list): |
|
|
|
return [self._deconstruct_binary_internal(item, attachments) |
|
|
|
return [cls._deconstruct_binary_internal(item, attachments) |
|
|
|
for item in data] |
|
|
|
elif isinstance(data, dict): |
|
|
|
return {key: self._deconstruct_binary_internal(value, attachments) |
|
|
|
return {key: cls._deconstruct_binary_internal(value, attachments) |
|
|
|
for key, value in data.items()} |
|
|
|
else: |
|
|
|
return data |
|
|
|
|
|
|
|
def _data_is_binary(self, data): |
|
|
|
@classmethod |
|
|
|
def data_is_binary(cls, data): |
|
|
|
"""Check if the data contains binary components.""" |
|
|
|
if isinstance(data, bytes): |
|
|
|
return True |
|
|
|
elif isinstance(data, list): |
|
|
|
return functools.reduce( |
|
|
|
lambda a, b: a or b, [self._data_is_binary(item) |
|
|
|
lambda a, b: a or b, [cls.data_is_binary(item) |
|
|
|
for item in data], False) |
|
|
|
elif isinstance(data, dict): |
|
|
|
return functools.reduce( |
|
|
|
lambda a, b: a or b, [self._data_is_binary(item) |
|
|
|
lambda a, b: a or b, [cls.data_is_binary(item) |
|
|
|
for item in data.values()], |
|
|
|
False) |
|
|
|
else: |
|
|
|