# HG changeset patch # User Charly COSTE # Date 1265313756 -3600 # Node ID c158ad24ef3c3b13360c8a984759da8b0608f6e4 # Parent 6c4aaf8f3733bbae86e62d89f47f22277c51f184 moved irc connection interval handling to irclib Signed-off-by: Charly COSTE diff --git a/bridge.py b/bridge.py --- a/bridge.py +++ b/bridge.py @@ -42,7 +42,7 @@ class Bridge: class NoSuchParticipantException(Exception): pass - def __init__(self, owner_bot, xmpp_room_jid, irc_room, irc_server, mode, say_level, irc_port=6667, irc_connection_interval=1, irc_charsets=None): + def __init__(self, owner_bot, xmpp_room_jid, irc_room, irc_server, mode, say_level, irc_port=6667, irc_connection_interval=None, irc_charsets=None): """Create a new bridge.""" self.bot = owner_bot self.irc_server = irc_server @@ -67,21 +67,12 @@ class Bridge: def init2(self): # Join XMPP room - try: - self.xmpp_room = xmpp.muc(self.xmpp_room_jid) - self.xmpp_room.join(self.bot.xmpp_c, self.bot.nickname, callback=self._xmpp_join_callback) - except: - self.bot.error('[Error] joining XMPP room failed') - raise + self.xmpp_room = xmpp.muc(self.xmpp_room_jid) + self.xmpp_room.join(self.bot.xmpp_c, self.bot.nickname, callback=self._xmpp_join_callback) # Join IRC room - try: - self.irc_connections_limit = -1 - self.irc_connection = self.bot.irc.open_connection(self.irc_server, self.irc_port, self.bot.nickname) - self.irc_connection.connect(nick_callback=self._irc_nick_callback, charsets=self.irc_charsets) - except: - self.bot.error('[Error] joining IRC room failed') - raise + self.irc_connection = self.bot.irc.open_connection(self.irc_server, self.irc_port, self.bot.nickname, delay=self.irc_connection_interval) + self.irc_connection.connect(nick_callback=self._irc_nick_callback, charsets=self.irc_charsets) self.bot.error('[Notice] bridge "'+str(self)+'" is running in '+self.mode+' mode and a say_level of "'+self.__class__._say_levels[self.say_level]+'"') @@ -93,6 +84,8 @@ class Bridge: self.irc_connection.join(self.irc_room) self.bot.error('===> Debug: successfully connected on IRC side of bridge "'+str(self)+'"', debug=True) self.say('[Notice] bridge "'+str(self)+'" is running in '+self.mode+' mode', on_xmpp=False) + if self.mode not in ['normal', 'bypass']: + self.show_participants_list_on(protocols=['irc']) else: self.mode = None if self.xmpp_room.connected == True: @@ -385,7 +378,7 @@ class Bridge: def show_participants_list_on(self, protocols=[]): - if 'irc' in protocols: + if 'irc' in protocols and self.irc_connection.really_connected: xmpp_participants_nicknames = self.get_participants_nicknames_list(protocols=['xmpp']) self.say('[Info] Participants on XMPP: '+' '.join(xmpp_participants_nicknames), on_xmpp=False) if 'xmpp' in protocols: diff --git a/irclib.py b/irclib.py --- a/irclib.py +++ b/irclib.py @@ -164,9 +164,34 @@ class IRC: self.handlers = {} self.delayed_commands = [] # list of tuples in the format (time, function, arguments) self.charsets = {'': ['utf-8']} + self.connection_intervals = {'': 1} + self.connection_stacks = {} self.add_global_handler("ping", _ping_ponger, -42) + + def _connection_loop(self, server_str): + stack = self.connection_stacks[server_str] + if len(stack) > 0: + stack[0][0](*stack[0][1]) + stack.pop(0) + delay = self.connection_interval(server=server_str) + self.bot.error('==> Debug: waiting '+str(delay)+' seconds before next connection on '+server_str, debug=True) + self.execute_delayed(delay, self._connection_loop, (server_str,)) + else: + self.connection_stacks.pop(server_str) + + + def connection_interval(self, server='', seconds=None): + if seconds: + self.connection_intervals[server] = seconds + return seconds + elif self.connection_intervals.has_key(server): + return self.connection_intervals[server] + else: + return self.connection_intervals[''] + + def get_connection(self, server, port, nickname): for c in self.connections: if c.server == server and c.port == port and c.real_nickname == nickname: @@ -178,7 +203,7 @@ class IRC: return True return False - def open_connection(self, server, port, nickname): + def open_connection(self, server, port, nickname, delay=None): """Creates or returns an existing ServerConnection object for nickname at server:port. server -- Server name. @@ -191,6 +216,11 @@ class IRC: if c: return c c = ServerConnection(self, server, port, nickname) + server_str = c._server_str() + if not self.connection_stacks.has_key(server_str): + self.connection_stacks[server_str] = [] + delay = self.connection_interval(server=server_str, seconds=delay) + self.execute_delayed(delay, self._connection_loop, (server_str,)) self.connections.append(c) return c @@ -414,12 +444,13 @@ class ServerConnection(Connection): Connection.__init__(self, irclibobj) self.connected = False # Not connected yet. self.really_connected = False - self.used_by = 1 + self.used_by = 0 self.socket = None self.ssl = None self.server = server self.port = port self.nickname = nickname + self.nick_callbacks = [] self.lock = threading.RLock() self.left_channels = [] @@ -477,20 +508,21 @@ class ServerConnection(Connection): self.lock.acquire() - if self.connected == True: + if nick_callback: + self.add_nick_callback(nick_callback) + + if self.used_by > 0: self.used_by += 1 self.irclibobj.bot.error('===> Debug: using existing IRC connection for '+self.__str__()+', this connection is now used by '+str(self.used_by)+' bridges', debug=True) - if nick_callback != None: - self.add_nick_callback(nick_callback) if self.really_connected: self._call_nick_callbacks(None) self.lock.release() return self if self.socket != 'closed': + self.used_by = 1 if charsets or not self.irclibobj.charsets.has_key(self._server_str()): self.irclibobj.charsets[self._server_str()] = charsets - self.nick_callbacks = [] self.irc_id = None self.previous_buffer = "" self.handlers = {} @@ -502,21 +534,34 @@ class ServerConnection(Connection): self.localaddress = localaddress self.localport = localport self.localhost = socket.gethostname() + self.ssl = ssl + self.ipv6 = ipv6 + self.irclibobj.connection_stacks[self._server_str()].append( (self._connect, ()) ) + + self.lock.release() + return self + + + def _connect(self): + + self._ping() + + self.lock.acquire() + + if self.socket != 'closed': self.irclibobj.bot.error('===> Debug: opening new IRC connection for '+self.__str__(), debug=True) else: self.irclibobj.bot.error('===> Debug: reopening IRC connection for '+self.__str__(), debug=True) - self._ping() - - if ipv6: + if self.ipv6: self.socket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) else: self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: self.socket.bind((self.localaddress, self.localport)) self.socket.connect((self.server, self.port)) - if ssl: + if self.ssl: self.ssl = socket.ssl(self.socket) except socket.error, x: self.socket.close() @@ -529,8 +574,9 @@ class ServerConnection(Connection): # Log on... if self.password: self.pass_(self.password) - if self.nick(self.nickname, callback=nick_callback) == True: + if self.nick(self.nickname): self.user(self.username, self.ircname) + self.lock.release() return self diff --git a/participant.py b/participant.py --- a/participant.py +++ b/participant.py @@ -107,7 +107,6 @@ class Participant: def createDuplicateOnIRC(self): if isinstance(self.xmpp_c, xmpp.client.Client) or isinstance(self.irc_connection, ServerConnection): return - sleep(self.bridge.irc_connection_interval) # to prevent "reconnecting too fast" self.irc_connection = self.bridge.bot.irc.open_connection(self.bridge.irc_server, self.bridge.irc_port, self.duplicate_nickname) self.irc_connection.connect(nick_callback=self._irc_nick_callback)