-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨(back) override channel_redis channel layer
The channel layer provided by channel_redis use msgpack to serialize and deserialize messages. We have a problem when a video is serialized. It is impossible then to deserialize it because in the urls the resolution can be used as key and those keys are integer. Msgpack is unable to deserialize this kind of key. As suggested in the issue[1] open on channel_redis git repository we implement our own serialize and deserialize methods. 1: django/channels_redis#287
- Loading branch information
Showing
3 changed files
with
68 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
"""Layers used by django channels""" | ||
import json | ||
import random | ||
|
||
from django.core.serializers.json import DjangoJSONEncoder | ||
|
||
from channels_redis.core import RedisChannelLayer | ||
|
||
|
||
class JsonRedisChannelLayer(RedisChannelLayer): | ||
"""Use json to serialize and deserialize messages.""" | ||
|
||
def serialize(self, message): | ||
""" | ||
Serializes message in json. | ||
""" | ||
value = bytes(json.dumps(message, cls=DjangoJSONEncoder), encoding="utf-8") | ||
if self.crypter: | ||
value = self.crypter.encrypt(value) | ||
|
||
# As we use an sorted set to expire messages we need to guarantee uniqueness, | ||
# with 12 bytes. | ||
random_prefix = random.getrandbits(8 * 12).to_bytes(12, "big") | ||
return random_prefix + value | ||
|
||
def deserialize(self, message): | ||
""" | ||
Deserializes from a byte string. | ||
""" | ||
# Removes the random prefix | ||
message = message[12:] | ||
message = message.decode("utf-8") | ||
|
||
if self.crypter: | ||
message = self.crypter.decrypt(message, self.expiry + 10) | ||
return json.loads(message) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
"""Test marsha layers use by django channels.""" | ||
from django.test import TestCase | ||
|
||
from marsha.websocket.layers import JsonRedisChannelLayer | ||
|
||
|
||
class JsonRedisChannelLayerTest(TestCase): | ||
"""Test serialize and deserialize.""" | ||
|
||
def test_serialize_message(self): | ||
""" | ||
Test default serialization method | ||
""" | ||
message = {"a": True, "b": None, "c": {"d": []}} | ||
channel_layer = JsonRedisChannelLayer() | ||
serialized = channel_layer.serialize(message) | ||
self.assertIsInstance(serialized, bytes) | ||
self.assertEqual(serialized[12:], b'{"a": true, "b": null, "c": {"d": []}}') | ||
|
||
def test_deserialize_message(self): | ||
""" | ||
Test default deserialization method | ||
""" | ||
message = ( | ||
b'[\x85\xf8\xdeY\xe5\xa3}is\x0f3{"a": true, "b": null, "c": {"d": []}}' | ||
) | ||
channel_layer = JsonRedisChannelLayer() | ||
deserialized = channel_layer.deserialize(message) | ||
|
||
self.assertIsInstance(deserialized, dict) | ||
self.assertEqual(deserialized, {"a": True, "b": None, "c": {"d": []}}) |