Update redis, and implement a custom channel layer to send datetime/decimal objects

This commit is contained in:
Tom Hubrecht 2022-06-29 14:37:28 +02:00
parent 9a7deb5e2a
commit 95e658d05b
3 changed files with 47 additions and 2 deletions

View file

@ -148,7 +148,7 @@ CACHES = {
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"BACKEND": "shared.channels.ChannelLayer",
"CONFIG": {
"hosts": [
(

View file

@ -5,7 +5,7 @@ psycopg2<2.8
# Redis
django-redis-cache==3.0.*
redis~=2.10.6
redis==3.5.*
channels-redis==3.4.*
# ASGI protocol and HTTP server

45
shared/channels.py Normal file
View file

@ -0,0 +1,45 @@
import datetime
import random
from decimal import Decimal
import msgpack
from channels_redis.core import RedisChannelLayer
def encode_kf(obj):
if isinstance(obj, Decimal):
return {"__decimal__": True, "as_str": str(obj)}
elif isinstance(obj, datetime.datetime):
return {"__datetime__": True, "as_str": obj.strftime("%Y%m%dT%H:%M:%S.%f")}
return obj
def decode_kf(obj):
if "__decimal__" in obj:
obj = Decimal(obj["as_str"])
elif "__datetime__" in obj:
obj = datetime.datetime.strptime(obj["as_str"], "%Y%m%dT%H:%M:%S.%f")
return obj
class ChannelLayer(RedisChannelLayer):
def serialize(self, message):
"""Serializes to a byte string."""
value = msgpack.packb(message, default=encode_kf, use_bin_type=True)
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:]
if self.crypter:
message = self.crypter.decrypt(message, self.expiry + 10)
return msgpack.unpackb(message, object_hook=decode_kf, raw=False)