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.
This commit is contained in:
Tomeu Vizoso 2010-06-22 16:31:21 +02:00
parent d6da506dfd
commit 98cc77f1fb
5 changed files with 274 additions and 326 deletions

View File

@ -70,6 +70,7 @@ from sugar.graphics.alert import Alert
from sugar.graphics.icon import Icon from sugar.graphics.icon import Icon
from sugar.datastore import datastore from sugar.datastore import datastore
from sugar.session import XSMPClient from sugar.session import XSMPClient
from sugar.presence import presenceservice
from sugar import wm from sugar import wm
# support deprecated imports # support deprecated imports
@ -266,7 +267,6 @@ class Activity(Window, gtk.Container):
self._active = False self._active = False
self._activity_id = handle.activity_id self._activity_id = handle.activity_id
self._pservice = presenceservice.get_instance()
self.shared_activity = None self.shared_activity = None
self._share_id = None self._share_id = None
self._join_id = None self._join_id = None
@ -302,8 +302,9 @@ class Activity(Window, gtk.Container):
share_scope = self._jobject.metadata['share-scope'] share_scope = self._jobject.metadata['share-scope']
# handle activity share/join # handle activity share/join
mesh_instance = self._pservice.get_activity(self._activity_id, pservice = presenceservice.get_instance()
warn_if_none=False) mesh_instance = pservice.get_activity(self._activity_id,
warn_if_none=False)
logging.debug("*** Act %s, mesh instance %r, scope %s", logging.debug("*** Act %s, mesh instance %r, scope %s",
self._activity_id, mesh_instance, share_scope) self._activity_id, mesh_instance, share_scope)
if mesh_instance is not None: if mesh_instance is not None:

View File

@ -75,11 +75,14 @@ def create_activity_id():
# check through network activities # check through network activities
found = False found = False
logging.info('KILL_PS check the activity_id is not used in the network')
"""
activities = pservice.get_activities() activities = pservice.get_activities()
for act in activities: for act in activities:
if act_id == act.props.id: if act_id == act.props.id:
found = True found = True
break break
"""
if not found: if not found:
return act_id return act_id
raise RuntimeError("Cannot generate unique activity id.") raise RuntimeError("Cannot generate unique activity id.")

View File

@ -25,7 +25,14 @@ import logging
import dbus import dbus
import gobject import gobject
import telepathy 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') _logger = logging.getLogger('sugar.presence.activity')
@ -64,34 +71,14 @@ class Activity(gobject.GObject):
'joined': (bool, None, None, False, gobject.PARAM_READABLE), 'joined': (bool, None, None, False, gobject.PARAM_READABLE),
} }
_PRESENCE_SERVICE = "org.laptop.Sugar.Presence" def __init__(self, connection, room_handle):
_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"""
gobject.GObject.__init__(self) 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._id = None
self._color = None self._color = None
self._name = None self._name = None
@ -99,31 +86,32 @@ class Activity(gobject.GObject):
self._tags = None self._tags = None
self._private = True self._private = True
self._joined = False 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() bus = dbus.SessionBus()
self.telepathy_conn = None self._get_properties_call = bus.call_async(
self.telepathy_tubes_chan = None connection.requested_bus_name,
self.telepathy_text_chan = None connection.object_path,
self._telepathy_room = None 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): def _got_properties_cb(self, properties):
return ('<proxy for %s at %x>' % (self._object_path, id(self))) _logger.debug('_got_properties_cb', properties)
def _get_properties_reply_cb(self, new_props):
self._get_properties_call = None self._get_properties_call = None
_logger.debug('%r: initial GetProperties returned', self) self._update_properties(properties)
self._properties_changed_cb(new_props)
def _get_properties_error_cb(self, e): def _error_handler_cb(self, error):
self._get_properties_call = None _logger.debug('_error_handler_cb', error)
# FIXME: do something with the error
_logger.warning('%r: Error doing initial GetProperties: %s', self, e)
def _properties_changed_cb(self, new_props): def _properties_changed_cb(self, new_props):
_logger.debug('%r: Activity properties changed to %r', 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) val = new_props.get('name', self._name)
if isinstance(val, str) and val != self._name: if isinstance(val, str) and val != self._name:
self._name = val self._name = val
@ -244,16 +232,8 @@ class Activity(gobject.GObject):
returns list of presence Buddy objects that we can successfully returns list of presence Buddy objects that we can successfully
create from the buddy object paths that PS has for this activity. create from the buddy object paths that PS has for this activity.
""" """
resp = self._activity.GetJoinedBuddies() logging.info('KILL_PS return joined buddies')
buddies = [] return []
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
def get_buddy_by_handle(self, handle): def get_buddy_by_handle(self, handle):
"""Retrieve the Buddy object given a telepathy 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) _logger.debug('%r: finished setting up tubes', self)
reply_handler() reply_handler()
def tubes_chan_ready(chan): def tubes_channel_ready_cb(channel):
_logger.debug('%r: Tubes channel %r is ready', self, chan) _logger.debug('%r: Tubes channel %r is ready', self, channel)
self.telepathy_tubes_chan = chan self.telepathy_tubes_chan = channel
tubes_ready() tubes_ready()
def text_chan_ready(chan): def text_channel_ready_cb(channel):
_logger.debug('%r: Text channel %r is ready', self, chan) _logger.debug('%r: Text channel %r is ready', self, channel)
self.telepathy_text_chan = chan self.telepathy_text_chan = channel
tubes_ready() tubes_ready()
def conn_ready(conn): def create_text_channel_cb(channel_path):
_logger.debug('%r: Connection %r is ready', self, conn) Channel(self.telepathy_conn.requested_bus_name, channel_path,
self.telepathy_conn = conn ready_handler=text_channel_ready_cb)
found_text_channel = False
found_tubes_channel = False
for chan_path, chan_iface, handle_type, handle in chans: def create_tubes_channel_cb(channel_path):
if handle_type != telepathy.HANDLE_TYPE_ROOM: Channel(self.telepathy_conn.requested_bus_name, channel_path,
return ready_handler=tubes_channel_ready_cb)
if chan_iface == telepathy.CHANNEL_TYPE_TEXT: def error_handler_cb(error):
telepathy.client.Channel( raise RuntimeError(error)
conn.service_name, chan_path,
ready_handler=text_chan_ready,
error_handler=error_handler)
found_text_channel = True
self.telepathy_room_handle = handle
elif chan_iface == telepathy.CHANNEL_TYPE_TUBES: self.telepathy_conn.RequestChannel(CHANNEL_TYPE_TEXT,
telepathy.client.Channel( HANDLE_TYPE_ROOM, self._room_handle, True,
conn.service_name, chan_path, reply_handler=create_text_channel_cb,
ready_handler=tubes_chan_ready, error_handler=error_handler_cb,
error_handler=error_handler) dbus_interface=CONNECTION)
found_tubes_channel = True
if not found_text_channel: self.telepathy_conn.RequestChannel(CHANNEL_TYPE_TUBES,
error_handler(AssertionError("Presence Service didn't create " HANDLE_TYPE_ROOM, self._room_handle, True,
"a chatroom")) reply_handler=create_tubes_channel_cb,
elif not found_tubes_channel: error_handler=error_handler_cb,
error_handler(AssertionError("Presence Service didn't create " dbus_interface=CONNECTION)
"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)
def _join_cb(self): def _join_cb(self):
_logger.debug('%r: Join finished', self) _logger.debug('%r: Join finished', self)
@ -370,11 +326,7 @@ class Activity(gobject.GObject):
_logger.debug('%r: joining', self) _logger.debug('%r: joining', self)
def joined(): self.set_up_tubes(reply_handler=self._join_cb,
self.set_up_tubes(reply_handler=self._join_cb,
error_handler=self._join_error_cb)
self._activity.Join(reply_handler=joined,
error_handler=self._join_error_cb) error_handler=self._join_error_cb)
# GetChannels() wrapper # GetChannels() wrapper

View File

@ -20,12 +20,21 @@
STABLE. STABLE.
""" """
import logging
import gobject import gobject
import gtk import gtk
import dbus 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 """UI interface for a Buddy in the presence service
Each buddy interface tracks a set of activities and properties Each buddy interface tracks a set of activities and properties
@ -42,6 +51,8 @@ class Buddy(gobject.GObject):
See __gproperties__ See __gproperties__
""" """
__gtype_name__ = 'PresenceBaseBuddy'
__gsignals__ = { __gsignals__ = {
'icon-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])), 'icon-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
'joined-activity': (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])), ([gobject.TYPE_PYOBJECT])),
} }
__gproperties__ = { def __init__(self):
'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
"""
gobject.GObject.__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._key = None
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._icon = 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): def destroy(self):
self._icon_changed_signal.remove() self._icon_changed_signal.remove()
@ -114,41 +89,68 @@ class Buddy(gobject.GObject):
return {} return {}
return props return props
def do_get_property(self, pspec): def get_key(self):
"""Retrieve a particular property from our property dictionary return self._key
pspec -- XXX some sort of GTK specifier object with attributes def set_key(self, key):
including 'name', 'active' and 'icon-name' self._key = key
"""
if pspec.name == "key": key = gobject.property(type=str, getter=get_key, setter=set_key)
return self._properties["key"]
elif pspec.name == "nick": def get_icon(self):
return self._properties["nick"] raise NotImplementedError()
elif pspec.name == "color":
return self._properties["color"] icon = gobject.property(type=str, getter=get_icon)
elif pspec.name == "tags":
return self._properties["tags"] def get_nick(self):
elif pspec.name == "current-activity": return self._nick
if not self._properties.has_key("current-activity"):
return None def set_nick(self, nick):
curact = self._properties["current-activity"] self._nick = nick
if not len(curact):
return None nick = gobject.property(type=str, getter=get_nick, setter=set_nick)
for activity in self._activities.values():
if activity.props.id == curact: def get_color(self):
return activity 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 return None
elif pspec.name == "owner": for activity in self._activities.values():
return self._properties["owner"] if activity.props.id == self._current_activity:
elif pspec.name == "icon": return activity
if not self._icon: return None
self._icon = str(self._buddy.GetIcon(byte_arrays=True))
return self._icon current_activity = gobject.property(type=object, getter=get_current_activity)
elif pspec.name == "ip4-address":
# IPv4 address will go away quite soon def get_owner(self):
if not self._properties.has_key("ip4-address"): return self._owner
return None
return self._properties["ip4-address"] 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): def object_path(self):
"""Retrieve our dbus object path""" """Retrieve our dbus object path"""
@ -160,16 +162,16 @@ class Buddy(gobject.GObject):
self.emit('icon-changed') self.emit('icon-changed')
return False return False
def _icon_changed_cb(self, icon_data): def __icon_changed_cb(self, icon_data):
"""Handle dbus signal by emitting a GObject signal""" """Handle dbus signal by emitting a GObject signal"""
gobject.idle_add(self._emit_icon_changed_signal, icon_data) 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""" """Emit activity joined signal with Activity object"""
self.emit('joined-activity', self._ps_new_object(object_path)) self.emit('joined-activity', self._ps_new_object(object_path))
return False return False
def _joined_activity_cb(self, object_path): def __joined_activity_cb(self, object_path):
"""Handle dbus signal by emitting a GObject signal """Handle dbus signal by emitting a GObject signal
Stores the activity in activities dictionary as well 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)) self.emit('left-activity', self._ps_new_object(object_path))
return False return False
def _left_activity_cb(self, object_path): def __left_activity_cb(self, object_path):
"""Handle dbus signal by emitting a GObject signal """Handle dbus signal by emitting a GObject signal
Also removes from the activities dictionary Also removes from the activities dictionary
@ -207,7 +209,7 @@ class Buddy(gobject.GObject):
self.emit('property-changed', prop_list) self.emit('property-changed', prop_list)
return False return False
def _property_changed_cb(self, prop_list): def __property_changed_cb(self, prop_list):
"""Handle dbus signal by emitting a GObject signal""" """Handle dbus signal by emitting a GObject signal"""
gobject.idle_add(self._handle_property_changed_signal, prop_list) gobject.idle_add(self._handle_property_changed_signal, prop_list)
@ -241,3 +243,92 @@ class Buddy(gobject.GObject):
for item in resp: for item in resp:
acts.append(self._ps_new_object(item)) acts.append(self._ps_new_object(item))
return acts 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")

View File

@ -23,19 +23,16 @@ STABLE.
import logging import logging
import traceback import traceback
import gobject
import dbus import dbus
import dbus.exceptions import dbus.exceptions
import dbus.glib 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.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') _logger = logging.getLogger('sugar.presence.presenceservice')
@ -66,92 +63,12 @@ class PresenceService(gobject.GObject):
gobject.TYPE_PYOBJECT])), gobject.TYPE_PYOBJECT])),
} }
_PS_BUDDY_OP = DBUS_PATH + "/Buddies/" def __init__(self):
_PS_ACTIVITY_OP = DBUS_PATH + "/Activities/"
def __init__(self, allow_offline_iface=True):
"""Initialise the service and attempt to connect to events """Initialise the service and attempt to connect to events
""" """
gobject.GObject.__init__(self) gobject.GObject.__init__(self)
self._objcache = {}
self._joined = None
# Get a connection to the session bus self._buddy_cache = {}
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)""")
def _new_object(self, object_path): def _new_object(self, object_path):
"""Turn new object path into (cached) Buddy/Activity instance """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 returns list of Activity objects for all object paths
the service reports exist (using GetActivities) the service reports exist (using GetActivities)
""" """
try: resp = self._ps.GetActivities()
resp = self._ps.GetActivities() acts = []
except dbus.exceptions.DBusException: for item in resp:
_logger.exception('Unable to retrieve activity list from ' acts.append(self._new_object(item))
'presence service') return acts
return []
else:
acts = []
for item in resp:
acts.append(self._new_object(item))
return acts
def _get_activities_cb(self, reply_handler, resp): def _get_activities_cb(self, reply_handler, resp):
acts = [] acts = []
@ -338,14 +249,14 @@ class PresenceService(gobject.GObject):
returns single Activity object or None if the activity returns single Activity object or None if the activity
is not found using GetActivityById on the service is not found using GetActivityById on the service
""" """
try: for connection in get_connection_manager().connections:
act_op = self._ps.GetActivityById(activity_id) try:
except dbus.exceptions.DBusException, err: room_handle = connection.GetActivity(activity_id)
if warn_if_none: return Activity(connection, room_handle)
_logger.warn("Unable to retrieve activity handle for %r from " except:
"presence service: %s", activity_id, err) pass
return None
return self._new_object(act_op) return None
def get_buddies(self): def get_buddies(self):
"""Retrieve set of all buddies from service """Retrieve set of all buddies from service
@ -426,26 +337,19 @@ class PresenceService(gobject.GObject):
channel-specific handle. channel-specific handle.
:Returns: the Buddy object, or None if the buddy is not found :Returns: the Buddy object, or None if the buddy is not found
""" """
try: logging.info('KILL_PS decide how to invalidate this cache')
buddy_op = self._ps.GetBuddyByTelepathyHandle(tp_conn_name, if (tp_conn_path, handle) in self._buddy_cache:
tp_conn_path, return self._buddy_cache[(tp_conn_path, handle)]
handle) else:
except dbus.exceptions.DBusException, err: bus = dbus.SessionBus()
_logger.warn('Unable to retrieve buddy handle for handle %u at ' connection = bus.get_object(tp_conn_name, tp_conn_path)
'conn %s:%s from presence service: %s', buddy = Buddy(connection, handle)
handle, tp_conn_name, tp_conn_path, err) self._buddy_cache[(tp_conn_path, handle)] = buddy
return None return buddy
return self._new_object(buddy_op)
def get_owner(self): def get_owner(self):
"""Retrieves the laptop "owner" Buddy object.""" """Retrieves the laptop Buddy object."""
try: return Owner()
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)
def _share_activity_cb(self, activity, op): def _share_activity_cb(self, activity, op):
"""Finish sharing the activity """Finish sharing the activity
@ -505,14 +409,11 @@ class PresenceService(gobject.GObject):
should use when talking directly to telepathy should use when talking directly to telepathy
returns the bus name and the object path of the Telepathy connection""" returns the bus name and the object path of the Telepathy connection"""
connection = get_connection_manager().get_preferred_connection()
try: if connection is None:
bus_name, object_path = self._ps.GetPreferredConnection()
except dbus.exceptions.DBusException:
logging.error(traceback.format_exc())
return None return None
else:
return bus_name, object_path return connection.requested_bus_name, connection.object_path
class _OfflineInterface(object): class _OfflineInterface(object):
@ -596,5 +497,5 @@ def get_instance(allow_offline_iface=False):
"""Retrieve this process' view of the PresenceService""" """Retrieve this process' view of the PresenceService"""
global _ps global _ps
if not _ps: if not _ps:
_ps = PresenceService(allow_offline_iface) _ps = PresenceService()
return _ps return _ps