[telepathy-ashes/master] Mechanism to request channel with handler class.

David Laban david.laban at collabora.co.uk
Wed Oct 14 10:59:26 PDT 2009


Many functions now take an optional handler_class argument, which
can be used to override the class from _handler_classes.
There is also a create_channel(request, handler_class) convenience
function.
---
 ashes/tools/dispatchers.py |   59 +++++++++++++++++++++++++++++++++++---------
 ashes/tools/groups.py      |    4 +-
 2 files changed, 49 insertions(+), 14 deletions(-)

diff --git a/ashes/tools/dispatchers.py b/ashes/tools/dispatchers.py
index 43b9ad9..72f5bec 100644
--- a/ashes/tools/dispatchers.py
+++ b/ashes/tools/dispatchers.py
@@ -12,7 +12,6 @@ from helper_functions import (get_connections, get_property,
 # garbage collected.
 # Should probably be sets but I'll leave it like this for now.
 connections = []
-channels = []
 
 
 class ChannelDispatcher(ConnectionListener):
@@ -27,8 +26,14 @@ class ChannelDispatcher(ConnectionListener):
     REQUESTS = telepathy.interfaces.CONNECTION_INTERFACE_REQUESTS
     CAPS = telepathy.interfaces.CONNECTION_INTERFACE_CAPABILITIES
 
+    # FIXME: This dict looks like a class variable, but is shadowed by an
+    # instance variable later. This is massively confusing.
     _handler_classes = {}
 
+    # This list really is a class variable. The reason for this is to avoid
+    # two instances of the dispatcher handling the same channel.
+    channels = []
+
     def _collect_handler_classes(self):
         """
         This function collects handler classes registered to subclasses/
@@ -61,8 +66,9 @@ class ChannelDispatcher(ConnectionListener):
 
     def finish_setup(self, *conn):
         """
-        Sets up super-classes recursively, then sets capabilities
-        FIXME: do caps based on _handler_classes rather than hardcoded.
+        Sets up super-classes recursively.
+        Note that setting capabilities is done in dispatch_initial_channels,
+        after the connection has told us that it is online.
         """
         super(ChannelDispatcher, self).finish_setup()
 
@@ -75,6 +81,10 @@ class ChannelDispatcher(ConnectionListener):
         super(ChannelDispatcher, self).StatusChanged(status, reason)
 
     def dispatch_initial_channels(self):
+        """
+        Tells the connection manager what capabilities we support, and asks it
+        what channels it already has (reply handled by self.NewChannels).
+        """
         handler_classes = self._collect_handler_classes()
         caps = []
         for (chantype, handletype), handler_class in handler_classes.items():
@@ -96,18 +106,26 @@ class ChannelDispatcher(ConnectionListener):
         get_property(self.connection, telepathy.CONNECTION_INTERFACE_REQUESTS,
             'Channels', reply_handler=self.NewChannels, error_handler=printer)
 
-    #@shiny.debug_exceptions
     def NewChannels(self, Channels):
         """
         Callback for Requests.NewChannels.
         """
         for object_path, properties in Channels:
-            cb = rpartial(self.dispatch_channel, properties)
-            telepathy.client.Channel(self.connection.service_name,
-                                    object_path,
-                                    ready_handler=cb)
+            self._new_channel(object_path, properties)
 
-    def dispatch_channel(self, channel, properties):
+    def _new_channel(self, object_path, properties, handler_class=None):
+        """
+        Gets called for each new channel in NewChannels, and also as the reply
+        callback of create_channel.
+
+        handler_class can be used to override the default handler class.
+        """
+        cb = rpartial(self.dispatch_channel, properties, handler_class)
+        telepathy.client.Channel(self.connection.service_name,
+                                object_path,
+                                ready_handler=cb)
+
+    def dispatch_channel(self, channel, properties, handler_class=None):
         """
         Gets called for each channel in a NewChannels signal.
         The channel is guaranteed to be "ready" at this point.
@@ -117,7 +135,7 @@ class ChannelDispatcher(ConnectionListener):
         handle = properties['org.freedesktop.Telepathy.Channel.TargetHandle']
         requested = properties['org.freedesktop.Telepathy.Channel.Requested']
         id = properties['org.freedesktop.Telepathy.Channel.TargetID']
-        # Hrrrm. This optimisation is probably not very general.
+        # FIXME. This optimisation is probably not very general.
         # Don't be putting it in any libraries.
         if handle_type == telepathy.HANDLE_TYPE_CONTACT:
             if re.match(self.contact_regexp, id):
@@ -130,13 +148,30 @@ class ChannelDispatcher(ConnectionListener):
             else:
                 print id, 'does not match', self.contact_regexp
                 return
+        if channel in self.channels:
+            print "Channel already handled:", channel.object_path
 
-        if (channel_type, handle_type) in self._handler_classes:
+        if handler_class is not None:
+            # FIXME: split this out into its own function.
+            handler = handler_class(self, channel, properties)
+            self.channels.append(handler)
+        elif (channel_type, handle_type) in self._handler_classes:
             handler_class = self._handler_classes[channel_type, handle_type]
             handler = handler_class(self, channel, properties)
-            channels.append(handler)
+            self.channels.append(handler)
             return handler
         else:
             print "Don't know how to handle channel with handle type:", handle_type,
             print "and channel type", channel_type
 
+    def create_channel(self, request, handler_class=None, error_handler=printer):
+        """
+        Calls CreateChannel, and uses handler_class as the handler, if provided,
+        or uses the default as found in self._handler_classes.
+        Passing in a handler class will cause the NewChannels signal to be
+        ignored for this channel, as it will have already been handled.
+        """
+        cb = rpartial(self._new_channel, handler_class)
+        self.connection[telepathy.interfaces.CONNECTION_INTERFACE_REQUESTS
+            ].CreateChannel(request, reply_handler=cb, error_handler=error_handler)
+
diff --git a/ashes/tools/groups.py b/ashes/tools/groups.py
index 7fc2c9e..6d04655 100644
--- a/ashes/tools/groups.py
+++ b/ashes/tools/groups.py
@@ -141,12 +141,12 @@ class ContactSubscriber(ChannelDispatcher):
         super(ContactSubscriber, self).__init__(*args, **kwargs)
         self.contact_list_handlers = {}
 
-    def dispatch_channel(self, channel, properties):
+    def dispatch_channel(self, *args):
         """
         Adds a special case to ContactAcceptor classes (which handle magic
         ContactList groups like publish and subscribe).
         """
-        handler = super(ContactSubscriber, self).dispatch_channel(channel, properties)
+        handler = super(ContactSubscriber, self).dispatch_channel(*args)
         if isinstance(handler, ContactAcceptor):
             self.register_contact_list_handler(handler)
         return handler
-- 
1.5.6.5




More information about the telepathy-commits mailing list