Skip to content

Commit

Permalink
Merge pull request #808 from oberstet/json_bin_conversion
Browse files Browse the repository at this point in the history
Json bin conversion
  • Loading branch information
oberstet committed Apr 5, 2017
2 parents 4828a37 + 82fe6a4 commit 459da03
Show file tree
Hide file tree
Showing 5 changed files with 218 additions and 92 deletions.
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ all:
install:
# enforce use of bundled libsodium
export SODIUM_INSTALL=bundled
pip install --upgrade -e .[all,dev]
pip install --upgrade -e .[twisted,asyncio,serialization,encryption,dev]

# upload to our internal deployment system
upload: clean
Expand Down Expand Up @@ -72,6 +72,9 @@ test_twisted:
USE_TWISTED=1 trial autobahn
#WAMP_ROUTER_URL="ws://127.0.0.1:8080/ws" USE_TWISTED=1 trial autobahn

test_serializer:
USE_TWISTED=1 trial autobahn.wamp.test.test_serializer

test_twisted_coverage:
-rm .coverage
USE_TWISTED=1 coverage run --omit=*/test/* --source=autobahn `which trial` autobahn
Expand Down
1 change: 1 addition & 0 deletions autobahn/twisted/wamp.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import six
import inspect
import binascii
from functools import reduce

import txaio
txaio.use_twisted() # noqa
Expand Down
6 changes: 2 additions & 4 deletions autobahn/wamp/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,10 +408,8 @@ def onUserError(self, fail, msg):
"""
Implements :func:`autobahn.wamp.interfaces.ISession.onUserError`
"""
if isinstance(fail.value, exception.ApplicationError):
# silence on errors raised explicitly from the app
# previous code: self.log.error(fail.value.error_message())
pass
if False and isinstance(fail.value, exception.ApplicationError):
self.log.error(fail.value.error_message())
else:
self.log.error(
u'{msg}: {traceback}',
Expand Down
138 changes: 85 additions & 53 deletions autobahn/wamp/serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,73 +136,105 @@ def unserialize(self, payload, isBinary=None):


# JSON serialization is always supported
try:
# try import accelerated JSON implementation
#
import ujson

_json = ujson
import json
import base64

def _loads(val):
return ujson.loads(val, precise_float=True)

def _dumps(obj):
return ujson.dumps(obj, double_precision=15, ensure_ascii=False)
class _WAMPJsonEncoder(json.JSONEncoder):

except ImportError:
# fallback to stdlib implementation
#
import json
def default(self, obj):
if isinstance(obj, six.binary_type):
return u'\x00' + base64.b64encode(obj).decode('ascii')
else:
return json.JSONEncoder.default(self, obj)

_json = json

_loads = json.loads
#
# the following is a hack. see http://bugs.python.org/issue29992
#

def _dumps(obj):
return json.dumps(obj, separators=(',', ':'), ensure_ascii=False)
from json import scanner
from json.decoder import scanstring

finally:
class JsonObjectSerializer(object):

JSON_MODULE = _json
"""
The JSON module used (either stdib builtin or ujson).
"""
def _parse_string(*args, **kwargs):
s, idx = scanstring(*args, **kwargs)
if s and s[0] == u'\x00':
s = base64.b64decode(s[1:])
return s, idx

BINARY = False

def __init__(self, batched=False):
"""
Ctor.
class _WAMPJsonDecoder(json.JSONDecoder):

:param batched: Flag that controls whether serializer operates in batched mode.
:type batched: bool
"""
self._batched = batched
def __init__(self, *args, **kwargs):
json.JSONDecoder.__init__(self, *args, **kwargs)
self.parse_string = _parse_string

def serialize(self, obj):
"""
Implements :func:`autobahn.wamp.interfaces.IObjectSerializer.serialize`
"""
s = _dumps(obj)
if isinstance(s, six.text_type):
s = s.encode('utf8')
if self._batched:
return s + b'\30'
else:
return s
# we need to recreate the internal scan function ..
self.scan_once = scanner.py_make_scanner(self)

def unserialize(self, payload):
"""
Implements :func:`autobahn.wamp.interfaces.IObjectSerializer.unserialize`
"""
if self._batched:
chunks = payload.split(b'\30')[:-1]
else:
chunks = [payload]
if len(chunks) == 0:
raise Exception("batch format error")
return [_loads(data.decode('utf8')) for data in chunks]
# .. and we have to explicitly use the Py version,
# not the C version, as the latter won't work
# self.scan_once = scanner.make_scanner(self)


def _loads(s):
return json.loads(s, cls=_WAMPJsonDecoder)


def _dumps(obj):
return json.dumps(obj,
separators=(',', ':'),
ensure_ascii=False,
sort_keys=False,
cls=_WAMPJsonEncoder)


_json = json


class JsonObjectSerializer(object):

JSON_MODULE = _json
"""
The JSON module used (now only stdlib).
"""

BINARY = False

def __init__(self, batched=False):
"""
Ctor.
:param batched: Flag that controls whether serializer operates in batched mode.
:type batched: bool
"""
self._batched = batched

def serialize(self, obj):
"""
Implements :func:`autobahn.wamp.interfaces.IObjectSerializer.serialize`
"""
s = _dumps(obj)
if isinstance(s, six.text_type):
s = s.encode('utf8')
if self._batched:
return s + b'\30'
else:
return s

def unserialize(self, payload):
"""
Implements :func:`autobahn.wamp.interfaces.IObjectSerializer.unserialize`
"""
if self._batched:
chunks = payload.split(b'\30')[:-1]
else:
chunks = [payload]
if len(chunks) == 0:
raise Exception("batch format error")
return [_loads(data.decode('utf8')) for data in chunks]


IObjectSerializer.register(JsonObjectSerializer)
Expand Down

0 comments on commit 459da03

Please sign in to comment.