Skip to content

Commit

Permalink
Added send_packet() method
Browse files Browse the repository at this point in the history
  • Loading branch information
miguelgrinberg committed Aug 31, 2023
1 parent bb87ec6 commit 48451a3
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 3 deletions.
12 changes: 11 additions & 1 deletion src/engineio/asyncio_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,16 @@ async def send(self, sid, data):
``str``, ``bytes``, ``list`` or ``dict``. If a ``list``
or ``dict``, the data will be serialized as JSON.
Note: this method is a coroutine.
"""
await self.send_packet(sid, packet.Packet(packet.MESSAGE, data=data))

async def send_packet(self, sid, pkt):
"""Send a raw packet to a client.
:param sid: The session id of the recipient client.
:param pkt: The packet to send to the client.
Note: this method is a coroutine.
"""
try:
Expand All @@ -95,7 +105,7 @@ async def send(self, sid, data):
# the socket is not available
self.logger.warning('Cannot send to sid %s', sid)
return
await socket.send(packet.Packet(packet.MESSAGE, data=data))
await socket.send(pkt)

async def get_session(self, sid):
"""Return the user session for a client.
Expand Down
10 changes: 9 additions & 1 deletion src/engineio/packet.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class Packet(object):
def __init__(self, packet_type=NOOP, data=None, encoded_packet=None):
self.packet_type = packet_type
self.data = data
self.encode_cache = None
if isinstance(data, str):
self.binary = False
elif isinstance(data, binary_types):
Expand All @@ -27,7 +28,13 @@ def __init__(self, packet_type=NOOP, data=None, encoded_packet=None):
self.decode(encoded_packet)

def encode(self, b64=False):
"""Encode the packet for transmission."""
"""Encode the packet for transmission.
Note: as a performance optimization, subsequent calls to this method
will return a cached encoded packet, even if the data has changed.
"""
if self.encode_cache:
return self.encode_cache
if self.binary:
if b64:
encoded_packet = 'b' + base64.b64encode(self.data).decode(
Expand All @@ -43,6 +50,7 @@ def encode(self, b64=False):
separators=(',', ':'))
elif self.data is not None:
encoded_packet += str(self.data)
self.encode_cache = encoded_packet
return encoded_packet

def decode(self, encoded_packet):
Expand Down
10 changes: 9 additions & 1 deletion src/engineio/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,13 +224,21 @@ def send(self, sid, data):
``str``, ``bytes``, ``list`` or ``dict``. If a ``list``
or ``dict``, the data will be serialized as JSON.
"""
self.send_packet(sid, packet.Packet(packet.MESSAGE, data=data))

def send_packet(self, sid, pkt):
"""Send a raw packet to a client.
:param sid: The session id of the recipient client.
:param pkt: The packet to send to the client.
"""
try:
socket = self._get_socket(sid)
except KeyError:
# the socket is not available
self.logger.warning('Cannot send to sid %s', sid)
return
socket.send(packet.Packet(packet.MESSAGE, data=data))
socket.send(pkt)

def get_session(self, sid):
"""Return the user session for a client.
Expand Down
8 changes: 8 additions & 0 deletions tests/common/test_packet.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,11 @@ def test_binary_non_message_packet(self):
def test_decode_invalid_empty_text_packet(self):
with pytest.raises(ValueError):
packet.Packet(encoded_packet='')

def test_encode_cache(self):
pkt = packet.Packet(packet.MESSAGE, data=123)
assert pkt.encode() == '4123'
pkt.data = 456
assert pkt.encode() == '4123'
pkt.encode_cache = None
assert pkt.encode() == '4456'

0 comments on commit 48451a3

Please sign in to comment.