Refactored the Socket driver, hopefully to resolve the currently outstanding bugs (#1156765 and #1097217) with it.

This commit is contained in:
Jeremy Fincher 2005-05-19 23:39:19 +00:00
parent 6986bbad16
commit 8730832e69

View File

@ -45,9 +45,6 @@ import supybot.drivers as drivers
import supybot.schedule as schedule import supybot.schedule as schedule
from supybot.utils.iter import imap from supybot.utils.iter import imap
# XXX Shouldn't the reconnect wait (at least the last one) be configurable?
reconnectWaits = [0, 60, 300]
class SocketDriver(drivers.IrcDriver, drivers.ServersMixin): class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
def __init__(self, irc): def __init__(self, irc):
self.irc = irc self.irc = irc
@ -61,20 +58,28 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
self.zombie = False self.zombie = False
self.scheduled = None self.scheduled = None
self.connected = False self.connected = False
self.reconnectWaitsIndex = 0 self.resetDelay()
self.reconnectWaits = reconnectWaits # Only connect to non-SSL servers
#Only connect to non-SSL servers
if self.networkGroup.get('ssl').value: if self.networkGroup.get('ssl').value:
drivers.log.error('The Socket driver can not connect to SSL ' drivers.log.error('The Socket driver can not connect to SSL '
'servers. Try the Twisted driver instead.') 'servers. Try the Twisted driver instead.')
else: else:
self.connect() self.connect()
def getDelay(self):
ret = self.currentDelay
self.currentDelay = min(self.currentDelay * 2,
conf.supybot.drivers.maxReconnectWait())
return ret
def resetDelay(self):
self.currentDelay = 10.0
def _getNextServer(self): def _getNextServer(self):
oldServer = getattr(self, 'currentServer', None) oldServer = getattr(self, 'currentServer', None)
server = self.__parent._getNextServer() server = self.__parent._getNextServer()
if self.currentServer != oldServer: if self.currentServer != oldServer:
self.reconnectWaitsIndex = 0 self.resetDelay()
return server return server
def _handleSocketError(self, e): def _handleSocketError(self, e):
@ -82,7 +87,7 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
# hasn't finished yet. We'll keep track of how many we get. # hasn't finished yet. We'll keep track of how many we get.
if e.args[0] != 11 and self.eagains > 120: if e.args[0] != 11 and self.eagains > 120:
drivers.log.disconnect(self.currentServer, e) drivers.log.disconnect(self.currentServer, e)
self.reconnect(wait=True) self.scheduleReconnect()
else: else:
log.debug('Got EAGAIN, current count: %s.', self.eagains) log.debug('Got EAGAIN, current count: %s.', self.eagains)
self.eagains += 1 self.eagains += 1
@ -113,7 +118,7 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
self._sendIfMsgs() self._sendIfMsgs()
try: try:
self.inbuffer += self.conn.recv(1024) self.inbuffer += self.conn.recv(1024)
self.eagains = 0 self.eagains = 0 # If we successfully recv'ed, we can reset this.
lines = self.inbuffer.split('\n') lines = self.inbuffer.split('\n')
self.inbuffer = lines.pop() self.inbuffer = lines.pop()
for line in lines: for line in lines:
@ -131,8 +136,8 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
def connect(self, **kwargs): def connect(self, **kwargs):
self.reconnect(reset=False, **kwargs) self.reconnect(reset=False, **kwargs)
def reconnect(self, wait=False, reset=True): def reconnect(self, reset=True):
self.scheduled = False self.scheduled = None
if self.connected: if self.connected:
drivers.log.reconnect(self.irc.network) drivers.log.reconnect(self.irc.network)
self.conn.close() self.conn.close()
@ -142,9 +147,6 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
self.irc.reset() self.irc.reset()
else: else:
drivers.log.debug('Not resetting %s.', self.irc) drivers.log.debug('Not resetting %s.', self.irc)
if wait:
self._scheduleReconnect()
return
server = self._getNextServer() server = self._getNextServer()
drivers.log.connect(self.currentServer) drivers.log.connect(self.currentServer)
try: try:
@ -153,18 +155,16 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
self.conn.bind((vhost, 0)) self.conn.bind((vhost, 0))
except socket.error, e: except socket.error, e:
drivers.log.connectError(self.currentServer, e) drivers.log.connectError(self.currentServer, e)
if self.reconnectWaitsIndex < len(self.reconnectWaits)-1: self.scheduleReconnect()
self.reconnectWaitsIndex += 1
self.reconnect(wait=True)
return return
# We allow more time for the connect here, since it might take longer. # We allow more time for the connect here, since it might take longer.
# At least 10 seconds. # At least 10 seconds.
self.conn.settimeout(max(10, conf.supybot.drivers.poll()*10)) self.conn.settimeout(max(10, conf.supybot.drivers.poll()*10))
if self.reconnectWaitsIndex < len(self.reconnectWaits)-1:
self.reconnectWaitsIndex += 1
try: try:
self.conn.connect(server) self.conn.connect(server)
self.conn.settimeout(conf.supybot.drivers.poll()) self.conn.settimeout(conf.supybot.drivers.poll())
self.connected = True
self.resetDelay()
except socket.error, e: except socket.error, e:
if e.args[0] == 115: if e.args[0] == 115:
now = time.time() now = time.time()
@ -175,10 +175,8 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
schedule.addEvent(self._checkAndWriteOrReconnect, when) schedule.addEvent(self._checkAndWriteOrReconnect, when)
else: else:
drivers.log.connectError(self.currentServer, e) drivers.log.connectError(self.currentServer, e)
self.reconnect(wait=True) self.scheduleReconnect()
return return
self.connected = True
self.reconnectWaitPeriodsIndex = 0
def _checkAndWriteOrReconnect(self): def _checkAndWriteOrReconnect(self):
drivers.log.debug('Checking whether we are connected.') drivers.log.debug('Checking whether we are connected.')
@ -186,15 +184,21 @@ class SocketDriver(drivers.IrcDriver, drivers.ServersMixin):
if w: if w:
drivers.log.debug('Socket is writable, it might be connected.') drivers.log.debug('Socket is writable, it might be connected.')
self.connected = True self.connected = True
self.reconnectWaitPeriodsIndex = 0 self.resetDelay()
else: else:
drivers.log.connectError(self.currentServer, 'Timed out') drivers.log.connectError(self.currentServer, 'Timed out')
self.reconnect() self.reconnect()
def _scheduleReconnect(self): def scheduleReconnect(self):
when = time.time() + self.reconnectWaits[self.reconnectWaitsIndex] when = time.time() + self.getDelay()
if not world.dying: if not world.dying:
drivers.log.reconnect(self.irc.network, when) drivers.log.reconnect(self.irc.network, when)
if self.scheduled:
drivers.log.error('Scheduling a second reconnect when one is '
'already scheduled. This is a bug; please '
'report it, with an explanation of what caused '
'this to happen.')
schedule.removeEvent(self.scheduled)
self.scheduled = schedule.addEvent(self.reconnect, when) self.scheduled = schedule.addEvent(self.reconnect, when)
def die(self): def die(self):