diff irclib.py @ 260:9a2302e8382b

(irclib) created a "Channel" class Signed-off-by: Charly COSTE <changaco@changaco.net>
author Charly COSTE <changaco@changaco.net>
date Sat, 13 Mar 2010 17:38:47 +0100
parents e64b574afa8f
children 53f4d9aa2b52
line wrap: on
line diff
--- a/irclib.py
+++ b/irclib.py
@@ -410,6 +410,56 @@ class IRC:
         if self.fn_to_remove_socket:
             self.fn_to_remove_socket(connection._get_socket())
 
+
+LEFT, LEAVING, NOT_IN, JOINING, JOINED = range(5)
+
+class Channel:
+
+    def __init__(self, connection, channel_name):
+        self.connection = connection
+        self.channel_name = channel_name
+        self.callbacks = []
+        self.state = NOT_IN
+
+    def _callback(self, error):
+        if not error:
+            self.state = JOINED
+        else:
+            self.state = NOT_IN
+        m = 'channel "'+self.channel_name+'" on connection "'+str(self.connection)+'"'
+        if len(self.callbacks) == 0:
+            self.connection.irclibobj.bot.error(1, 'no join callback for '+m, debug=True)
+        else:
+            self.connection.irclibobj.bot.error(1, 'calling '+str(len(self.callbacks))+' join callback(s) for '+m, debug=True)
+            for f in self.callbacks:
+                f(self.channel_name, error)
+
+    def add_callback(self, callback):
+        if callback and not callback in self.callbacks:
+            self.callbacks.append(callback)
+
+    def join(self, key=None, callback=None):
+        self.state = JOINING
+        self.key = key
+        self.add_callback(callback)
+        self.connection.send_raw("JOIN %s%s" % (self.channel_name, (key and (" " + key))))
+
+    def part(self, message=None):
+        if self.state <= NOT_IN:
+            return
+        self.state = LEAVING
+        self.connection.send_raw("PART " + self.channel_name + (message and (" " + message)))
+
+    def rejoin(self):
+        self.join(key=self.key)
+
+    def remove_callback(self, callback):
+        try:
+            self.callbacks.remove(callback)
+        except ValueError:
+            pass
+
+
 _rfc_1459_command_regexp = re.compile("^(:(?P<prefix>[^ ]+) +)?(?P<command>[^ ]+)( *(?P<argument> .+))?")
 
 class Connection:
@@ -464,9 +514,7 @@ class ServerConnection(Connection):
         self.nick_callbacks = []
         self.join_callbacks = {}
         self.lock = threading.RLock()
-        self.left_channels = []
-        self.channels = []
-        self.channels_keys = {}
+        self.channels = {}
         self.irc_id = None
         self.previous_buffer = ""
         self.handlers = {}
@@ -594,12 +642,8 @@ class ServerConnection(Connection):
         
         # Rejoin channels
         if len(self.channels) > 0:
-            for channel in self.channels:
-                if self.channels_keys.has_key(channel):
-                    key = self.channels_keys[channel]
-                else:
-                    key = ''
-                self.join(channel, key=key)
+            for channel in self.channels.itervalues():
+                channel.rejoin()
         
         self.lock.release()
         return self
@@ -615,19 +659,6 @@ class ServerConnection(Connection):
         self.nick_callbacks = []
 
 
-    def _call_join_callbacks(self, channel, error):
-        self.lock.acquire()
-        m = 'channel "'+channel+'" on connection "'+str(self)+'"'
-        if not self.join_callbacks.has_key(channel) or len(self.join_callbacks[channel]) == 0:
-            self.irclibobj.bot.error(1, 'no join callback for '+m, debug=True)
-        else:
-            self.irclibobj.bot.error(1, 'calling '+str(len(self.join_callbacks[channel]))+' join callback(s) for '+m, debug=True)
-            for f in self.join_callbacks[channel]:
-                f(channel, error)
-        self.join_callbacks.pop(channel, None)
-        self.lock.release()
-
-
     def add_nick_callback(self, callback):
         self.nick_callbacks.append(callback)
 
@@ -797,14 +828,11 @@ class ServerConnection(Connection):
                         if DEBUG:
                             print "irc_id: %s" % (prefix)
                     channel = target.lower()
-                    if not channel in self.channels:
-                        self.channels.append(channel)
-                        if channel in self.left_channels:
-                            self.left_channels.remove(channel)
-                        self._call_join_callbacks(channel, None)
+                    if self.channels[channel].state != JOINED:
+                        self.channels[channel]._callback(None)
 
                 if command in ['inviteonlychan', 'bannedfromchan', 'channelisfull', 'badchannelkey']:
-                    self._call_join_callbacks(arguments[0].lower(), command)
+                    self.channels[arguments[0].lower()]._callback(command)
 
                 if DEBUG:
                     print "command: %s, source: %s, target: %s, arguments: %s" % (
@@ -914,13 +942,11 @@ class ServerConnection(Connection):
         """
         self.send_raw("ISON " + " ".join(nicks))
 
-    def join(self, channel, callback=None, key=""):
+    def join(self, channel_name, callback=None, key=""):
         """Send a JOIN command."""
-        if callback:
-            self.add_join_callback(channel, callback)
-        if key:
-            self.channels_keys[channel] = key
-        self.send_raw("JOIN %s%s" % (channel, (key and (" " + key))))
+        if not self.channels.has_key(channel_name):
+            self.channels[channel_name] = Channel(self, channel_name)
+        self.channels[channel_name].join(key=key, callback=callback)
 
     def kick(self, channel, nick, comment=""):
         """Send a KICK command."""
@@ -984,23 +1010,15 @@ class ServerConnection(Connection):
     def oper(self, nick, password):
         """Send an OPER command."""
         self.send_raw("OPER %s %s" % (nick, password))
-    
-    def _remove_channel(self, channel):
-        if channel in self.channels:
-            self.channels.remove(channel)
-        if not channel in self.left_channels:
-            self.left_channels.append(channel)
 
     def part(self, channels, message=""):
         """Send a PART command."""
         try:
             if isinstance(channels, basestring):
-                self._remove_channel(channels)
-                self.send_raw("PART " + channels + (message and (" " + message)))
+                self.channels[channels].part(message=message)
             else:
                 for channel in channels:
-                    self._remove_channel(channel)
-                self.send_raw("PART " + ",".join(channels) + (message and (" " + message)))
+                    self.channels[channel].part(message=message)
         except ServerNotConnectedError:
             self.disconnect(volontary=True)
             self.connect()