From 98cc77f1fb35ae0c0e44a27dc389248b8024bba7 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Tue, 22 Jun 2010 16:31:21 +0200 Subject: [PATCH] Replace enough of the old PS so we can join an activity instance on the network. * src/sugar/activity/activity.py: Get the shared activity wrapper from sugar.presence. * src/sugar/activity/activityfactory.py: Disable checking in the PS for activity_id duplicates. * src/sugar/presence/activity.py: Remove the PS dependency and query Telepathy directly. Implemented enough to join an activity. * src/sugar/presence/buddy.py: Remove the PS dependency and query Telepathy directly. Implemented enough to join an activity. Added an Owner subclass of Buddy() * src/sugar/presence/presenceservice.py: Remove the PS dependency and query Telepathy directly. Implemented enough to join an activity. * src/sugar/presence/util.py: Add ConnectionManager for discovering and tracking connections. --- src/sugar/activity/activity.py | 7 +- src/sugar/activity/activityfactory.py | 3 + src/sugar/presence/activity.py | 166 ++++++----------- src/sugar/presence/buddy.py | 257 +++++++++++++++++--------- src/sugar/presence/presenceservice.py | 167 ++++------------- 5 files changed, 274 insertions(+), 326 deletions(-) diff --git a/src/sugar/activity/activity.py b/src/sugar/activity/activity.py index 0e2ecc53..20c9c7dc 100644 --- a/src/sugar/activity/activity.py +++ b/src/sugar/activity/activity.py @@ -70,6 +70,7 @@ from sugar.graphics.alert import Alert from sugar.graphics.icon import Icon from sugar.datastore import datastore from sugar.session import XSMPClient +from sugar.presence import presenceservice from sugar import wm # support deprecated imports @@ -266,7 +267,6 @@ class Activity(Window, gtk.Container): self._active = False self._activity_id = handle.activity_id - self._pservice = presenceservice.get_instance() self.shared_activity = None self._share_id = None self._join_id = None @@ -302,8 +302,9 @@ class Activity(Window, gtk.Container): share_scope = self._jobject.metadata['share-scope'] # handle activity share/join - mesh_instance = self._pservice.get_activity(self._activity_id, - warn_if_none=False) + pservice = presenceservice.get_instance() + mesh_instance = pservice.get_activity(self._activity_id, + warn_if_none=False) logging.debug("*** Act %s, mesh instance %r, scope %s", self._activity_id, mesh_instance, share_scope) if mesh_instance is not None: diff --git a/src/sugar/activity/activityfactory.py b/src/sugar/activity/activityfactory.py index 6b4ba322..0dd37938 100644 --- a/src/sugar/activity/activityfactory.py +++ b/src/sugar/activity/activityfactory.py @@ -75,11 +75,14 @@ def create_activity_id(): # check through network activities found = False + logging.info('KILL_PS check the activity_id is not used in the network') + """ activities = pservice.get_activities() for act in activities: if act_id == act.props.id: found = True break + """ if not found: return act_id raise RuntimeError("Cannot generate unique activity id.") diff --git a/src/sugar/presence/activity.py b/src/sugar/presence/activity.py index 1d4a9c9e..617409f0 100644 --- a/src/sugar/presence/activity.py +++ b/src/sugar/presence/activity.py @@ -25,7 +25,14 @@ import logging import dbus import gobject import telepathy +from telepathy.client import Channel +from telepathy.interfaces import CHANNEL, \ + CHANNEL_TYPE_TUBES, \ + CHANNEL_TYPE_TEXT, \ + CONNECTION +from telepathy.constants import HANDLE_TYPE_ROOM +CONN_INTERFACE_ACTIVITY_PROPERTIES = 'org.laptop.Telepathy.ActivityProperties' _logger = logging.getLogger('sugar.presence.activity') @@ -64,34 +71,14 @@ class Activity(gobject.GObject): 'joined': (bool, None, None, False, gobject.PARAM_READABLE), } - _PRESENCE_SERVICE = "org.laptop.Sugar.Presence" - _ACTIVITY_DBUS_INTERFACE = "org.laptop.Sugar.Presence.Activity" - - def __init__(self, bus, new_obj_cb, del_obj_cb, object_path): - """Initialse the activity interface, connecting to service""" + def __init__(self, connection, room_handle): gobject.GObject.__init__(self) - self.telepathy_room_handle = None - self._object_path = object_path - self._ps_new_object = new_obj_cb - self._ps_del_object = del_obj_cb - bobj = bus.get_object(self._PRESENCE_SERVICE, object_path) - self._activity = dbus.Interface(bobj, self._ACTIVITY_DBUS_INTERFACE) - self._activity.connect_to_signal('BuddyHandleJoined', - self._buddy_handle_joined_cb) - self._activity.connect_to_signal('BuddyLeft', - self._buddy_left_cb) - self._activity.connect_to_signal('NewChannel', self._new_channel_cb) - self._activity.connect_to_signal('PropertiesChanged', - self._properties_changed_cb, - utf8_strings=True) - # FIXME: this *would* just use a normal proxy call, but I want the - # pending call object so I can block on it, and normal proxy methods - # don't return those as of dbus-python 0.82.1; so do it the hard way - self._get_properties_call = bus.call_async(self._PRESENCE_SERVICE, - object_path, self._ACTIVITY_DBUS_INTERFACE, 'GetProperties', - '', (), self._get_properties_reply_cb, - self._get_properties_error_cb, utf8_strings=True) + self.telepathy_conn = connection + self.telepathy_text_chan = None + self.telepathy_tubes_chan = None + + self._room_handle = room_handle self._id = None self._color = None self._name = None @@ -99,31 +86,32 @@ class Activity(gobject.GObject): self._tags = None self._private = True self._joined = False - # Cache for get_buddy_by_handle, maps handles to buddy object paths - self._handle_to_buddy_path = {} - self._buddy_path_to_handle = {} - # Set up by set_up_tubes() - self.telepathy_conn = None - self.telepathy_tubes_chan = None - self.telepathy_text_chan = None - self._telepathy_room = None + bus = dbus.SessionBus() + self._get_properties_call = bus.call_async( + connection.requested_bus_name, + connection.object_path, + CONN_INTERFACE_ACTIVITY_PROPERTIES, + 'GetProperties', + 'u', + (self._room_handle,), + reply_handler=self._got_properties_cb, + error_handler=self._error_handler_cb, + utf8_strings=True) - def __repr__(self): - return ('' % (self._object_path, id(self))) - - def _get_properties_reply_cb(self, new_props): + def _got_properties_cb(self, properties): + _logger.debug('_got_properties_cb', properties) self._get_properties_call = None - _logger.debug('%r: initial GetProperties returned', self) - self._properties_changed_cb(new_props) + self._update_properties(properties) - def _get_properties_error_cb(self, e): - self._get_properties_call = None - # FIXME: do something with the error - _logger.warning('%r: Error doing initial GetProperties: %s', self, e) + def _error_handler_cb(self, error): + _logger.debug('_error_handler_cb', error) def _properties_changed_cb(self, new_props): _logger.debug('%r: Activity properties changed to %r', self, new_props) + self._update_properties(new_props) + + def _update_properties(self, new_props): val = new_props.get('name', self._name) if isinstance(val, str) and val != self._name: self._name = val @@ -244,16 +232,8 @@ class Activity(gobject.GObject): returns list of presence Buddy objects that we can successfully create from the buddy object paths that PS has for this activity. """ - resp = self._activity.GetJoinedBuddies() - buddies = [] - for item in resp: - try: - buddies.append(self._ps_new_object(item)) - except dbus.DBusException: - _logger.debug( - 'get_joined_buddies failed to get buddy object for %r', - item) - return buddies + logging.info('KILL_PS return joined buddies') + return [] def get_buddy_by_handle(self, handle): """Retrieve the Buddy object given a telepathy handle. @@ -293,62 +273,38 @@ class Activity(gobject.GObject): _logger.debug('%r: finished setting up tubes', self) reply_handler() - def tubes_chan_ready(chan): - _logger.debug('%r: Tubes channel %r is ready', self, chan) - self.telepathy_tubes_chan = chan + def tubes_channel_ready_cb(channel): + _logger.debug('%r: Tubes channel %r is ready', self, channel) + self.telepathy_tubes_chan = channel tubes_ready() - def text_chan_ready(chan): - _logger.debug('%r: Text channel %r is ready', self, chan) - self.telepathy_text_chan = chan + def text_channel_ready_cb(channel): + _logger.debug('%r: Text channel %r is ready', self, channel) + self.telepathy_text_chan = channel tubes_ready() - def conn_ready(conn): - _logger.debug('%r: Connection %r is ready', self, conn) - self.telepathy_conn = conn - found_text_channel = False - found_tubes_channel = False + def create_text_channel_cb(channel_path): + Channel(self.telepathy_conn.requested_bus_name, channel_path, + ready_handler=text_channel_ready_cb) - for chan_path, chan_iface, handle_type, handle in chans: - if handle_type != telepathy.HANDLE_TYPE_ROOM: - return + def create_tubes_channel_cb(channel_path): + Channel(self.telepathy_conn.requested_bus_name, channel_path, + ready_handler=tubes_channel_ready_cb) - if chan_iface == telepathy.CHANNEL_TYPE_TEXT: - telepathy.client.Channel( - conn.service_name, chan_path, - ready_handler=text_chan_ready, - error_handler=error_handler) - found_text_channel = True - self.telepathy_room_handle = handle + def error_handler_cb(error): + raise RuntimeError(error) - elif chan_iface == telepathy.CHANNEL_TYPE_TUBES: - telepathy.client.Channel( - conn.service_name, chan_path, - ready_handler=tubes_chan_ready, - error_handler=error_handler) - found_tubes_channel = True + self.telepathy_conn.RequestChannel(CHANNEL_TYPE_TEXT, + HANDLE_TYPE_ROOM, self._room_handle, True, + reply_handler=create_text_channel_cb, + error_handler=error_handler_cb, + dbus_interface=CONNECTION) - if not found_text_channel: - error_handler(AssertionError("Presence Service didn't create " - "a chatroom")) - elif not found_tubes_channel: - error_handler(AssertionError("Presence Service didn't create " - "tubes channel")) - - def channels_listed(bus_name, conn_path, channels): - _logger.debug('%r: Connection on %s at %s, channels: %r', - self, bus_name, conn_path, channels) - - # can't use assignment for this due to Python scoping - chans.extend(channels) - - telepathy.client.Connection(bus_name, conn_path, - ready_handler=conn_ready, - error_handler=error_handler) - - - self._activity.ListChannels(reply_handler=channels_listed, - error_handler=error_handler) + self.telepathy_conn.RequestChannel(CHANNEL_TYPE_TUBES, + HANDLE_TYPE_ROOM, self._room_handle, True, + reply_handler=create_tubes_channel_cb, + error_handler=error_handler_cb, + dbus_interface=CONNECTION) def _join_cb(self): _logger.debug('%r: Join finished', self) @@ -370,11 +326,7 @@ class Activity(gobject.GObject): _logger.debug('%r: joining', self) - def joined(): - self.set_up_tubes(reply_handler=self._join_cb, - error_handler=self._join_error_cb) - - self._activity.Join(reply_handler=joined, + self.set_up_tubes(reply_handler=self._join_cb, error_handler=self._join_error_cb) # GetChannels() wrapper diff --git a/src/sugar/presence/buddy.py b/src/sugar/presence/buddy.py index 2978e4db..4722485f 100644 --- a/src/sugar/presence/buddy.py +++ b/src/sugar/presence/buddy.py @@ -20,12 +20,21 @@ STABLE. """ +import logging + import gobject import gtk import dbus +import gconf +from telepathy.interfaces import CONNECTION_INTERFACE_ALIASING, \ + CONNECTION_INTERFACE_CONTACTS + +CONN_INTERFACE_BUDDY_INFO = 'org.laptop.Telepathy.BuddyInfo' + +_logger = logging.getLogger('sugar.presence.buddy') -class Buddy(gobject.GObject): +class BaseBuddy(gobject.GObject): """UI interface for a Buddy in the presence service Each buddy interface tracks a set of activities and properties @@ -42,6 +51,8 @@ class Buddy(gobject.GObject): See __gproperties__ """ + __gtype_name__ = 'PresenceBaseBuddy' + __gsignals__ = { 'icon-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])), 'joined-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, @@ -52,53 +63,17 @@ class Buddy(gobject.GObject): ([gobject.TYPE_PYOBJECT])), } - __gproperties__ = { - 'key': (str, None, None, None, gobject.PARAM_READABLE), - 'icon': (str, None, None, None, gobject.PARAM_READABLE), - 'nick': (str, None, None, None, gobject.PARAM_READABLE), - 'color': (str, None, None, None, gobject.PARAM_READABLE), - 'current-activity': (object, None, None, gobject.PARAM_READABLE), - 'owner': (bool, None, None, False, gobject.PARAM_READABLE), - 'ip4-address': (str, None, None, None, gobject.PARAM_READABLE), - 'tags': (str, None, None, None, gobject.PARAM_READABLE), - } - - _PRESENCE_SERVICE = "org.laptop.Sugar.Presence" - _BUDDY_DBUS_INTERFACE = "org.laptop.Sugar.Presence.Buddy" - - def __init__(self, bus, new_obj_cb, del_obj_cb, object_path): - """Initialise the reference to the buddy - - bus -- dbus bus object - new_obj_cb -- callback to call when this buddy joins an activity - del_obj_cb -- callback to call when this buddy leaves an activity - object_path -- path to the buddy object - """ + def __init__(self): gobject.GObject.__init__(self) - self._object_path = object_path - self._ps_new_object = new_obj_cb - self._ps_del_object = del_obj_cb - self._properties = {} - self._activities = {} - bobj = bus.get_object(self._PRESENCE_SERVICE, object_path) - self._buddy = dbus.Interface(bobj, self._BUDDY_DBUS_INTERFACE) - - self._icon_changed_signal = self._buddy.connect_to_signal( - 'IconChanged', self._icon_changed_cb, byte_arrays=True) - self._joined_activity_signal = self._buddy.connect_to_signal( - 'JoinedActivity', self._joined_activity_cb) - self._left_activity_signal = self._buddy.connect_to_signal( - 'LeftActivity', self._left_activity_cb) - self._property_changed_signal = self._buddy.connect_to_signal( - 'PropertyChanged', self._property_changed_cb) - - self._properties = self._get_properties_helper() - - activities = self._buddy.GetJoinedActivities() - for op in activities: - self._activities[op] = self._ps_new_object(op) + self._key = None self._icon = None + self._nick = None + self._color = None + self._current_activity = None + self._owner = False + self._ip4_address = None + self._tags = None def destroy(self): self._icon_changed_signal.remove() @@ -114,41 +89,68 @@ class Buddy(gobject.GObject): return {} return props - def do_get_property(self, pspec): - """Retrieve a particular property from our property dictionary + def get_key(self): + return self._key - pspec -- XXX some sort of GTK specifier object with attributes - including 'name', 'active' and 'icon-name' - """ - if pspec.name == "key": - return self._properties["key"] - elif pspec.name == "nick": - return self._properties["nick"] - elif pspec.name == "color": - return self._properties["color"] - elif pspec.name == "tags": - return self._properties["tags"] - elif pspec.name == "current-activity": - if not self._properties.has_key("current-activity"): - return None - curact = self._properties["current-activity"] - if not len(curact): - return None - for activity in self._activities.values(): - if activity.props.id == curact: - return activity + def set_key(self, key): + self._key = key + + key = gobject.property(type=str, getter=get_key, setter=set_key) + + def get_icon(self): + raise NotImplementedError() + + icon = gobject.property(type=str, getter=get_icon) + + def get_nick(self): + return self._nick + + def set_nick(self, nick): + self._nick = nick + + nick = gobject.property(type=str, getter=get_nick, setter=set_nick) + + def get_color(self): + return self._color + + def set_color(self, color): + self._color = color + + color = gobject.property(type=str, getter=get_color, setter=set_color) + + def get_current_activity(self): + if self._current_activity is None: return None - elif pspec.name == "owner": - return self._properties["owner"] - elif pspec.name == "icon": - if not self._icon: - self._icon = str(self._buddy.GetIcon(byte_arrays=True)) - return self._icon - elif pspec.name == "ip4-address": - # IPv4 address will go away quite soon - if not self._properties.has_key("ip4-address"): - return None - return self._properties["ip4-address"] + for activity in self._activities.values(): + if activity.props.id == self._current_activity: + return activity + return None + + current_activity = gobject.property(type=object, getter=get_current_activity) + + def get_owner(self): + return self._owner + + def set_owner(self, owner): + self._owner = owner + + owner = gobject.property(type=bool, getter=get_owner, setter=set_owner, default=False) + + def get_ip4_address(self): + return self._ip4_address + + def set_ip4_address(self, ip4_address): + self._ip4_address = ip4_address + + ip4_address = gobject.property(type=str, getter=get_ip4_address, setter=set_ip4_address) + + def get_tags(self): + return self._tags + + def set_tags(self, tags): + self._tags = tags + + tags = gobject.property(type=str, getter=get_tags, setter=set_tags) def object_path(self): """Retrieve our dbus object path""" @@ -160,16 +162,16 @@ class Buddy(gobject.GObject): self.emit('icon-changed') return False - def _icon_changed_cb(self, icon_data): + def __icon_changed_cb(self, icon_data): """Handle dbus signal by emitting a GObject signal""" gobject.idle_add(self._emit_icon_changed_signal, icon_data) - def _emit_joined_activity_signal(self, object_path): + def __emit_joined_activity_signal(self, object_path): """Emit activity joined signal with Activity object""" self.emit('joined-activity', self._ps_new_object(object_path)) return False - def _joined_activity_cb(self, object_path): + def __joined_activity_cb(self, object_path): """Handle dbus signal by emitting a GObject signal Stores the activity in activities dictionary as well @@ -187,7 +189,7 @@ class Buddy(gobject.GObject): self.emit('left-activity', self._ps_new_object(object_path)) return False - def _left_activity_cb(self, object_path): + def __left_activity_cb(self, object_path): """Handle dbus signal by emitting a GObject signal Also removes from the activities dictionary @@ -207,7 +209,7 @@ class Buddy(gobject.GObject): self.emit('property-changed', prop_list) return False - def _property_changed_cb(self, prop_list): + def __property_changed_cb(self, prop_list): """Handle dbus signal by emitting a GObject signal""" gobject.idle_add(self._handle_property_changed_signal, prop_list) @@ -241,3 +243,92 @@ class Buddy(gobject.GObject): for item in resp: acts.append(self._ps_new_object(item)) return acts + + +class Buddy(BaseBuddy): + __gtype_name__ = 'PresenceBuddy' + def __init__(self, connection, contact_handle): + BaseBuddy.__init__(self) + + self._contact_handle = contact_handle + + bus = dbus.SessionBus() + self._get_properties_call = bus.call_async( + connection.requested_bus_name, + connection.object_path, + CONN_INTERFACE_BUDDY_INFO, + 'GetProperties', + 'u', + (self._contact_handle,), + reply_handler=self.__got_properties_cb, + error_handler=self.__error_handler_cb, + utf8_strings=True, + byte_arrays=True) + + self._get_attributes_call = bus.call_async( + connection.requested_bus_name, + connection.object_path, + CONNECTION_INTERFACE_CONTACTS, + 'GetContactAttributes', + 'auasb', + ([self._contact_handle], [CONNECTION_INTERFACE_ALIASING], False), + reply_handler=self.__got_attributes_cb, + error_handler=self.__error_handler_cb) + + def __got_properties_cb(self, properties): + _logger.debug('__got_properties_cb', properties) + self._get_properties_call = None + self._update_properties(properties) + + def __got_attributes_cb(self, attributes): + _logger.debug('__got_attributes_cb', attributes) + self._get_attributes_call = None + self._update_attributes(attributes[self._contact_handle]) + + def __error_handler_cb(self, error): + _logger.debug('__error_handler_cb', error) + + def __properties_changed_cb(self, new_props): + _logger.debug('%r: Buddy properties changed to %r', self, new_props) + self._update_properties(new_props) + + def _update_properties(self, properties): + if 'key' in properties: + self.props.key = properties['key'] + if 'icon' in properties: + self.props.icon = properties['icon'] + if 'color' in properties: + self.props.color = properties['color'] + if 'current-activity' in properties: + self.props.current_activity = properties['current-activity'] + if 'owner' in properties: + self.props.owner = properties['owner'] + if 'ip4-address' in properties: + self.props.ip4_address = properties['ip4-address'] + if 'tags' in properties: + self.props.tags = properties['tags'] + + def _update_attributes(self, attributes): + nick_key = CONNECTION_INTERFACE_ALIASING + '/alias' + if nick_key in attributes: + self.props.nick = attributes[nick_key] + + def do_get_property(self, pspec): + if self._get_properties_call is not None: + _logger.debug('%r: Blocking on GetProperties() because someone ' + 'wants property %s', self, pspec.name) + self._get_properties_call.block() + + return BaseBuddy.do_get_property(self, pspec) + + +class Owner(BaseBuddy): + + __gtype_name__ = 'PresenceOwner' + + def __init__(self): + BaseBuddy.__init__(self) + + client = gconf.client_get_default() + self.props.nick = client.get_string("/desktop/sugar/user/nick") + self.props.color = client.get_string("/desktop/sugar/user/color") diff --git a/src/sugar/presence/presenceservice.py b/src/sugar/presence/presenceservice.py index f4aa6df7..0b949249 100644 --- a/src/sugar/presence/presenceservice.py +++ b/src/sugar/presence/presenceservice.py @@ -23,19 +23,16 @@ STABLE. import logging import traceback +import gobject import dbus import dbus.exceptions import dbus.glib -import gobject -from sugar.presence.buddy import Buddy +from sugar.presence.buddy import Buddy, Owner from sugar.presence.activity import Activity +from sugar.presence.util import get_connection_manager -DBUS_SERVICE = "org.laptop.Sugar.Presence" -DBUS_INTERFACE = "org.laptop.Sugar.Presence" -DBUS_PATH = "/org/laptop/Sugar/Presence" - _logger = logging.getLogger('sugar.presence.presenceservice') @@ -66,92 +63,12 @@ class PresenceService(gobject.GObject): gobject.TYPE_PYOBJECT])), } - _PS_BUDDY_OP = DBUS_PATH + "/Buddies/" - _PS_ACTIVITY_OP = DBUS_PATH + "/Activities/" - - def __init__(self, allow_offline_iface=True): + def __init__(self): """Initialise the service and attempt to connect to events """ gobject.GObject.__init__(self) - self._objcache = {} - self._joined = None - # Get a connection to the session bus - self._bus = dbus.SessionBus() - self._bus.add_signal_receiver(self._name_owner_changed_cb, - signal_name="NameOwnerChanged", - dbus_interface="org.freedesktop.DBus") - - # attempt to load the interface to the service... - self._allow_offline_iface = allow_offline_iface - self._get_ps() - - def _name_owner_changed_cb(self, name, old, new): - if name != DBUS_SERVICE: - return - if (old and len(old)) and (not new and not len(new)): - # PS went away, clear out PS dbus service wrapper - self._ps_ = None - elif (not old and not len(old)) and (new and len(new)): - # PS started up - self._get_ps() - - _ps_ = None - - def _get_ps(self): - """Retrieve dbus interface to PresenceService - - Also registers for updates from various dbus events on the - interface. - - If unable to retrieve the interface, we will temporarily - return an _OfflineInterface object to allow the calling - code to continue functioning as though it had accessed a - real presence service. - - If successful, caches the presence service interface - for use by other methods and returns that interface - """ - if not self._ps_: - try: - # NOTE: We need to follow_name_owner_changes here - # because we can not connect to a signal unless - # we follow the changes or we start the service - # before we connect. Starting the service here - # causes a major bottleneck during startup - ps = dbus.Interface( - self._bus.get_object(DBUS_SERVICE, - DBUS_PATH, - follow_name_owner_changes=True), - DBUS_INTERFACE) - except dbus.exceptions.DBusException, err: - _logger.error( - """Failure retrieving %r interface from - the D-BUS service %r %r: %s""", - DBUS_INTERFACE, DBUS_SERVICE, DBUS_PATH, err) - if self._allow_offline_iface: - return _OfflineInterface() - raise RuntimeError('Failed to connect to the presence ' - 'service.') - else: - self._ps_ = ps - ps.connect_to_signal('BuddyAppeared', - self._buddy_appeared_cb) - ps.connect_to_signal('BuddyDisappeared', - self._buddy_disappeared_cb) - ps.connect_to_signal('ActivityAppeared', - self._activity_appeared_cb) - ps.connect_to_signal('ActivityDisappeared', - self._activity_disappeared_cb) - ps.connect_to_signal('ActivityInvitation', - self._activity_invitation_cb) - ps.connect_to_signal('PrivateInvitation', - self._private_invitation_cb) - return self._ps_ - - _ps = property(_get_ps, None, None, - """DBUS interface to the PresenceService - (services/presence/presenceservice)""") + self._buddy_cache = {} def _new_object(self, object_path): """Turn new object path into (cached) Buddy/Activity instance @@ -289,17 +206,11 @@ class PresenceService(gobject.GObject): returns list of Activity objects for all object paths the service reports exist (using GetActivities) """ - try: - resp = self._ps.GetActivities() - except dbus.exceptions.DBusException: - _logger.exception('Unable to retrieve activity list from ' - 'presence service') - return [] - else: - acts = [] - for item in resp: - acts.append(self._new_object(item)) - return acts + resp = self._ps.GetActivities() + acts = [] + for item in resp: + acts.append(self._new_object(item)) + return acts def _get_activities_cb(self, reply_handler, resp): acts = [] @@ -338,14 +249,14 @@ class PresenceService(gobject.GObject): returns single Activity object or None if the activity is not found using GetActivityById on the service """ - try: - act_op = self._ps.GetActivityById(activity_id) - except dbus.exceptions.DBusException, err: - if warn_if_none: - _logger.warn("Unable to retrieve activity handle for %r from " - "presence service: %s", activity_id, err) - return None - return self._new_object(act_op) + for connection in get_connection_manager().connections: + try: + room_handle = connection.GetActivity(activity_id) + return Activity(connection, room_handle) + except: + pass + + return None def get_buddies(self): """Retrieve set of all buddies from service @@ -426,26 +337,19 @@ class PresenceService(gobject.GObject): channel-specific handle. :Returns: the Buddy object, or None if the buddy is not found """ - try: - buddy_op = self._ps.GetBuddyByTelepathyHandle(tp_conn_name, - tp_conn_path, - handle) - except dbus.exceptions.DBusException, err: - _logger.warn('Unable to retrieve buddy handle for handle %u at ' - 'conn %s:%s from presence service: %s', - handle, tp_conn_name, tp_conn_path, err) - return None - return self._new_object(buddy_op) + logging.info('KILL_PS decide how to invalidate this cache') + if (tp_conn_path, handle) in self._buddy_cache: + return self._buddy_cache[(tp_conn_path, handle)] + else: + bus = dbus.SessionBus() + connection = bus.get_object(tp_conn_name, tp_conn_path) + buddy = Buddy(connection, handle) + self._buddy_cache[(tp_conn_path, handle)] = buddy + return buddy def get_owner(self): - """Retrieves the laptop "owner" Buddy object.""" - try: - owner_op = self._ps.GetOwner() - except dbus.exceptions.DBusException: - _logger.exception('Unable to retrieve local user/owner from ' - 'presence service') - raise RuntimeError("Could not get owner object.") - return self._new_object(owner_op) + """Retrieves the laptop Buddy object.""" + return Owner() def _share_activity_cb(self, activity, op): """Finish sharing the activity @@ -505,14 +409,11 @@ class PresenceService(gobject.GObject): should use when talking directly to telepathy returns the bus name and the object path of the Telepathy connection""" - - try: - bus_name, object_path = self._ps.GetPreferredConnection() - except dbus.exceptions.DBusException: - logging.error(traceback.format_exc()) + connection = get_connection_manager().get_preferred_connection() + if connection is None: return None - - return bus_name, object_path + else: + return connection.requested_bus_name, connection.object_path class _OfflineInterface(object): @@ -596,5 +497,5 @@ def get_instance(allow_offline_iface=False): """Retrieve this process' view of the PresenceService""" global _ps if not _ps: - _ps = PresenceService(allow_offline_iface) + _ps = PresenceService() return _ps