Skip to content

Custom JSON encoder and decoder. #48

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 7, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions pusher/pusher.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ class Pusher(object):
:param backend: an http adapter class (AsyncIOBackend, RequestsBackend, SynchronousBackend, TornadoBackend)
:param backend_options: additional backend
"""
def __init__(self, app_id, key, secret, ssl=True, host=None, port=None, timeout=5, cluster=None, backend=RequestsBackend, **backend_options):
def __init__(self, app_id, key, secret, ssl=True, host=None, port=None, timeout=5, cluster=None,
json_encoder=None, json_decoder=None, backend=RequestsBackend, **backend_options):
self._app_id = ensure_text(app_id, "app_id")
if not app_id_re.match(self._app_id):
raise ValueError("Invalid app id")
Expand All @@ -62,6 +63,8 @@ def __init__(self, app_id, key, secret, ssl=True, host=None, port=None, timeout=
if not isinstance(timeout, six.integer_types):
raise TypeError("timeout should be an integer")
self._timeout = timeout
self._json_encoder = json_encoder
self._json_decoder = json_decoder

self.http = backend(self, **backend_options)

Expand Down Expand Up @@ -139,7 +142,7 @@ def trigger(self, channels, event_name, data, socket_id=None):
if isinstance(data, six.string_types):
data = ensure_text(data, "data")
else:
data = json.dumps(data)
data = json.dumps(data, cls=self._json_encoder)

if len(data) > 10240:
raise ValueError("Too much data")
Expand Down Expand Up @@ -208,7 +211,7 @@ def authenticate(self, channel, socket_id, custom_data=None):
socket_id = ensure_text(socket_id, "socket_id")

if custom_data:
custom_data = json.dumps(custom_data)
custom_data = json.dumps(custom_data, cls=self._json_encoder)

string_to_sign = "%s:%s" % (socket_id, channel)

Expand Down Expand Up @@ -244,15 +247,14 @@ def validate_webhook(self, key, signature, body):
return None

try:
body_data = json.loads(body)
body_data = json.loads(body, cls=self._json_decoder)
except ValueError:
return None

time_ms = body_data.get('time_ms')
if not time_ms:
return None

print(abs(time.time()*1000 - time_ms))
if abs(time.time()*1000 - time_ms) > 300000:
return None

Expand Down
40 changes: 39 additions & 1 deletion pusher_tests/test_pusher.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
import os
import six
import hmac
import json
import hashlib
import unittest
import time
from decimal import Decimal

from pusher import Pusher
from pusher.http import GET
from pusher.signature import sign

try:
import unittest.mock as mock
Expand Down Expand Up @@ -125,7 +129,7 @@ def test_authenticate_for_presence_channels(self):
actual = pusher.authenticate(u'presence-channel', u'34543245', custom_data)

self.assertEqual(actual, expected)
dumps_mock.assert_called_once_with(custom_data)
dumps_mock.assert_called_once_with(custom_data, cls=None)

def test_validate_webhook_success_case(self):
pusher = Pusher.from_url(u'http://foo:bar@host/apps/4')
Expand Down Expand Up @@ -224,5 +228,39 @@ def test_user_info_success_case(self):
self.assertEqual(request.path, u'/apps/4/channels/presence-channel/users')
self.assertEqual(request.params, {})


class TestJson(unittest.TestCase):
def setUp(self):
class JSONEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, Decimal):
return str(o)
return super(JSONEncoder, self).default(o)

constants = {"NaN": 99999}

class JSONDecoder(json.JSONDecoder):
def __init__(self, **kwargs):
super(JSONDecoder, self).__init__(parse_constant=constants.__getitem__)

self.pusher = Pusher.from_url(u'http://key:secret@somehost/apps/4',
json_encoder=JSONEncoder,
json_decoder=JSONDecoder)

def test_custom_json_decoder(self):
t = 1000 * time.time()
body = u'{"nan": NaN, "time_ms": %f}' % t
signature = sign(self.pusher.secret, body)
data = self.pusher.validate_webhook(self.pusher.key, signature, body)
self.assertEqual({u"nan": 99999, u"time_ms": t}, data)

def test_custom_json_encoder(self):
expected = {
u'channel_data': '{"money": "1.32"}',
u'auth': u'key:75c6044a30f2ccd9952c48cfcf149cb0a4843bf38bab47545fb953acd62bd0c9'
}
data = self.pusher.authenticate("presence-c1", "1", {"money": Decimal("1.32")})
self.assertEqual(expected, data)

if __name__ == '__main__':
unittest.main()