|
|
|
@ -63,13 +63,12 @@ class PresenceService(gobject.GObject):
|
|
|
|
|
([gobject.TYPE_PYOBJECT])),
|
|
|
|
|
'activity-shared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
|
|
|
|
([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT,
|
|
|
|
|
gobject.TYPE_PYOBJECT]))
|
|
|
|
|
gobject.TYPE_PYOBJECT])),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_PS_BUDDY_OP = DBUS_PATH + "/Buddies/"
|
|
|
|
|
_PS_ACTIVITY_OP = DBUS_PATH + "/Activities/"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, allow_offline_iface=True):
|
|
|
|
|
"""Initialise the service and attempt to connect to events
|
|
|
|
|
"""
|
|
|
|
@ -98,6 +97,7 @@ class PresenceService(gobject.GObject):
|
|
|
|
|
self._get_ps()
|
|
|
|
|
|
|
|
|
|
_ps_ = None
|
|
|
|
|
|
|
|
|
|
def _get_ps(self):
|
|
|
|
|
"""Retrieve dbus interface to PresenceService
|
|
|
|
|
|
|
|
|
@ -123,17 +123,16 @@ class PresenceService(gobject.GObject):
|
|
|
|
|
self._bus.get_object(DBUS_SERVICE,
|
|
|
|
|
DBUS_PATH,
|
|
|
|
|
follow_name_owner_changes=True),
|
|
|
|
|
DBUS_INTERFACE
|
|
|
|
|
)
|
|
|
|
|
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
|
|
|
|
|
)
|
|
|
|
|
DBUS_INTERFACE, DBUS_SERVICE, DBUS_PATH, err)
|
|
|
|
|
if self._allow_offline_iface:
|
|
|
|
|
return _OfflineInterface()
|
|
|
|
|
raise RuntimeError("Failed to connect to the presence service.")
|
|
|
|
|
raise RuntimeError('Failed to connect to the presence '
|
|
|
|
|
'service.')
|
|
|
|
|
else:
|
|
|
|
|
self._ps_ = ps
|
|
|
|
|
ps.connect_to_signal('BuddyAppeared',
|
|
|
|
@ -150,11 +149,9 @@ class PresenceService(gobject.GObject):
|
|
|
|
|
self._private_invitation_cb)
|
|
|
|
|
return self._ps_
|
|
|
|
|
|
|
|
|
|
_ps = property(
|
|
|
|
|
_get_ps, None, None,
|
|
|
|
|
_ps = property(_get_ps, None, None,
|
|
|
|
|
"""DBUS interface to the PresenceService
|
|
|
|
|
(services/presence/presenceservice)"""
|
|
|
|
|
)
|
|
|
|
|
(services/presence/presenceservice)""")
|
|
|
|
|
|
|
|
|
|
def _new_object(self, object_path):
|
|
|
|
|
"""Turn new object path into (cached) Buddy/Activity instance
|
|
|
|
@ -207,7 +204,8 @@ class PresenceService(gobject.GObject):
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def _buddy_appeared_cb(self, op):
|
|
|
|
|
"""Callback for dbus event (forwards to method to emit GObject event)"""
|
|
|
|
|
"""Callback for dbus event (forwards to method to emit GObject
|
|
|
|
|
event)"""
|
|
|
|
|
gobject.idle_add(self._emit_buddy_appeared_signal, op)
|
|
|
|
|
|
|
|
|
|
def _emit_buddy_disappeared_signal(self, object_path):
|
|
|
|
@ -218,9 +216,9 @@ class PresenceService(gobject.GObject):
|
|
|
|
|
obj = self._objcache[object_path]
|
|
|
|
|
self.emit('buddy-disappeared', obj)
|
|
|
|
|
|
|
|
|
|
# We cannot maintain the object in the cache because that would keep
|
|
|
|
|
# a lot of objects from being collected. That includes UI objects
|
|
|
|
|
# due to signals using strong references.
|
|
|
|
|
# We cannot maintain the object in the cache because that would
|
|
|
|
|
# keep a lot of objects from being collected. That includes UI
|
|
|
|
|
# objects due to signals using strong references.
|
|
|
|
|
# If we want to cache some despite the memory usage increase,
|
|
|
|
|
# we could use a LRU cache limited to some value.
|
|
|
|
|
del self._objcache[object_path]
|
|
|
|
@ -229,7 +227,8 @@ class PresenceService(gobject.GObject):
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def _buddy_disappeared_cb(self, object_path):
|
|
|
|
|
"""Callback for dbus event (forwards to method to emit GObject event)"""
|
|
|
|
|
"""Callback for dbus event (forwards to method to emit GObject
|
|
|
|
|
event)"""
|
|
|
|
|
gobject.idle_add(self._emit_buddy_disappeared_signal, object_path)
|
|
|
|
|
|
|
|
|
|
def _emit_activity_invitation_signal(self, activity_path, buddy_path,
|
|
|
|
@ -240,7 +239,8 @@ class PresenceService(gobject.GObject):
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def _activity_invitation_cb(self, activity_path, buddy_path, message):
|
|
|
|
|
"""Callback for dbus event (forwards to method to emit GObject event)"""
|
|
|
|
|
"""Callback for dbus event (forwards to method to emit GObject
|
|
|
|
|
event)"""
|
|
|
|
|
gobject.idle_add(self._emit_activity_invitation_signal, activity_path,
|
|
|
|
|
buddy_path, message)
|
|
|
|
|
|
|
|
|
@ -252,7 +252,8 @@ class PresenceService(gobject.GObject):
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def _private_invitation_cb(self, bus_name, connection, channel, chan_type):
|
|
|
|
|
"""Callback for dbus event (forwards to method to emit GObject event)"""
|
|
|
|
|
"""Callback for dbus event (forwards to method to emit GObject
|
|
|
|
|
event)"""
|
|
|
|
|
gobject.idle_add(self._emit_private_invitation_signal, bus_name,
|
|
|
|
|
connection, channel, chan_type)
|
|
|
|
|
|
|
|
|
@ -262,7 +263,8 @@ class PresenceService(gobject.GObject):
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def _activity_appeared_cb(self, object_path):
|
|
|
|
|
"""Callback for dbus event (forwards to method to emit GObject event)"""
|
|
|
|
|
"""Callback for dbus event (forwards to method to emit GObject
|
|
|
|
|
event)"""
|
|
|
|
|
gobject.idle_add(self._emit_activity_appeared_signal, object_path)
|
|
|
|
|
|
|
|
|
|
def _emit_activity_disappeared_signal(self, object_path):
|
|
|
|
@ -271,7 +273,8 @@ class PresenceService(gobject.GObject):
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def _activity_disappeared_cb(self, object_path):
|
|
|
|
|
"""Callback for dbus event (forwards to method to emit GObject event)"""
|
|
|
|
|
"""Callback for dbus event (forwards to method to emit GObject
|
|
|
|
|
event)"""
|
|
|
|
|
gobject.idle_add(self._emit_activity_disappeared_signal, object_path)
|
|
|
|
|
|
|
|
|
|
def get(self, object_path):
|
|
|
|
@ -288,11 +291,9 @@ class PresenceService(gobject.GObject):
|
|
|
|
|
"""
|
|
|
|
|
try:
|
|
|
|
|
resp = self._ps.GetActivities()
|
|
|
|
|
except dbus.exceptions.DBusException, err:
|
|
|
|
|
_logger.warn(
|
|
|
|
|
"""Unable to retrieve activity list from presence service: %s"""
|
|
|
|
|
% err
|
|
|
|
|
)
|
|
|
|
|
except dbus.exceptions.DBusException:
|
|
|
|
|
_logger.exception('Unable to retrieve activity list from '
|
|
|
|
|
'presence service')
|
|
|
|
|
return []
|
|
|
|
|
else:
|
|
|
|
|
acts = []
|
|
|
|
@ -311,10 +312,8 @@ class PresenceService(gobject.GObject):
|
|
|
|
|
if error_handler:
|
|
|
|
|
error_handler(e)
|
|
|
|
|
else:
|
|
|
|
|
_logger.warn(
|
|
|
|
|
"""Unable to retrieve activity-list from presence service: %s"""
|
|
|
|
|
% e
|
|
|
|
|
)
|
|
|
|
|
_logger.warn('Unable to retrieve activity-list from presence '
|
|
|
|
|
'service: %s', e)
|
|
|
|
|
|
|
|
|
|
def get_activities_async(self, reply_handler=None, error_handler=None):
|
|
|
|
|
"""Retrieve set of all activities from service asyncronously
|
|
|
|
@ -331,7 +330,6 @@ class PresenceService(gobject.GObject):
|
|
|
|
|
error_handler=lambda e: \
|
|
|
|
|
self._get_activities_error_cb(error_handler, e))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_activity(self, activity_id, warn_if_none=True):
|
|
|
|
|
"""Retrieve single Activity object for the given unique id
|
|
|
|
|
|
|
|
|
@ -357,11 +355,9 @@ class PresenceService(gobject.GObject):
|
|
|
|
|
"""
|
|
|
|
|
try:
|
|
|
|
|
resp = self._ps.GetBuddies()
|
|
|
|
|
except dbus.exceptions.DBusException, err:
|
|
|
|
|
_logger.warn(
|
|
|
|
|
"""Unable to retrieve buddy-list from presence service: %s"""
|
|
|
|
|
% err
|
|
|
|
|
)
|
|
|
|
|
except dbus.exceptions.DBusException:
|
|
|
|
|
_logger.exception('Unable to retrieve buddy-list from presence '
|
|
|
|
|
'service')
|
|
|
|
|
return []
|
|
|
|
|
else:
|
|
|
|
|
buddies = []
|
|
|
|
@ -380,10 +376,8 @@ class PresenceService(gobject.GObject):
|
|
|
|
|
if error_handler:
|
|
|
|
|
error_handler(e)
|
|
|
|
|
else:
|
|
|
|
|
_logger.warn(
|
|
|
|
|
"""Unable to retrieve buddy-list from presence service: %s"""
|
|
|
|
|
% e
|
|
|
|
|
)
|
|
|
|
|
_logger.warn('Unable to retrieve buddy-list from presence '
|
|
|
|
|
'service: %s', e)
|
|
|
|
|
|
|
|
|
|
def get_buddies_async(self, reply_handler=None, error_handler=None):
|
|
|
|
|
"""Retrieve set of all buddies from service asyncronously
|
|
|
|
@ -411,12 +405,9 @@ class PresenceService(gobject.GObject):
|
|
|
|
|
"""
|
|
|
|
|
try:
|
|
|
|
|
buddy_op = self._ps.GetBuddyByPublicKey(dbus.ByteArray(key))
|
|
|
|
|
except dbus.exceptions.DBusException, err:
|
|
|
|
|
_logger.warn(
|
|
|
|
|
"""Unable to retrieve buddy handle
|
|
|
|
|
for %r from presence service: %s"""
|
|
|
|
|
% key, err
|
|
|
|
|
)
|
|
|
|
|
except dbus.exceptions.DBusException:
|
|
|
|
|
_logger.exception('Unable to retrieve buddy handle for %r from '
|
|
|
|
|
'presence service', key)
|
|
|
|
|
return None
|
|
|
|
|
return self._new_object(buddy_op)
|
|
|
|
|
|
|
|
|
@ -450,12 +441,9 @@ class PresenceService(gobject.GObject):
|
|
|
|
|
"""Retrieves the laptop "owner" Buddy object."""
|
|
|
|
|
try:
|
|
|
|
|
owner_op = self._ps.GetOwner()
|
|
|
|
|
except dbus.exceptions.DBusException, err:
|
|
|
|
|
_logger.warn(
|
|
|
|
|
"""Unable to retrieve local user/owner
|
|
|
|
|
from presence service: %s"""
|
|
|
|
|
% err
|
|
|
|
|
)
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
@ -526,7 +514,8 @@ class PresenceService(gobject.GObject):
|
|
|
|
|
|
|
|
|
|
return bus_name, object_path
|
|
|
|
|
|
|
|
|
|
class _OfflineInterface( object ):
|
|
|
|
|
|
|
|
|
|
class _OfflineInterface(object):
|
|
|
|
|
"""Offline-presence-service interface
|
|
|
|
|
|
|
|
|
|
Used to mimic the behaviour of a real PresenceService sufficiently
|
|
|
|
@ -535,33 +524,33 @@ class _OfflineInterface( object ):
|
|
|
|
|
XXX we could likely return a "MockOwner" object reasonably
|
|
|
|
|
easily, but would it be worth it?
|
|
|
|
|
"""
|
|
|
|
|
def raiseException( self, *args, **named ):
|
|
|
|
|
|
|
|
|
|
def raiseException(self, *args, **named):
|
|
|
|
|
"""Raise dbus.exceptions.DBusException"""
|
|
|
|
|
raise dbus.exceptions.DBusException(
|
|
|
|
|
"""PresenceService Interface not available"""
|
|
|
|
|
)
|
|
|
|
|
raise dbus.exceptions.DBusException('PresenceService Interface not '
|
|
|
|
|
'available')
|
|
|
|
|
|
|
|
|
|
GetActivities = raiseException
|
|
|
|
|
GetActivityById = raiseException
|
|
|
|
|
GetBuddies = raiseException
|
|
|
|
|
GetBuddyByPublicKey = raiseException
|
|
|
|
|
GetOwner = raiseException
|
|
|
|
|
GetPreferredConnection = raiseException
|
|
|
|
|
def ShareActivity(
|
|
|
|
|
self, actid, atype, name, properties,
|
|
|
|
|
reply_handler, error_handler,
|
|
|
|
|
):
|
|
|
|
|
|
|
|
|
|
def ShareActivity(self, actid, atype, name, properties, reply_handler,
|
|
|
|
|
error_handler):
|
|
|
|
|
"""Pretend to share and fail..."""
|
|
|
|
|
exc = IOError(
|
|
|
|
|
"""Unable to share activity as PresenceService
|
|
|
|
|
is not currenly available"""
|
|
|
|
|
)
|
|
|
|
|
return error_handler( exc )
|
|
|
|
|
exc = IOError('Unable to share activity as PresenceService is not '
|
|
|
|
|
'currently available')
|
|
|
|
|
return error_handler(exc)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class _MockPresenceService(gobject.GObject):
|
|
|
|
|
"""Test fixture allowing testing of items that use PresenceService
|
|
|
|
|
|
|
|
|
|
See PresenceService for usage and purpose
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
__gsignals__ = {
|
|
|
|
|
'buddy-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
|
|
|
|
([gobject.TYPE_PYOBJECT])),
|
|
|
|
@ -575,7 +564,7 @@ class _MockPresenceService(gobject.GObject):
|
|
|
|
|
'activity-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
|
|
|
|
([gobject.TYPE_PYOBJECT])),
|
|
|
|
|
'activity-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
|
|
|
|
([gobject.TYPE_PYOBJECT]))
|
|
|
|
|
([gobject.TYPE_PYOBJECT])),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
@ -599,11 +588,13 @@ class _MockPresenceService(gobject.GObject):
|
|
|
|
|
def share_activity(self, activity, properties=None):
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_ps = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_instance(allow_offline_iface=False):
|
|
|
|
|
"""Retrieve this process' view of the PresenceService"""
|
|
|
|
|
global _ps
|
|
|
|
|
if not _ps:
|
|
|
|
|
_ps = PresenceService(allow_offline_iface)
|
|
|
|
|
return _ps
|
|
|
|
|
|
|
|
|
|