Browse Source

Reworked reconnect code #24

* reconnect is no longer done automatically
* added `reconnect` method to SteamClient implementing exp backoff
pull/34/head
Rossen Georgiev 9 years ago
parent
commit
7af1c66938
  1. 21
      steam/client/__init__.py
  2. 33
      steam/core/cm.py

21
steam/client/__init__.py

@ -22,6 +22,7 @@ class SteamClient(CMClient, BuiltinBase):
See `gevent-eventmitter <https://github.com/rossengeorgiev/gevent-eventemitter>`_
for details on how to work with events.
"""
_reconnect_backoff_c = 0
current_jobid = 0
credential_location = None #: location for sentry
username = None #: username when logged on
@ -86,6 +87,7 @@ class SteamClient(CMClient, BuiltinBase):
result = EResult(msg.body.eresult)
if result == EResult.OK:
self._reconnect_backoff_c = 0
self.logged_on = True
self.set_persona(EPersonaState.Online)
self.emit("logged_on")
@ -134,6 +136,25 @@ class SteamClient(CMClient, BuiltinBase):
self.send(resp)
def reconnect(self, maxdelay=30, retry=0):
"""Implements explonential backoff delay before attempting to connect.
It is otherwise identical to calling :meth:`steam.core.cm.CMClient.connect`.
The delay is reset upon a successful login.
:param maxdelay: maximum delay in seconds before connect (0-120s)
:type maxdelay: :class:`int`
:param retry: see :meth:`steam.core.cm.CMClient.connect`
:type retry: :class:`int`
:return: successful connection
:rtype: :class:`bool`
"""
delay_seconds = 2**self._reconnect_backoff_c - 1
if delay_seconds < maxdelay:
self._reconnect_backoff_c = min(7, self._reconnect_backoff_c + 1)
return self.connect(delay=delay_seconds, retry=retry)
def send(self, message):
"""
Send a message to CM

33
steam/core/cm.py

@ -50,7 +50,6 @@ class CMClient(EventEmitter):
_recv_loop = None
_heartbeat_loop = None
_reconnect_backoff_c = 0
_LOG = None
def __init__(self, protocol=0):
@ -72,11 +71,13 @@ class CMClient(EventEmitter):
self._LOG.debug("Emit event: %s" % repr(event))
super(CMClient, self).emit(event, *args)
def connect(self, retry=None):
def connect(self, retry=None, delay=0):
"""Initiate connection to CM. Blocks until connected unless ``retry`` is specified.
:param retry: number of retries before returning. Unlimited when set to ``None``
:type retry: :class:`int`
:param delay: delay in secnds before connection attempt
:type delay: :class:`int`
:return: successful connection
:rtype: :class:`bool`
"""
@ -88,6 +89,10 @@ class CMClient(EventEmitter):
return
self._connecting = True
if delay:
self._LOG.debug("Delayed connect: %d seconds" % delay)
gevent.sleep(delay)
self._LOG.debug("Connect initiated.")
for i, server_addr in enumerate(self.servers):
@ -113,7 +118,7 @@ class CMClient(EventEmitter):
self._connecting = False
return True
def disconnect(self, reconnect=False, nodelay=False):
def disconnect(self):
"""Close connection
.. note::
@ -145,20 +150,7 @@ class CMClient(EventEmitter):
self._reset_attributes()
if reconnect:
if nodelay:
delay_seconds = 0
self._reconnect_backoff_c = 0
else:
delay_seconds = 2**self._reconnect_backoff_c - 1
self._reconnect_backoff_c = min(5, self._reconnect_backoff_c + 1)
self.emit('reconnect', delay_seconds)
gevent.spawn_later(delay_seconds, self.connect)
else:
self._reconnect_backoff_c = 0
self.emit('disconnected')
self.emit('disconnected')
def _reset_attributes(self):
for name in ['connected',
@ -286,14 +278,14 @@ class CMClient(EventEmitter):
if result is None:
self.servers.mark_bad(self.current_server_addr)
gevent.spawn(self.disconnect, True)
gevent.spawn(self.disconnect)
return
eresult = result[0].body.eresult
if eresult != EResult.OK:
self._LOG.error("Failed to secure channel: %s" % eresult)
gevent.spawn(self.disconnect, True)
gevent.spawn(self.disconnect)
return
self.channel_key = key
@ -345,10 +337,9 @@ class CMClient(EventEmitter):
EResult.ServiceUnavailable
):
self.servers.mark_bad(self.current_server_addr)
self.disconnect(True)
self.disconnect()
elif result == EResult.OK:
self._seen_logon = True
self._reconnect_backoff_c = 0
self._LOG.debug("Logon completed")

Loading…
Cancel
Save