Skip to content

Commit 40331fc

Browse files
committed
Merge pull request #48 from iurisilvio/jsonencoder
Custom JSON encoder and decoder.
2 parents 76b4944 + 2156c3c commit 40331fc

File tree

2 files changed

+46
-6
lines changed

2 files changed

+46
-6
lines changed

pusher/pusher.py

+7-5
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ class Pusher(object):
3636
:param backend: an http adapter class (AsyncIOBackend, RequestsBackend, SynchronousBackend, TornadoBackend)
3737
:param backend_options: additional backend
3838
"""
39-
def __init__(self, app_id, key, secret, ssl=True, host=None, port=None, timeout=5, cluster=None, backend=RequestsBackend, **backend_options):
39+
def __init__(self, app_id, key, secret, ssl=True, host=None, port=None, timeout=5, cluster=None,
40+
json_encoder=None, json_decoder=None, backend=RequestsBackend, **backend_options):
4041
self._app_id = ensure_text(app_id, "app_id")
4142
if not app_id_re.match(self._app_id):
4243
raise ValueError("Invalid app id")
@@ -62,6 +63,8 @@ def __init__(self, app_id, key, secret, ssl=True, host=None, port=None, timeout=
6263
if not isinstance(timeout, six.integer_types):
6364
raise TypeError("timeout should be an integer")
6465
self._timeout = timeout
66+
self._json_encoder = json_encoder
67+
self._json_decoder = json_decoder
6568

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

@@ -139,7 +142,7 @@ def trigger(self, channels, event_name, data, socket_id=None):
139142
if isinstance(data, six.string_types):
140143
data = ensure_text(data, "data")
141144
else:
142-
data = json.dumps(data)
145+
data = json.dumps(data, cls=self._json_encoder)
143146

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

210213
if custom_data:
211-
custom_data = json.dumps(custom_data)
214+
custom_data = json.dumps(custom_data, cls=self._json_encoder)
212215

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

@@ -244,15 +247,14 @@ def validate_webhook(self, key, signature, body):
244247
return None
245248

246249
try:
247-
body_data = json.loads(body)
250+
body_data = json.loads(body, cls=self._json_decoder)
248251
except ValueError:
249252
return None
250253

251254
time_ms = body_data.get('time_ms')
252255
if not time_ms:
253256
return None
254257

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

pusher_tests/test_pusher.py

+39-1
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@
55
import os
66
import six
77
import hmac
8+
import json
89
import hashlib
910
import unittest
11+
import time
12+
from decimal import Decimal
1013

1114
from pusher import Pusher
1215
from pusher.http import GET
16+
from pusher.signature import sign
1317

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

127131
self.assertEqual(actual, expected)
128-
dumps_mock.assert_called_once_with(custom_data)
132+
dumps_mock.assert_called_once_with(custom_data, cls=None)
129133

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

231+
232+
class TestJson(unittest.TestCase):
233+
def setUp(self):
234+
class JSONEncoder(json.JSONEncoder):
235+
def default(self, o):
236+
if isinstance(o, Decimal):
237+
return str(o)
238+
return super(JSONEncoder, self).default(o)
239+
240+
constants = {"NaN": 99999}
241+
242+
class JSONDecoder(json.JSONDecoder):
243+
def __init__(self, **kwargs):
244+
super(JSONDecoder, self).__init__(parse_constant=constants.__getitem__)
245+
246+
self.pusher = Pusher.from_url(u'http://key:secret@somehost/apps/4',
247+
json_encoder=JSONEncoder,
248+
json_decoder=JSONDecoder)
249+
250+
def test_custom_json_decoder(self):
251+
t = 1000 * time.time()
252+
body = u'{"nan": NaN, "time_ms": %f}' % t
253+
signature = sign(self.pusher.secret, body)
254+
data = self.pusher.validate_webhook(self.pusher.key, signature, body)
255+
self.assertEqual({u"nan": 99999, u"time_ms": t}, data)
256+
257+
def test_custom_json_encoder(self):
258+
expected = {
259+
u'channel_data': '{"money": "1.32"}',
260+
u'auth': u'key:75c6044a30f2ccd9952c48cfcf149cb0a4843bf38bab47545fb953acd62bd0c9'
261+
}
262+
data = self.pusher.authenticate("presence-c1", "1", {"money": Decimal("1.32")})
263+
self.assertEqual(expected, data)
264+
227265
if __name__ == '__main__':
228266
unittest.main()

0 commit comments

Comments
 (0)