From fa9c594cce613fb776e62ff29a0e6d9de7982fc2 Mon Sep 17 00:00:00 2001 From: Swann Date: Mon, 4 Feb 2019 17:58:12 +0100 Subject: [PATCH] added basic schema --- README.md | 4 + img/basic.png | Bin 0 -> 10048 bytes libs/umsgpack.py | 1134 +++++++++++++++++++++++++++++++++++++++++++++ main.py | 80 ++-- main_old.py | 52 +++ msgpacktest.py | 23 + net_components.py | 1 + 7 files changed, 1258 insertions(+), 36 deletions(-) create mode 100644 img/basic.png create mode 100644 libs/umsgpack.py create mode 100644 main_old.py create mode 100644 msgpacktest.py diff --git a/README.md b/README.md index eb18d99..376cc66 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # Realtime Collaborative Framework experiments +## Idea + +![basic](img/basic.png) + ## Dependencies | Dependency | Version | Needed | diff --git a/img/basic.png b/img/basic.png new file mode 100644 index 0000000000000000000000000000000000000000..48395ef51f9d969fd2cfae8eb48c34c8dfd0af4a GIT binary patch literal 10048 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 F{tMU&FhT$T literal 0 HcmV?d00001 diff --git a/libs/umsgpack.py b/libs/umsgpack.py new file mode 100644 index 0000000..139ab98 --- /dev/null +++ b/libs/umsgpack.py @@ -0,0 +1,1134 @@ +# u-msgpack-python v2.5.0 - v at sergeev.io +# https://github.com/vsergeev/u-msgpack-python +# +# u-msgpack-python is a lightweight MessagePack serializer and deserializer +# module, compatible with both Python 2 and 3, as well CPython and PyPy +# implementations of Python. u-msgpack-python is fully compliant with the +# latest MessagePack specification.com/msgpack/msgpack/blob/master/spec.md). In +# particular, it supports the new binary, UTF-8 string, and application ext +# types. +# +# MIT License +# +# Copyright (c) 2013-2016 vsergeev / Ivan (Vanya) A. Sergeev +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +""" +u-msgpack-python v2.5.0 - v at sergeev.io +https://github.com/vsergeev/u-msgpack-python + +u-msgpack-python is a lightweight MessagePack serializer and deserializer +module, compatible with both Python 2 and 3, as well CPython and PyPy +implementations of Python. u-msgpack-python is fully compliant with the +latest MessagePack specification.com/msgpack/msgpack/blob/master/spec.md). In +particular, it supports the new binary, UTF-8 string, and application ext +types. + +License: MIT +""" +import struct +import collections +import datetime +import sys +import io + +__version__ = "2.5.0" +"Module version string" + +version = (2, 5, 0) +"Module version tuple" + + +############################################################################## +# Ext Class +############################################################################## + +# Extension type for application-defined types and data +class Ext: + """ + The Ext class facilitates creating a serializable extension object to store + an application-defined type and data byte array. + """ + + def __init__(self, type, data): + """ + Construct a new Ext object. + + Args: + type: application-defined type integer + data: application-defined data byte array + + Example: + >>> foo = umsgpack.Ext(0x05, b"\x01\x02\x03") + >>> umsgpack.packb({u"special stuff": foo, u"awesome": True}) + '\x82\xa7awesome\xc3\xadspecial stuff\xc7\x03\x05\x01\x02\x03' + >>> bar = umsgpack.unpackb(_) + >>> print(bar["special stuff"]) + Ext Object (Type: 0x05, Data: 01 02 03) + >>> + """ + # Check type is type int + if not isinstance(type, int): + raise TypeError("ext type is not type integer") + # Check data is type bytes + elif sys.version_info[0] == 3 and not isinstance(data, bytes): + raise TypeError("ext data is not type \'bytes\'") + elif sys.version_info[0] == 2 and not isinstance(data, str): + raise TypeError("ext data is not type \'str\'") + self.type = type + self.data = data + + def __eq__(self, other): + """ + Compare this Ext object with another for equality. + """ + return (isinstance(other, self.__class__) and + self.type == other.type and + self.data == other.data) + + def __ne__(self, other): + """ + Compare this Ext object with another for inequality. + """ + return not self.__eq__(other) + + def __str__(self): + """ + String representation of this Ext object. + """ + s = "Ext Object (Type: 0x%02x, Data: " % self.type + s += " ".join(["0x%02x" % ord(self.data[i:i + 1]) + for i in xrange(min(len(self.data), 8))]) + if len(self.data) > 8: + s += " ..." + s += ")" + return s + + def __hash__(self): + """ + Provide a hash of this Ext object. + """ + return hash((self.type, self.data)) + + +class InvalidString(bytes): + """Subclass of bytes to hold invalid UTF-8 strings.""" + pass + +############################################################################## +# Exceptions +############################################################################## + + +# Base Exception classes +class PackException(Exception): + "Base class for exceptions encountered during packing." + pass + + +class UnpackException(Exception): + "Base class for exceptions encountered during unpacking." + pass + + +# Packing error +class UnsupportedTypeException(PackException): + "Object type not supported for packing." + pass + + +# Unpacking error +class InsufficientDataException(UnpackException): + "Insufficient data to unpack the serialized object." + pass + + +class InvalidStringException(UnpackException): + "Invalid UTF-8 string encountered during unpacking." + pass + + +class UnsupportedTimestampException(UnpackException): + "Unsupported timestamp format encountered during unpacking." + pass + + +class ReservedCodeException(UnpackException): + "Reserved code encountered during unpacking." + pass + + +class UnhashableKeyException(UnpackException): + """ + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + """ + pass + + +class DuplicateKeyException(UnpackException): + "Duplicate key encountered during map unpacking." + pass + + +# Backwards compatibility +KeyNotPrimitiveException = UnhashableKeyException +KeyDuplicateException = DuplicateKeyException + +############################################################################# +# Exported Functions and Glob +############################################################################# + +# Exported functions and variables, set up in __init() +pack = None +packb = None +unpack = None +unpackb = None +dump = None +dumps = None +load = None +loads = None + +compatibility = False +""" +Compatibility mode boolean. + +When compatibility mode is enabled, u-msgpack-python will serialize both +unicode strings and bytes into the old "raw" msgpack type, and deserialize the +"raw" msgpack type into bytes. This provides backwards compatibility with the +old MessagePack specification. + +Example: +>>> umsgpack.compatibility = True +>>> +>>> umsgpack.packb([u"some string", b"some bytes"]) +b'\x92\xabsome string\xaasome bytes' +>>> umsgpack.unpackb(_) +[b'some string', b'some bytes'] +>>> +""" + +############################################################################## +# Packing +############################################################################## + +# You may notice struct.pack("B", obj) instead of the simpler chr(obj) in the +# code below. This is to allow for seamless Python 2 and 3 compatibility, as +# chr(obj) has a str return type instead of bytes in Python 3, and +# struct.pack(...) has the right return type in both versions. + + +def _pack_integer(obj, fp, options): + if obj < 0: + if obj >= -32: + fp.write(struct.pack("b", obj)) + elif obj >= -2**(8 - 1): + fp.write(b"\xd0" + struct.pack("b", obj)) + elif obj >= -2**(16 - 1): + fp.write(b"\xd1" + struct.pack(">h", obj)) + elif obj >= -2**(32 - 1): + fp.write(b"\xd2" + struct.pack(">i", obj)) + elif obj >= -2**(64 - 1): + fp.write(b"\xd3" + struct.pack(">q", obj)) + else: + raise UnsupportedTypeException("huge signed int") + else: + if obj <= 127: + fp.write(struct.pack("B", obj)) + elif obj <= 2**8 - 1: + fp.write(b"\xcc" + struct.pack("B", obj)) + elif obj <= 2**16 - 1: + fp.write(b"\xcd" + struct.pack(">H", obj)) + elif obj <= 2**32 - 1: + fp.write(b"\xce" + struct.pack(">I", obj)) + elif obj <= 2**64 - 1: + fp.write(b"\xcf" + struct.pack(">Q", obj)) + else: + raise UnsupportedTypeException("huge unsigned int") + + +def _pack_nil(obj, fp, options): + fp.write(b"\xc0") + + +def _pack_boolean(obj, fp, options): + fp.write(b"\xc3" if obj else b"\xc2") + + +def _pack_float(obj, fp, options): + float_precision = options.get('force_float_precision', _float_precision) + + if float_precision == "double": + fp.write(b"\xcb" + struct.pack(">d", obj)) + elif float_precision == "single": + fp.write(b"\xca" + struct.pack(">f", obj)) + else: + raise ValueError("invalid float precision") + + +def _pack_string(obj, fp, options): + obj = obj.encode('utf-8') + if len(obj) <= 31: + fp.write(struct.pack("B", 0xa0 | len(obj)) + obj) + elif len(obj) <= 2**8 - 1: + fp.write(b"\xd9" + struct.pack("B", len(obj)) + obj) + elif len(obj) <= 2**16 - 1: + fp.write(b"\xda" + struct.pack(">H", len(obj)) + obj) + elif len(obj) <= 2**32 - 1: + fp.write(b"\xdb" + struct.pack(">I", len(obj)) + obj) + else: + raise UnsupportedTypeException("huge string") + + +def _pack_binary(obj, fp, options): + if len(obj) <= 2**8 - 1: + fp.write(b"\xc4" + struct.pack("B", len(obj)) + obj) + elif len(obj) <= 2**16 - 1: + fp.write(b"\xc5" + struct.pack(">H", len(obj)) + obj) + elif len(obj) <= 2**32 - 1: + fp.write(b"\xc6" + struct.pack(">I", len(obj)) + obj) + else: + raise UnsupportedTypeException("huge binary string") + + +def _pack_oldspec_raw(obj, fp, options): + if len(obj) <= 31: + fp.write(struct.pack("B", 0xa0 | len(obj)) + obj) + elif len(obj) <= 2**16 - 1: + fp.write(b"\xda" + struct.pack(">H", len(obj)) + obj) + elif len(obj) <= 2**32 - 1: + fp.write(b"\xdb" + struct.pack(">I", len(obj)) + obj) + else: + raise UnsupportedTypeException("huge raw string") + + +def _pack_ext(obj, fp, options): + if len(obj.data) == 1: + fp.write(b"\xd4" + struct.pack("B", obj.type & 0xff) + obj.data) + elif len(obj.data) == 2: + fp.write(b"\xd5" + struct.pack("B", obj.type & 0xff) + obj.data) + elif len(obj.data) == 4: + fp.write(b"\xd6" + struct.pack("B", obj.type & 0xff) + obj.data) + elif len(obj.data) == 8: + fp.write(b"\xd7" + struct.pack("B", obj.type & 0xff) + obj.data) + elif len(obj.data) == 16: + fp.write(b"\xd8" + struct.pack("B", obj.type & 0xff) + obj.data) + elif len(obj.data) <= 2**8 - 1: + fp.write(b"\xc7" + + struct.pack("BB", len(obj.data), obj.type & 0xff) + obj.data) + elif len(obj.data) <= 2**16 - 1: + fp.write(b"\xc8" + + struct.pack(">HB", len(obj.data), obj.type & 0xff) + obj.data) + elif len(obj.data) <= 2**32 - 1: + fp.write(b"\xc9" + + struct.pack(">IB", len(obj.data), obj.type & 0xff) + obj.data) + else: + raise UnsupportedTypeException("huge ext data") + + +def _pack_ext_timestamp(obj, fp, options): + delta = obj - _epoch + seconds = delta.seconds + delta.days * 86400 + microseconds = delta.microseconds + + if microseconds == 0 and 0 <= seconds <= 2**32 - 1: + # 32-bit timestamp + fp.write(b"\xd6\xff" + + struct.pack(">I", seconds)) + elif 0 <= seconds <= 2**34 - 1: + # 64-bit timestamp + value = ((microseconds * 1000) << 34) | seconds + fp.write(b"\xd7\xff" + + struct.pack(">Q", value)) + elif -2**63 <= abs(seconds) <= 2**63 - 1: + # 96-bit timestamp + fp.write(b"\xc7\x0c\xff" + + struct.pack(">I", microseconds * 1000) + + struct.pack(">q", seconds)) + else: + raise UnsupportedTypeException("huge timestamp") + + +def _pack_array(obj, fp, options): + if len(obj) <= 15: + fp.write(struct.pack("B", 0x90 | len(obj))) + elif len(obj) <= 2**16 - 1: + fp.write(b"\xdc" + struct.pack(">H", len(obj))) + elif len(obj) <= 2**32 - 1: + fp.write(b"\xdd" + struct.pack(">I", len(obj))) + else: + raise UnsupportedTypeException("huge array") + + for e in obj: + pack(e, fp, **options) + + +def _pack_map(obj, fp, options): + if len(obj) <= 15: + fp.write(struct.pack("B", 0x80 | len(obj))) + elif len(obj) <= 2**16 - 1: + fp.write(b"\xde" + struct.pack(">H", len(obj))) + elif len(obj) <= 2**32 - 1: + fp.write(b"\xdf" + struct.pack(">I", len(obj))) + else: + raise UnsupportedTypeException("huge array") + + for k, v in obj.items(): + pack(k, fp, **options) + pack(v, fp, **options) + +######################################## + + +# Pack for Python 2, with 'unicode' type, 'str' type, and 'long' type +def _pack2(obj, fp, **options): + """ + Serialize a Python object into MessagePack bytes. + + Args: + obj: a Python object + fp: a .write()-supporting file-like object + + Kwargs: + ext_handlers (dict): dictionary of Ext handlers, mapping a custom type + to a callable that packs an instance of the type + into an Ext object + force_float_precision (str): "single" to force packing floats as + IEEE-754 single-precision floats, + "double" to force packing floats as + IEEE-754 double-precision floats. + + Returns: + None. + + Raises: + UnsupportedType(PackException): + Object type not supported for packing. + + Example: + >>> f = open('test.bin', 'wb') + >>> umsgpack.pack({u"compact": True, u"schema": 0}, f) + >>> + """ + global compatibility + + ext_handlers = options.get("ext_handlers") + + if obj is None: + _pack_nil(obj, fp, options) + elif ext_handlers and obj.__class__ in ext_handlers: + _pack_ext(ext_handlers[obj.__class__](obj), fp, options) + elif isinstance(obj, bool): + _pack_boolean(obj, fp, options) + elif isinstance(obj, int) or isinstance(obj, long): + _pack_integer(obj, fp, options) + elif isinstance(obj, float): + _pack_float(obj, fp, options) + elif compatibility and isinstance(obj, unicode): + _pack_oldspec_raw(bytes(obj), fp, options) + elif compatibility and isinstance(obj, bytes): + _pack_oldspec_raw(obj, fp, options) + elif isinstance(obj, unicode): + _pack_string(obj, fp, options) + elif isinstance(obj, str): + _pack_binary(obj, fp, options) + elif isinstance(obj, list) or isinstance(obj, tuple): + _pack_array(obj, fp, options) + elif isinstance(obj, dict): + _pack_map(obj, fp, options) + elif isinstance(obj, datetime.datetime): + _pack_ext_timestamp(obj, fp, options) + elif isinstance(obj, Ext): + _pack_ext(obj, fp, options) + elif ext_handlers: + # Linear search for superclass + t = next((t for t in ext_handlers.keys() if isinstance(obj, t)), None) + if t: + _pack_ext(ext_handlers[t](obj), fp, options) + else: + raise UnsupportedTypeException( + "unsupported type: %s" % str(type(obj))) + else: + raise UnsupportedTypeException("unsupported type: %s" % str(type(obj))) + + +# Pack for Python 3, with unicode 'str' type, 'bytes' type, and no 'long' type +def _pack3(obj, fp, **options): + """ + Serialize a Python object into MessagePack bytes. + + Args: + obj: a Python object + fp: a .write()-supporting file-like object + + Kwargs: + ext_handlers (dict): dictionary of Ext handlers, mapping a custom type + to a callable that packs an instance of the type + into an Ext object + force_float_precision (str): "single" to force packing floats as + IEEE-754 single-precision floats, + "double" to force packing floats as + IEEE-754 double-precision floats. + + Returns: + None. + + Raises: + UnsupportedType(PackException): + Object type not supported for packing. + + Example: + >>> f = open('test.bin', 'wb') + >>> umsgpack.pack({u"compact": True, u"schema": 0}, f) + >>> + """ + global compatibility + + ext_handlers = options.get("ext_handlers") + + if obj is None: + _pack_nil(obj, fp, options) + elif ext_handlers and obj.__class__ in ext_handlers: + _pack_ext(ext_handlers[obj.__class__](obj), fp, options) + elif isinstance(obj, bool): + _pack_boolean(obj, fp, options) + elif isinstance(obj, int): + _pack_integer(obj, fp, options) + elif isinstance(obj, float): + _pack_float(obj, fp, options) + elif compatibility and isinstance(obj, str): + _pack_oldspec_raw(obj.encode('utf-8'), fp, options) + elif compatibility and isinstance(obj, bytes): + _pack_oldspec_raw(obj, fp, options) + elif isinstance(obj, str): + _pack_string(obj, fp, options) + elif isinstance(obj, bytes): + _pack_binary(obj, fp, options) + elif isinstance(obj, list) or isinstance(obj, tuple): + _pack_array(obj, fp, options) + elif isinstance(obj, dict): + _pack_map(obj, fp, options) + elif isinstance(obj, datetime.datetime): + _pack_ext_timestamp(obj, fp, options) + elif isinstance(obj, Ext): + _pack_ext(obj, fp, options) + elif ext_handlers: + # Linear search for superclass + t = next((t for t in ext_handlers.keys() if isinstance(obj, t)), None) + if t: + _pack_ext(ext_handlers[t](obj), fp, options) + else: + raise UnsupportedTypeException( + "unsupported type: %s" % str(type(obj))) + else: + raise UnsupportedTypeException( + "unsupported type: %s" % str(type(obj))) + + +def _packb2(obj, **options): + """ + Serialize a Python object into MessagePack bytes. + + Args: + obj: a Python object + + Kwargs: + ext_handlers (dict): dictionary of Ext handlers, mapping a custom type + to a callable that packs an instance of the type + into an Ext object + force_float_precision (str): "single" to force packing floats as + IEEE-754 single-precision floats, + "double" to force packing floats as + IEEE-754 double-precision floats. + + Returns: + A 'str' containing serialized MessagePack bytes. + + Raises: + UnsupportedType(PackException): + Object type not supported for packing. + + Example: + >>> umsgpack.packb({u"compact": True, u"schema": 0}) + '\x82\xa7compact\xc3\xa6schema\x00' + >>> + """ + fp = io.BytesIO() + _pack2(obj, fp, **options) + return fp.getvalue() + + +def _packb3(obj, **options): + """ + Serialize a Python object into MessagePack bytes. + + Args: + obj: a Python object + + Kwargs: + ext_handlers (dict): dictionary of Ext handlers, mapping a custom type + to a callable that packs an instance of the type + into an Ext object + force_float_precision (str): "single" to force packing floats as + IEEE-754 single-precision floats, + "double" to force packing floats as + IEEE-754 double-precision floats. + + Returns: + A 'bytes' containing serialized MessagePack bytes. + + Raises: + UnsupportedType(PackException): + Object type not supported for packing. + + Example: + >>> umsgpack.packb({u"compact": True, u"schema": 0}) + b'\x82\xa7compact\xc3\xa6schema\x00' + >>> + """ + fp = io.BytesIO() + _pack3(obj, fp, **options) + return fp.getvalue() + +############################################################################# +# Unpacking +############################################################################# + + +def _read_except(fp, n): + data = fp.read(n) + if len(data) < n: + raise InsufficientDataException() + return data + + +def _unpack_integer(code, fp, options): + if (ord(code) & 0xe0) == 0xe0: + return struct.unpack("b", code)[0] + elif code == b'\xd0': + return struct.unpack("b", _read_except(fp, 1))[0] + elif code == b'\xd1': + return struct.unpack(">h", _read_except(fp, 2))[0] + elif code == b'\xd2': + return struct.unpack(">i", _read_except(fp, 4))[0] + elif code == b'\xd3': + return struct.unpack(">q", _read_except(fp, 8))[0] + elif (ord(code) & 0x80) == 0x00: + return struct.unpack("B", code)[0] + elif code == b'\xcc': + return struct.unpack("B", _read_except(fp, 1))[0] + elif code == b'\xcd': + return struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b'\xce': + return struct.unpack(">I", _read_except(fp, 4))[0] + elif code == b'\xcf': + return struct.unpack(">Q", _read_except(fp, 8))[0] + raise Exception("logic error, not int: 0x%02x" % ord(code)) + + +def _unpack_reserved(code, fp, options): + if code == b'\xc1': + raise ReservedCodeException( + "encountered reserved code: 0x%02x" % ord(code)) + raise Exception( + "logic error, not reserved code: 0x%02x" % ord(code)) + + +def _unpack_nil(code, fp, options): + if code == b'\xc0': + return None + raise Exception("logic error, not nil: 0x%02x" % ord(code)) + + +def _unpack_boolean(code, fp, options): + if code == b'\xc2': + return False + elif code == b'\xc3': + return True + raise Exception("logic error, not boolean: 0x%02x" % ord(code)) + + +def _unpack_float(code, fp, options): + if code == b'\xca': + return struct.unpack(">f", _read_except(fp, 4))[0] + elif code == b'\xcb': + return struct.unpack(">d", _read_except(fp, 8))[0] + raise Exception("logic error, not float: 0x%02x" % ord(code)) + + +def _unpack_string(code, fp, options): + if (ord(code) & 0xe0) == 0xa0: + length = ord(code) & ~0xe0 + elif code == b'\xd9': + length = struct.unpack("B", _read_except(fp, 1))[0] + elif code == b'\xda': + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b'\xdb': + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not string: 0x%02x" % ord(code)) + + # Always return raw bytes in compatibility mode + global compatibility + if compatibility: + return _read_except(fp, length) + + data = _read_except(fp, length) + try: + return bytes.decode(data, 'utf-8') + except UnicodeDecodeError: + if options.get("allow_invalid_utf8"): + return InvalidString(data) + raise InvalidStringException("unpacked string is invalid utf-8") + + +def _unpack_binary(code, fp, options): + if code == b'\xc4': + length = struct.unpack("B", _read_except(fp, 1))[0] + elif code == b'\xc5': + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b'\xc6': + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not binary: 0x%02x" % ord(code)) + + return _read_except(fp, length) + + +def _unpack_ext(code, fp, options): + if code == b'\xd4': + length = 1 + elif code == b'\xd5': + length = 2 + elif code == b'\xd6': + length = 4 + elif code == b'\xd7': + length = 8 + elif code == b'\xd8': + length = 16 + elif code == b'\xc7': + length = struct.unpack("B", _read_except(fp, 1))[0] + elif code == b'\xc8': + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b'\xc9': + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not ext: 0x%02x" % ord(code)) + + ext_type = struct.unpack("b", _read_except(fp, 1))[0] + ext_data = _read_except(fp, length) + + # Create extension object + ext = Ext(ext_type, ext_data) + + # Unpack with ext handler, if we have one + ext_handlers = options.get("ext_handlers") + if ext_handlers and ext.type in ext_handlers: + return ext_handlers[ext.type](ext) + + # Timestamp extension + if ext.type == -1: + return _unpack_ext_timestamp(ext, options) + + return ext + + +def _unpack_ext_timestamp(ext, options): + if len(ext.data) == 4: + # 32-bit timestamp + seconds = struct.unpack(">I", ext.data)[0] + microseconds = 0 + elif len(ext.data) == 8: + # 64-bit timestamp + value = struct.unpack(">Q", ext.data)[0] + seconds = value & 0x3ffffffff + microseconds = (value >> 34) // 1000 + elif len(ext.data) == 12: + # 96-bit timestamp + seconds = struct.unpack(">q", ext.data[4:12])[0] + microseconds = struct.unpack(">I", ext.data[0:4])[0] // 1000 + else: + raise UnsupportedTimestampException( + "unsupported timestamp with data length %d" % len(ext.data)) + + return _epoch + datetime.timedelta(seconds=seconds, + microseconds=microseconds) + + +def _unpack_array(code, fp, options): + if (ord(code) & 0xf0) == 0x90: + length = (ord(code) & ~0xf0) + elif code == b'\xdc': + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b'\xdd': + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not array: 0x%02x" % ord(code)) + + return [_unpack(fp, options) for i in xrange(length)] + + +def _deep_list_to_tuple(obj): + if isinstance(obj, list): + return tuple([_deep_list_to_tuple(e) for e in obj]) + return obj + + +def _unpack_map(code, fp, options): + if (ord(code) & 0xf0) == 0x80: + length = (ord(code) & ~0xf0) + elif code == b'\xde': + length = struct.unpack(">H", _read_except(fp, 2))[0] + elif code == b'\xdf': + length = struct.unpack(">I", _read_except(fp, 4))[0] + else: + raise Exception("logic error, not map: 0x%02x" % ord(code)) + + d = {} if not options.get('use_ordered_dict') \ + else collections.OrderedDict() + for _ in xrange(length): + # Unpack key + k = _unpack(fp, options) + + if isinstance(k, list): + # Attempt to convert list into a hashable tuple + k = _deep_list_to_tuple(k) + elif not isinstance(k, collections.Hashable): + raise UnhashableKeyException( + "encountered unhashable key: %s, %s" % (str(k), str(type(k)))) + elif k in d: + raise DuplicateKeyException( + "encountered duplicate key: %s, %s" % (str(k), str(type(k)))) + + # Unpack value + v = _unpack(fp, options) + + try: + d[k] = v + except TypeError: + raise UnhashableKeyException( + "encountered unhashable key: %s" % str(k)) + return d + + +def _unpack(fp, options): + code = _read_except(fp, 1) + return _unpack_dispatch_table[code](code, fp, options) + +######################################## + + +def _unpack2(fp, **options): + """ + Deserialize MessagePack bytes into a Python object. + + Args: + fp: a .read()-supporting file-like object + + Kwargs: + ext_handlers (dict): dictionary of Ext handlers, mapping integer Ext + type to a callable that unpacks an instance of + Ext into an object + use_ordered_dict (bool): unpack maps into OrderedDict, instead of + unordered dict (default False) + allow_invalid_utf8 (bool): unpack invalid strings into instances of + InvalidString, for access to the bytes + (default False) + + Returns: + A Python object. + + Raises: + InsufficientDataException(UnpackException): + Insufficient data to unpack the serialized object. + InvalidStringException(UnpackException): + Invalid UTF-8 string encountered during unpacking. + UnsupportedTimestampException(UnpackException): + Unsupported timestamp format encountered during unpacking. + ReservedCodeException(UnpackException): + Reserved code encountered during unpacking. + UnhashableKeyException(UnpackException): + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + DuplicateKeyException(UnpackException): + Duplicate key encountered during map unpacking. + + Example: + >>> f = open('test.bin', 'rb') + >>> umsgpack.unpackb(f) + {u'compact': True, u'schema': 0} + >>> + """ + return _unpack(fp, options) + + +def _unpack3(fp, **options): + """ + Deserialize MessagePack bytes into a Python object. + + Args: + fp: a .read()-supporting file-like object + + Kwargs: + ext_handlers (dict): dictionary of Ext handlers, mapping integer Ext + type to a callable that unpacks an instance of + Ext into an object + use_ordered_dict (bool): unpack maps into OrderedDict, instead of + unordered dict (default False) + allow_invalid_utf8 (bool): unpack invalid strings into instances of + InvalidString, for access to the bytes + (default False) + + Returns: + A Python object. + + Raises: + InsufficientDataException(UnpackException): + Insufficient data to unpack the serialized object. + InvalidStringException(UnpackException): + Invalid UTF-8 string encountered during unpacking. + UnsupportedTimestampException(UnpackException): + Unsupported timestamp format encountered during unpacking. + ReservedCodeException(UnpackException): + Reserved code encountered during unpacking. + UnhashableKeyException(UnpackException): + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + DuplicateKeyException(UnpackException): + Duplicate key encountered during map unpacking. + + Example: + >>> f = open('test.bin', 'rb') + >>> umsgpack.unpackb(f) + {'compact': True, 'schema': 0} + >>> + """ + return _unpack(fp, options) + + +# For Python 2, expects a str object +def _unpackb2(s, **options): + """ + Deserialize MessagePack bytes into a Python object. + + Args: + s: a 'str' or 'bytearray' containing serialized MessagePack bytes + + Kwargs: + ext_handlers (dict): dictionary of Ext handlers, mapping integer Ext + type to a callable that unpacks an instance of + Ext into an object + use_ordered_dict (bool): unpack maps into OrderedDict, instead of + unordered dict (default False) + allow_invalid_utf8 (bool): unpack invalid strings into instances of + InvalidString, for access to the bytes + (default False) + + Returns: + A Python object. + + Raises: + TypeError: + Packed data type is neither 'str' nor 'bytearray'. + InsufficientDataException(UnpackException): + Insufficient data to unpack the serialized object. + InvalidStringException(UnpackException): + Invalid UTF-8 string encountered during unpacking. + UnsupportedTimestampException(UnpackException): + Unsupported timestamp format encountered during unpacking. + ReservedCodeException(UnpackException): + Reserved code encountered during unpacking. + UnhashableKeyException(UnpackException): + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + DuplicateKeyException(UnpackException): + Duplicate key encountered during map unpacking. + + Example: + >>> umsgpack.unpackb(b'\x82\xa7compact\xc3\xa6schema\x00') + {u'compact': True, u'schema': 0} + >>> + """ + if not isinstance(s, (str, bytearray)): + raise TypeError("packed data must be type 'str' or 'bytearray'") + return _unpack(io.BytesIO(s), options) + + +# For Python 3, expects a bytes object +def _unpackb3(s, **options): + """ + Deserialize MessagePack bytes into a Python object. + + Args: + s: a 'bytes' or 'bytearray' containing serialized MessagePack bytes + + Kwargs: + ext_handlers (dict): dictionary of Ext handlers, mapping integer Ext + type to a callable that unpacks an instance of + Ext into an object + use_ordered_dict (bool): unpack maps into OrderedDict, instead of + unordered dict (default False) + allow_invalid_utf8 (bool): unpack invalid strings into instances of + InvalidString, for access to the bytes + (default False) + + Returns: + A Python object. + + Raises: + TypeError: + Packed data type is neither 'bytes' nor 'bytearray'. + InsufficientDataException(UnpackException): + Insufficient data to unpack the serialized object. + InvalidStringException(UnpackException): + Invalid UTF-8 string encountered during unpacking. + UnsupportedTimestampException(UnpackException): + Unsupported timestamp format encountered during unpacking. + ReservedCodeException(UnpackException): + Reserved code encountered during unpacking. + UnhashableKeyException(UnpackException): + Unhashable key encountered during map unpacking. + The serialized map cannot be deserialized into a Python dictionary. + DuplicateKeyException(UnpackException): + Duplicate key encountered during map unpacking. + + Example: + >>> umsgpack.unpackb(b'\x82\xa7compact\xc3\xa6schema\x00') + {'compact': True, 'schema': 0} + >>> + """ + if not isinstance(s, (bytes, bytearray)): + raise TypeError("packed data must be type 'bytes' or 'bytearray'") + return _unpack(io.BytesIO(s), options) + +############################################################################# +# Module Initialization +############################################################################# + + +def __init(): + global pack + global packb + global unpack + global unpackb + global dump + global dumps + global load + global loads + global compatibility + global _epoch + global _utc_tzinfo + global _float_precision + global _unpack_dispatch_table + global xrange + + # Compatibility mode for handling strings/bytes with the old specification + compatibility = False + + if sys.version_info[0] == 3: + _utc_tzinfo = datetime.timezone.utc + else: + _utc_tzinfo = None + + # Calculate epoch datetime + _epoch = datetime.datetime(1970, 1, 1, tzinfo=_utc_tzinfo) + + # Auto-detect system float precision + if sys.float_info.mant_dig == 53: + _float_precision = "double" + else: + _float_precision = "single" + + # Map packb and unpackb to the appropriate version + if sys.version_info[0] == 3: + pack = _pack3 + packb = _packb3 + dump = _pack3 + dumps = _packb3 + unpack = _unpack3 + unpackb = _unpackb3 + load = _unpack3 + loads = _unpackb3 + xrange = range + else: + pack = _pack2 + packb = _packb2 + dump = _pack2 + dumps = _packb2 + unpack = _unpack2 + unpackb = _unpackb2 + load = _unpack2 + loads = _unpackb2 + + # Build a dispatch table for fast lookup of unpacking function + + _unpack_dispatch_table = {} + # Fix uint + for code in range(0, 0x7f + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer + # Fix map + for code in range(0x80, 0x8f + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_map + # Fix array + for code in range(0x90, 0x9f + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_array + # Fix str + for code in range(0xa0, 0xbf + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_string + # Nil + _unpack_dispatch_table[b'\xc0'] = _unpack_nil + # Reserved + _unpack_dispatch_table[b'\xc1'] = _unpack_reserved + # Boolean + _unpack_dispatch_table[b'\xc2'] = _unpack_boolean + _unpack_dispatch_table[b'\xc3'] = _unpack_boolean + # Bin + for code in range(0xc4, 0xc6 + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_binary + # Ext + for code in range(0xc7, 0xc9 + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_ext + # Float + _unpack_dispatch_table[b'\xca'] = _unpack_float + _unpack_dispatch_table[b'\xcb'] = _unpack_float + # Uint + for code in range(0xcc, 0xcf + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer + # Int + for code in range(0xd0, 0xd3 + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer + # Fixext + for code in range(0xd4, 0xd8 + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_ext + # String + for code in range(0xd9, 0xdb + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_string + # Array + _unpack_dispatch_table[b'\xdc'] = _unpack_array + _unpack_dispatch_table[b'\xdd'] = _unpack_array + # Map + _unpack_dispatch_table[b'\xde'] = _unpack_map + _unpack_dispatch_table[b'\xdf'] = _unpack_map + # Negative fixint + for code in range(0xe0, 0xff + 1): + _unpack_dispatch_table[struct.pack("B", code)] = _unpack_integer + + +__init() diff --git a/main.py b/main.py index b0905e0..255d60a 100644 --- a/main.py +++ b/main.py @@ -5,50 +5,58 @@ import zmq import sys import argparse import time +from zmq.asyncio import Context, ZMQEventLoop import asyncio +Url = 'tcp://127.0.0.1:5555' +Ctx = Context() + + +@asyncio.coroutine +def server(): + print("Getting ready for hello world client. Ctrl-C to exit.\n") + socket = Ctx.socket(zmq.REP) + socket.bind(Url) + while True: + # Wait for next request from client + message = yield from socket.recv() + print("Received request: {}".format(message)) + # Do some "work" + yield from asyncio.sleep(1) + # Send reply back to client + message = message.decode('utf-8') + message = '{}, world'.format(message) + message = message.encode('utf-8') + print("Sending reply: {}".format(message)) + yield from socket.send(message) + # TODO: Implement a manager class for each aspect (ex: Network_Manager) # TODO: Is it right to implement server-client as ESC ?... -@asyncio.coroutine def main(): - # Argument parsing - parser = argparse.ArgumentParser( - description='Launch an instance of collaboration system') - parser.add_argument('-r', choices=list(net_components.Role), - type=net_components.Role, help='role for the instance ') - - args = parser.parse_args() - - instance_role = args.r - instance_context = zmq.Context() - - print("Starting a {} instance \n".format(instance_role)) - - # Create a World instance to hold everything: - world = esper.World() - - # Instantiate a Processor (or more), and add them to the world: - network_system = net_systems.NetworkSystem() - world.add_processor(network_system) - - # Instanciate a session entity - session = world.create_entity() - - world.add_component( - session, net_components.NetworkInterface(context=instance_context)) - world.add_component( - session, net_components.User(role=instance_role)) - - - # A dummy main loop: + args = sys.argv[1:] + if len(args) != 0: + sys.exit(__doc__) try: - while True: - # Call world.process() to run all Processors. - world.process() - time.sleep(1) + loop = asyncio.get_event_loop() + loop.run_until_complete(server()) except KeyboardInterrupt: - return + print('\nFinished (interrupted)') + sys.exit(0) + + # Socket to talk to server + print("Connecting to hello world server...") + socket = context.socket(zmq.REQ) + socket.connect("tcp://localhost:5555") + + # Do 10 requests, waiting each time for a response + for request in range(10): + print("Sending request %s ..." % request) + socket.send(b"Hello") + + # Get the reply. + message = socket.recv() + print("Received reply %s [ %s ]" % (request, message)) if __name__ == '__main__': diff --git a/main_old.py b/main_old.py new file mode 100644 index 0000000..6566bec --- /dev/null +++ b/main_old.py @@ -0,0 +1,52 @@ +import net_systems +import net_components +from libs.esper import esper +import zmq +import sys +import argparse +import time + +# TODO: Implement a manager class for each aspect (ex: Network_Manager) +# TODO: Is it right to implement server-client as ESC ?... +def main(): + # Argument parsing + parser = argparse.ArgumentParser( + description='Launch an instance of collaboration system') + parser.add_argument('-r', choices=list(net_components.Role), + type=net_components.Role, help='role for the instance ') + + args = parser.parse_args() + + instance_role = args.r + instance_context = zmq.Context() + + print("Starting a {} instance \n".format(instance_role)) + + # Create a World instance to hold everything: + world = esper.World() + + # Instantiate a Processor (or more), and add them to the world: + network_system = net_systems.NetworkSystem() + world.add_processor(network_system) + + # Instanciate a session entity + session = world.create_entity() + + world.add_component( + session, net_components.NetworkInterface(context=instance_context)) + world.add_component( + session, net_components.User(role=instance_role)) + + + # A dummy main loop: + try: + while True: + # Call world.process() to run all Processors. + world.process() + time.sleep(1) + except KeyboardInterrupt: + return + + +if __name__ == '__main__': + main() diff --git a/msgpacktest.py b/msgpacktest.py new file mode 100644 index 0000000..6ac8f44 --- /dev/null +++ b/msgpacktest.py @@ -0,0 +1,23 @@ +import sys +import os + + +thirdPartyDir = "C:\\Users\\slumber\\repos\\phd\src\\2019_rcf\\libs" + + + +if thirdPartyDir in sys.path: + print('Third party module already added') +else: + print('Adding local modules dir to the path') + sys.path.insert(0, thirdPartyDir) + + +import umsgpack +import bpy +import esper + + +#c = umsgpack.packb("test") +#print(umsgpack.unpackb(c)) + diff --git a/net_components.py b/net_components.py index d9f21e9..aa15720 100644 --- a/net_components.py +++ b/net_components.py @@ -42,3 +42,4 @@ class Function: def __init__(self, function=None): self.function = function +