changeset 174:c158ad24ef3c

moved irc connection interval handling to irclib Signed-off-by: Charly COSTE <changaco@changaco.net>
author Charly COSTE <changaco@changaco.net>
date Thu, 04 Feb 2010 21:02:36 +0100
parents 6c4aaf8f3733
children 8378da7844f2
files bridge.py irclib.py participant.py
diffstat 3 files changed, 65 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- 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:
--- 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
 
--- 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)