Exit the loop if the client wants to disconnect; fixes #30

This commit is contained in:
Roy Hyunjin Han 2013-11-18 10:43:31 -08:00
commit 5ccb32f338
6 changed files with 46 additions and 7 deletions

View file

@ -39,6 +39,9 @@ class BaseNamespace(object):
callback, args = find_callback(args, kw)
self._transport.emit(self.path, event, args, callback)
def disconnect(self):
self._transport.disconnect(self.path)
def on(self, event, callback):
'Define a callback to handle a custom event emitted by the server'
self._callback_by_event[event] = callback
@ -161,12 +164,14 @@ class SocketIO(object):
self._transport.emit(path, event, args, callback)
def wait(self, seconds=None, for_callbacks=False):
"""Wait in a loop and process events as defined in the namespaces.
- Omit seconds, i.e. call wait() without arguments, to wait forever.
"""
try:
warning_screen = _yield_warning_screen(seconds)
for elapsed_time in warning_screen:
try:
if for_callbacks and not self._transport.has_ack_callback:
break
try:
for packet in self._transport.recv_packet():
try:
@ -175,6 +180,8 @@ class SocketIO(object):
_log.warn('[packet error] %s', e)
except TimeoutError:
pass
if self._stop_waiting(for_callbacks):
break
self.heartbeat_pacemaker.send(elapsed_time)
except ConnectionError as e:
try:
@ -186,6 +193,14 @@ class SocketIO(object):
except KeyboardInterrupt:
pass
def _stop_waiting(self, for_callbacks):
# Use __transport to make sure that we do not reconnect inadvertently
if for_callbacks and not self.__transport.has_ack_callback:
return True
if self.__transport._wants_to_disconnect:
return True
return False
def wait_for_callbacks(self, seconds=None):
self.wait(seconds, for_callbacks=True)

View file

@ -1,4 +1,5 @@
import logging
import time
from unittest import TestCase
from . import SocketIO, BaseNamespace, find_callback
@ -109,15 +110,15 @@ class BaseMixin(object):
def test_emit_with_callback_with_payload(self):
'Emit with callback with payload'
self.socketIO.emit('emit_with_callback_with_payload',
self.on_response)
self.socketIO.emit(
'emit_with_callback_with_payload', self.on_response)
self.socketIO.wait_for_callbacks(seconds=self.wait_time_in_seconds)
self.assertTrue(self.called_on_response)
def test_emit_with_callback_with_multiple_payloads(self):
'Emit with callback with multiple payloads'
self.socketIO.emit('emit_with_callback_with_multiple_payloads',
self.on_response)
self.socketIO.emit(
'emit_with_callback_with_multiple_payloads', self.on_response)
self.socketIO.wait_for_callbacks(seconds=self.wait_time_in_seconds)
self.assertTrue(self.called_on_response)
@ -138,6 +139,15 @@ class BaseMixin(object):
'ack_callback_response': (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)
@ -204,3 +214,6 @@ class Namespace(BaseNamespace):
if callback:
callback(*args)
self.args_by_event[event] = args
def on_wait_with_disconnect_response(self):
self.disconnect()

View file

@ -22,8 +22,11 @@ class _AbstractTransport(object):
def __init__(self):
self._packet_id = 0
self._callback_by_packet_id = {}
self._wants_to_disconnect = False
def disconnect(self, path=''):
if not path:
self._wants_to_disconnect = True
if not self.connected:
return
if path: