Browse Source

Allow application to provide a custom JSON encoder/decoder.

pull/5/head
Miguel Grinberg 10 years ago
parent
commit
f396732088
  1. 9
      socketio/packet.py
  2. 9
      socketio/server.py
  3. 31
      tests/test_server.py

9
socketio/packet.py

@ -1,5 +1,5 @@
import functools import functools
import json import json as _json
import six import six
@ -11,6 +11,9 @@ packet_names = ['CONNECT', 'DISCONNECT', 'EVENT', 'ACK', 'ERROR',
class Packet(object): class Packet(object):
"""Socket.IO packet.""" """Socket.IO packet."""
json = _json
def __init__(self, packet_type=EVENT, data=None, namespace=None, id=None, def __init__(self, packet_type=EVENT, data=None, namespace=None, id=None,
binary=None, encoded_packet=None): binary=None, encoded_packet=None):
self.packet_type = packet_type self.packet_type = packet_type
@ -54,7 +57,7 @@ class Packet(object):
if data is not None: if data is not None:
if needs_comma: if needs_comma:
encoded_packet += ',' encoded_packet += ','
encoded_packet += json.dumps(data, separators=(',', ':')) encoded_packet += self.json.dumps(data, separators=(',', ':'))
if attachments is not None: if attachments is not None:
encoded_packet = [encoded_packet] + attachments encoded_packet = [encoded_packet] + attachments
return encoded_packet return encoded_packet
@ -90,7 +93,7 @@ class Packet(object):
self.id = self.id * 10 + int(ep[0]) self.id = self.id * 10 + int(ep[0])
ep = ep[1:] ep = ep[1:]
if ep: if ep:
self.data = json.loads(ep) self.data = self.json.loads(ep)
return attachment_count return attachment_count
def reconstruct_binary(self, attachments): def reconstruct_binary(self, attachments):

9
socketio/server.py

@ -28,6 +28,10 @@ class Server(object):
``bytes`` values are treated as binary. This option has no ``bytes`` values are treated as binary. This option has no
effect on Python 3, where text and binary payloads are effect on Python 3, where text and binary payloads are
always automatically discovered. always automatically discovered.
:param json: An alternative json module to use for encoding and decoding
packets. Custom json modules must have ``dumps`` and ``loads``
functions that are compatible with the standard library
versions.
:param kwargs: Connection parameters for the underlying Engine.IO server. :param kwargs: Connection parameters for the underlying Engine.IO server.
The Engine.IO configuration supports the following settings: The Engine.IO configuration supports the following settings:
@ -60,7 +64,7 @@ class Server(object):
``False``. ``False``.
""" """
def __init__(self, client_manager_class=None, logger=False, binary=False, def __init__(self, client_manager_class=None, logger=False, binary=False,
**kwargs): json=None, **kwargs):
if client_manager_class is None: if client_manager_class is None:
client_manager_class = base_manager.BaseManager client_manager_class = base_manager.BaseManager
self.manager = client_manager_class(self) self.manager = client_manager_class(self)
@ -68,6 +72,9 @@ class Server(object):
engineio_logger = engineio_options.pop('engineio_logger', None) engineio_logger = engineio_options.pop('engineio_logger', None)
if engineio_logger is not None: if engineio_logger is not None:
engineio_options['logger'] = engineio_logger engineio_options['logger'] = engineio_logger
if json is not None:
packet.Packet.json = json
engineio_options['json'] = json
self.eio = engineio.Server(**engineio_options) self.eio = engineio.Server(**engineio_options)
self.eio.on('connect', self._handle_eio_connect) self.eio.on('connect', self._handle_eio_connect)
self.eio.on('message', self._handle_eio_message) self.eio.on('message', self._handle_eio_message)

31
tests/test_server.py

@ -1,3 +1,4 @@
import json
import logging import logging
import unittest import unittest
@ -7,11 +8,16 @@ if six.PY3:
else: else:
import mock import mock
from socketio import packet
from socketio import server from socketio import server
@mock.patch('engineio.Server') @mock.patch('engineio.Server')
class TestServer(unittest.TestCase): class TestServer(unittest.TestCase):
def tearDown(self):
# restore JSON encoder, in case a test changed it
packet.Packet.json = json
def test_create(self, eio): def test_create(self, eio):
mgr = mock.MagicMock() mgr = mock.MagicMock()
s = server.Server(mgr, binary=True, foo='bar') s = server.Server(mgr, binary=True, foo='bar')
@ -374,3 +380,28 @@ class TestServer(unittest.TestCase):
def test_engineio_logger(self, eio): def test_engineio_logger(self, eio):
server.Server(engineio_logger='foo') server.Server(engineio_logger='foo')
eio.assert_called_once_with(**{'logger': 'foo'}) eio.assert_called_once_with(**{'logger': 'foo'})
def test_custom_json(self, eio):
# Warning: this test cannot run in parallel with other tests, as it
# changes the JSON encoding/decoding functions
class CustomJSON(object):
@staticmethod
def dumps(*args, **kwargs):
return '*** encoded ***'
@staticmethod
def loads(*args, **kwargs):
return '+++ decoded +++'
server.Server(json=CustomJSON)
eio.assert_called_once_with(**{'json': CustomJSON})
pkt = packet.Packet(packet_type=packet.EVENT,
data={six.text_type('foo'): six.text_type('bar')})
self.assertEqual(pkt.encode(), '2*** encoded ***')
pkt2 = packet.Packet(encoded_packet=pkt.encode())
self.assertEqual(pkt2.data, '+++ decoded +++')
# restore the default JSON module
packet.Packet.json = json

Loading…
Cancel
Save