X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=src%2Ftp%2Fchannelmanager.py;h=d5e2bce9e4c26f494ef47eae0b6ba6752e46be50;hb=7ebb6c3f8cc7d5c9c0eba63a12ef859dc5241b9a;hp=17cef3975059083db985c70aa54f75054be6f6a3;hpb=3ae1df25c091b2bfb6b88b1d4023b868e63ce92f;p=theonering diff --git a/src/tp/channelmanager.py b/src/tp/channelmanager.py index 17cef39..d5e2bce 100644 --- a/src/tp/channelmanager.py +++ b/src/tp/channelmanager.py @@ -1,6 +1,6 @@ # telepathy-python - Base classes defining the interfaces of the Telepathy framework # -# Copyright (C) 2009 Collabora Limited +# Copyright (C) 2009-2010 Collabora Limited # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -16,84 +16,157 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +import warnings + from telepathy.errors import NotImplemented from telepathy.interfaces import (CHANNEL_INTERFACE, - CHANNEL_TYPE_CONTACT_LIST, - CHANNEL_TYPE_TEXT) + CHANNEL_TYPE_CONTACT_LIST) -class ChannelManager(object): +from telepathy.constants import HANDLE_TYPE_NONE + +from handle import NoneHandle +class ChannelManager(object): def __init__(self, connection): self._conn = connection - self._requestable_channel_classes = dict() + self._requestable_channels = dict() self._channels = dict() + self._fixed_properties = dict() self._available_properties = dict() + self._requestables = dict() + def close(self): - for channel_type in self._requestable_channel_classes: - for channel in self._channels[channel_type].values(): - if channel._type == CHANNEL_TYPE_CONTACT_LIST: - channel.remove_from_connection() - else: - channel.Close() + """Close channel manager and all the existing channels.""" + for channel_type in self._requestable_channels: + for channels in self._channels[channel_type].values(): + for channel in channels: + if channel._type == CHANNEL_TYPE_CONTACT_LIST: + channel.remove_from_connection() + else: + channel.Close() def remove_channel(self, channel): - for channel_type in self._requestable_channel_classes: - for handle, chan in self._channels[channel_type].items(): - if channel == chan: - del self._channels[channel_type][handle] + "Remove channel from the channel manager" + for channel_type in self._requestable_channels: + for handle, channels in self._channels[channel_type].items(): + if channel in channels : + channels.remove(channel) def _get_type_requested_handle(self, props): + """Return the type, request and target handle from the requested + properties""" type = props[CHANNEL_INTERFACE + '.ChannelType'] requested = props[CHANNEL_INTERFACE + '.Requested'] - target_handle = int(props[CHANNEL_INTERFACE + '.TargetHandle']) - target_handle_type = int(props[CHANNEL_INTERFACE + '.TargetHandleType']) - handle = self._conn._handles[target_handle_type, target_handle] + target_handle_type = \ + props.get(CHANNEL_INTERFACE + '.TargetHandleType', HANDLE_TYPE_NONE) + + if target_handle_type == HANDLE_TYPE_NONE: + handle = NoneHandle() + else: + target_handle = props[CHANNEL_INTERFACE + '.TargetHandle'] + handle = self._conn._handles[target_handle_type, target_handle] return (type, requested, handle) - def channel_exists(self, props): + def existing_channel(self, props): + """ Return a channel corresponding to theses properties if such + one exists, otherwhise return None. Default implementation will + return the last created channel of the same kind identified by + handle and type. + Connection Manager should subclass this function + to implement more appropriate behaviour. """ + type, _, handle = self._get_type_requested_handle(props) if type in self._channels: if handle in self._channels[type]: - return True + if len(self._channels[type][handle]) > 0: + return self._channels[type][handle][-1] - return False + return None - def channel_for_props(self, props, signal=True, **args): + def channel_exists(self, props): + """ Return True if channel exist with theses props, False otherwhise""" + return self.existing_channel(props) != None + + def create_channel_for_props(self, props, signal=True, **args): + """Create a new channel with theses properties""" type, _, handle = self._get_type_requested_handle(props) - if type not in self._requestable_channel_classes: + if type not in self._requestable_channels: raise NotImplemented('Unknown channel type "%s"' % type) - if self.channel_exists(props): - return self._channels[type][handle] - - channel = self._requestable_channel_classes[type]( + channel = self._requestable_channels[type]( props, **args) self._conn.add_channels([channel], signal=signal) - self._channels[type][handle] = channel + if handle.get_type() != HANDLE_TYPE_NONE and type in self._channels: + self._channels[type].setdefault(handle, []).append(channel) return channel + def channel_for_props(self, props, signal=True, **args): + channel = self.existing_channel(props) + """Return an existing channel with theses properties if it already + exists, otherwhise return a new one""" + if channel: + return channel + else: + return self.create_channel_for_props(props, signal, **args) + + # Should use implement_channel_classes instead. def _implement_channel_class(self, type, make_channel, fixed, available): - self._requestable_channel_classes[type] = make_channel + """Implement channel types in the channel manager, and add one channel + class that is retrieved in RequestableChannelClasses. + + self.implement_channel_classes should be used instead, as it allows + implementing multiple channel classes.""" + warnings.warn('deprecated in favour of implement_channel_classes', + DeprecationWarning) + + self._requestable_channels[type] = make_channel self._channels.setdefault(type, {}) self._fixed_properties[type] = fixed self._available_properties[type] = available + # Use this function instead of _implement_channel_class. + def implement_channel_classes(self, type, make_channel, classes): + """Implement channel types in the channel manager, and add channel + classes that are retrieved in RequestableChannelClasses. + + @type: the channel type + @make_channel: a function to call which returns a Channel object + @classes: a list of channel classes. E.g. + + [ ( { '...ChannelType': '...Text', '...TargetHandleType': HANDLE_TYPE_CONTACT }, + ['...TargetHandle'] ) + ] + + See the spec for more documentation on the + Requestable_Channel_Class struct. + """ + self._requestable_channels[type] = make_channel + self._channels.setdefault(type, {}) + + self._requestables[type] = classes + def get_requestable_channel_classes(self): + """Return all the channel types that can be created""" retval = [] - for channel_type in self._requestable_channel_classes: - retval.append((self._fixed_properties[channel_type], - self._available_properties[channel_type])) + for channel_type in self._requestable_channels: + retval.extend(self._requestables.get(channel_type, [])) + + # _implement_channel_class was used. + if channel_type in self._fixed_properties: + retval.append((self._fixed_properties[channel_type], + self._available_properties.get(channel_type, []))) + return retval