Refactored sdp serializers
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
import json
|
||||
import pickle
|
||||
import datetime
|
||||
import struct
|
||||
import io
|
||||
|
||||
|
||||
def json_default_converter(o):
|
||||
"""
|
||||
Default formatter for json
|
||||
It's used when the json serializer does not know
|
||||
how to serialise a type
|
||||
:param o:
|
||||
:return:
|
||||
"""
|
||||
if isinstance(o, (datetime.date, datetime.datetime)):
|
||||
return o.isoformat()
|
||||
|
||||
|
||||
class Serializer:
|
||||
HEADER_FORMAT = "cH"
|
||||
|
||||
def __init__(self):
|
||||
self._cache = []
|
||||
|
||||
# add builtin serializers
|
||||
self._cache.append(EventSerializer())
|
||||
self._cache.append(PickleSerializer())
|
||||
|
||||
def register(self, serializer):
|
||||
"""
|
||||
Register the list of all know serializers
|
||||
:param serializer:
|
||||
:return:
|
||||
"""
|
||||
self._cache.append(serializer)
|
||||
|
||||
def serialize(self, obj):
|
||||
"""
|
||||
Get the stream representation of an object
|
||||
:param obj:
|
||||
:return:
|
||||
"""
|
||||
serializers = [s for s in self._cache if s.match(obj)]
|
||||
|
||||
if not serializers:
|
||||
raise TypeError(f"Don't know how to serialize {type(obj)}")
|
||||
|
||||
serializer = serializers[0]
|
||||
|
||||
stream = io.BytesIO()
|
||||
header = struct.pack(Serializer.HEADER_FORMAT, bytes(serializer.name, "utf-8"), serializer.version)
|
||||
stream.write(header)
|
||||
|
||||
return serializer.dump(stream, obj)
|
||||
|
||||
def deserialize(self, stream):
|
||||
"""
|
||||
Loads an object from its stream representation
|
||||
:param stream:
|
||||
:return:
|
||||
"""
|
||||
header = struct.unpack(Serializer.HEADER_FORMAT, stream.read(4))
|
||||
serializers = [s for s in self._cache if s.name == header[0].decode("utf-8") and s.version == header[1]]
|
||||
|
||||
if not serializers:
|
||||
raise TypeError(f"Don't know how serializer name={header[0]}, version={header[1]}")
|
||||
|
||||
serializer = serializers[0]
|
||||
return serializer.load(stream)
|
||||
|
||||
|
||||
class BaseSerializer:
|
||||
|
||||
def __init__(self, name, version):
|
||||
"""
|
||||
Create a serializer, given a name and a version
|
||||
:param name:
|
||||
:param version:
|
||||
:return:
|
||||
"""
|
||||
self.name = name
|
||||
self.version = version
|
||||
|
||||
@staticmethod
|
||||
def match(obj):
|
||||
"""
|
||||
Returns true if self can serialize obj
|
||||
:param obj:
|
||||
:return:
|
||||
"""
|
||||
pass
|
||||
|
||||
def dump(self, stream, obj):
|
||||
"""
|
||||
Returns the byte representation of how the object should be serialized
|
||||
|
||||
:param stream: to write to
|
||||
:param obj:
|
||||
:return: stream of bytes
|
||||
"""
|
||||
pass
|
||||
|
||||
def load(self, stream):
|
||||
"""
|
||||
From a stream of bytes, create the object
|
||||
:param stream:
|
||||
:return: object
|
||||
"""
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def get_class(kls):
|
||||
parts = kls.split('.')
|
||||
module = ".".join(parts[:-1])
|
||||
m = __import__(module)
|
||||
for comp in parts[1:]:
|
||||
m = getattr(m, comp)
|
||||
return m
|
||||
|
||||
@staticmethod
|
||||
def get_full_qualified_name(obj):
|
||||
module = obj.__class__.__module__
|
||||
if module is None or module == str.__class__.__module__:
|
||||
return obj.__class__.__name__ # Avoid reporting __builtin__
|
||||
else:
|
||||
return module + '.' + obj.__class__.__name__
|
||||
|
||||
|
||||
class EventSerializer(BaseSerializer):
|
||||
@staticmethod
|
||||
def match(obj):
|
||||
return BaseSerializer.get_full_qualified_name(obj) == "sdp.sheerkaDataProvider.Event"
|
||||
|
||||
def __init__(self):
|
||||
BaseSerializer.__init__(self, "E", 1)
|
||||
|
||||
def dump(self, stream, obj):
|
||||
stream.write(obj.to_json().encode("utf-8"))
|
||||
stream.seek(0)
|
||||
return stream
|
||||
|
||||
def load(self, stream):
|
||||
json_stream = stream.read().decode("utf-8")
|
||||
json_message = json.loads(json_stream)
|
||||
event = BaseSerializer.get_class("sdp.sheerkaDataProvider.Event")()
|
||||
event.from_json(json_message)
|
||||
return event
|
||||
|
||||
|
||||
class PickleSerializer(BaseSerializer):
|
||||
@staticmethod
|
||||
def match(obj):
|
||||
return BaseSerializer.get_full_qualified_name(obj) == "sdp.sheerkaDataProvider.State"
|
||||
|
||||
def __init__(self):
|
||||
BaseSerializer.__init__(self, "P", 1)
|
||||
|
||||
def dump(self, stream, obj):
|
||||
stream.write(pickle.dumps(obj))
|
||||
stream.seek(0)
|
||||
return stream
|
||||
|
||||
def load(self, stream):
|
||||
return pickle.loads(stream.read())
|
||||
|
||||
|
||||
Reference in New Issue
Block a user