diff --git a/TODO.goals b/TODO.goals index 619a558..1c863a8 100644 --- a/TODO.goals +++ b/TODO.goals @@ -1,9 +1,8 @@ Release 0.6.1 #41 #52 - Send pong - Change print statements into logging statements - Clean up - - Put tests in index.html Update tests Merge sarietta's pull request +Add Websocket transport +Consider logging packets sent and received Implement rooms #65 +Implement binary event +Implement binary ack diff --git a/socketIO_client/__init__.py b/socketIO_client/__init__.py index 8ece708..eb84e60 100644 --- a/socketIO_client/__init__.py +++ b/socketIO_client/__init__.py @@ -314,9 +314,14 @@ class SocketIO(EngineIO): self._message(str(socketIO_packet_type) + socketIO_packet_data) def disconnect(self, path=''): - socketIO_packet_type = 1 - socketIO_packet_data = format_socketIO_data(path) - self._message(str(socketIO_packet_type) + socketIO_packet_data) + if not self.connected: + return + if path: + socketIO_packet_type = 1 + socketIO_packet_data = format_socketIO_data(path) + self._message(str(socketIO_packet_type) + socketIO_packet_data) + else: + self._close() try: namespace = self._namespace_by_path.pop(path) namespace.on_disconnect() @@ -337,6 +342,11 @@ class SocketIO(EngineIO): args.append(callback) self.emit('message', *args) + def _ack(self, path, ack_id, *args): + socketIO_packet_type = 3 + socketIO_packet_data = format_socketIO_data(path, ack_id, args) + self._message(str(socketIO_packet_type) + socketIO_packet_data) + # React def wait(self, seconds=None, for_callbacks=False): diff --git a/socketIO_client/parsers.py b/socketIO_client/parsers.py index e748164..a095d8a 100644 --- a/socketIO_client/parsers.py +++ b/socketIO_client/parsers.py @@ -77,7 +77,7 @@ def parse_socketIO_data(data): def format_socketIO_data(path=None, ack_id=None, args=None): - socketIO_packet_data = json.dumps(args) if args else '' + socketIO_packet_data = json.dumps(args, ensure_ascii=False) if args else '' if ack_id is not None: socketIO_packet_data = str(ack_id) + socketIO_packet_data if path: diff --git a/socketIO_client/tests/__init__.py b/socketIO_client/tests/__init__.py index 75be733..a5ab078 100644 --- a/socketIO_client/tests/__init__.py +++ b/socketIO_client/tests/__init__.py @@ -1,4 +1,5 @@ import logging +import time from unittest import TestCase from .. import SocketIO, LoggingSocketIONamespace, find_callback @@ -19,6 +20,20 @@ class BaseMixin(object): def tearDown(self): del self.socketIO + def test_disconnect(self): + 'Disconnect' + self.socketIO.define(LoggingSocketIONamespace) + self.assertTrue(self.socketIO.connected) + self.socketIO.disconnect() + self.assertFalse(self.socketIO.connected) + # Use context manager + with SocketIO(HOST, PORT, Namespace) as self.socketIO: + namespace = self.socketIO.get_namespace() + self.assertFalse(namespace.called_on_disconnect) + self.assertTrue(self.socketIO.connected) + self.assertTrue(namespace.called_on_disconnect) + self.assertFalse(self.socketIO.connected) + def test_emit(self): 'Emit' namespace = self.socketIO.define(Namespace) @@ -90,6 +105,48 @@ class BaseMixin(object): self.socketIO.wait(self.wait_time_in_seconds) self.assertEqual(namespace.response, DATA) + def test_ack(self): + 'Respond to a server callback request' + namespace = self.socketIO.define(Namespace) + self.socketIO.emit('trigger_server_expects_callback', PAYLOAD) + self.socketIO.wait(self.wait_time_in_seconds) + self.assertEqual(namespace.args_by_event, { + 'server_expects_callback': (PAYLOAD,), + 'server_received_callback': (PAYLOAD,), + }) + + def test_wait_with_disconnect(self): + 'Exit loop when the client wants to disconnect' + self.socketIO.define(Namespace) + self.socketIO.emit('wait_with_disconnect') + timeout_in_seconds = 5 + start_time = time.time() + self.socketIO.wait(timeout_in_seconds) + self.assertTrue(time.time() - start_time < timeout_in_seconds) + + def test_namespace_emit(self): + 'Behave differently in different namespaces' + main_namespace = self.socketIO.define(Namespace) + chat_namespace = self.socketIO.define(Namespace, '/chat') + news_namespace = self.socketIO.define(Namespace, '/news') + news_namespace.emit('emit_with_payload', PAYLOAD) + self.socketIO.wait(self.wait_time_in_seconds) + self.assertEqual(main_namespace.args_by_event, {}) + self.assertEqual(chat_namespace.args_by_event, {}) + self.assertEqual(news_namespace.args_by_event, { + 'emit_with_payload_response': (PAYLOAD,), + }) + + def test_namespace_ack(self): + 'Trigger server callback' + chat_namespace = self.socketIO.define(Namespace, '/chat') + chat_namespace.emit('trigger_server_expects_callback', PAYLOAD) + self.socketIO.wait(self.wait_time_in_seconds) + self.assertEqual(chat_namespace.args_by_event, { + 'server_expects_callback': (PAYLOAD,), + 'server_received_callback': (PAYLOAD,), + }) + def on_response(self, *args): for arg in args: if isinstance(arg, dict): @@ -99,14 +156,6 @@ class BaseMixin(object): self.called_on_response = True -# class Test_WebsocketTransport(TestCase, BaseMixin): - - # def setUp(self): - # super(Test_WebsocketTransport, self).setUp() - # self.socketIO = SocketIO(HOST, PORT, transports=['websocket']) - # self.wait_time_in_seconds = 0.1 - - class Test_XHR_PollingTransport(TestCase, BaseMixin): def setUp(self): diff --git a/socketIO_client/transports.py b/socketIO_client/transports.py index f917b8a..12a97b8 100644 --- a/socketIO_client/transports.py +++ b/socketIO_client/transports.py @@ -17,10 +17,10 @@ class AbstractTransport(object): self.url = url self.engineIO_session = engineIO_session - def send_packet(self, engineIO_packet_type, engineIO_packet_data): + def recv_packet(self): pass - def recv_packet(self): + def send_packet(self, engineIO_packet_type, engineIO_packet_data): pass