Try to avoid Sugar's shell just crashing and leaving a blank X server
when the PresenceService isn't available on the back-end for whatever reason, whether mis-configuration, corrupted installation, unexpected circumstances, or what have you. This patch makes as few changes as possible to the code, simply replacing the _ps member with a property that re-attempts connection on each access until an attempt is successful.
This commit is contained in:
parent
a0ee487a40
commit
a7af5b06cd
@ -132,18 +132,64 @@ class PresenceService(gobject.GObject):
|
|||||||
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Initialise the service and connect to events"""
|
"""Initialise the service and attempt to connect to events
|
||||||
|
"""
|
||||||
gobject.GObject.__init__(self)
|
gobject.GObject.__init__(self)
|
||||||
self._objcache = ObjectCache()
|
self._objcache = ObjectCache()
|
||||||
self._bus = dbus.SessionBus()
|
# attempt to load the interface to the service...
|
||||||
self._ps = dbus.Interface(self._bus.get_object(DBUS_SERVICE,
|
self._get_ps()
|
||||||
DBUS_PATH), DBUS_INTERFACE)
|
|
||||||
self._ps.connect_to_signal('BuddyAppeared', self._buddy_appeared_cb)
|
_bus_ = None
|
||||||
self._ps.connect_to_signal('BuddyDisappeared', self._buddy_disappeared_cb)
|
def _get_bus( self ):
|
||||||
self._ps.connect_to_signal('ActivityAppeared', self._activity_appeared_cb)
|
"""Retrieve dbus session-bus or create new"""
|
||||||
self._ps.connect_to_signal('ActivityDisappeared', self._activity_disappeared_cb)
|
if not self._bus_:
|
||||||
self._ps.connect_to_signal('ActivityInvitation', self._activity_invitation_cb)
|
self._bus_ = dbus.SessionBus()
|
||||||
self._ps.connect_to_signal('PrivateInvitation', self._private_invitation_cb)
|
return self._bus_
|
||||||
|
_bus = property(
|
||||||
|
_get_bus, None, None,
|
||||||
|
"""DBUS SessionBus object for user-local communications"""
|
||||||
|
)
|
||||||
|
_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:
|
||||||
|
ps = dbus.Interface(
|
||||||
|
self._bus.get_object(DBUS_SERVICE,DBUS_PATH),
|
||||||
|
DBUS_INTERFACE
|
||||||
|
)
|
||||||
|
except dbus.exceptions.DBusException, err:
|
||||||
|
logging.error(
|
||||||
|
"""Failure retrieving %r interface from the D-BUS service %r %r: %s""",
|
||||||
|
DBUS_INTERFACE, DBUS_SERVICE, DBUS_PATH, err
|
||||||
|
)
|
||||||
|
return _OfflineInterface()
|
||||||
|
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
|
||||||
@ -350,6 +396,35 @@ class PresenceService(gobject.GObject):
|
|||||||
|
|
||||||
return bus_name, object_path
|
return bus_name, object_path
|
||||||
|
|
||||||
|
class _OfflineInterface( object ):
|
||||||
|
"""Offline-presence-service interface
|
||||||
|
|
||||||
|
Used to mimic the behaviour of a real PresenceService sufficiently
|
||||||
|
to avoid crashing client code that expects the given interface.
|
||||||
|
|
||||||
|
XXX we could likely return a "MockOwner" object reasonably
|
||||||
|
easily, but would it be worth it?
|
||||||
|
"""
|
||||||
|
def raiseException( self, *args, **named ):
|
||||||
|
"""Raise dbus.exceptions.DBusException"""
|
||||||
|
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,
|
||||||
|
):
|
||||||
|
"""Pretend to share and fail..."""
|
||||||
|
exc = IOError(
|
||||||
|
"""Unable to share activity as PresenceService is not currenly available"""
|
||||||
|
)
|
||||||
|
return error_handler( exc )
|
||||||
|
|
||||||
class _MockPresenceService(gobject.GObject):
|
class _MockPresenceService(gobject.GObject):
|
||||||
"""Test fixture allowing testing of items that use PresenceService
|
"""Test fixture allowing testing of items that use PresenceService
|
||||||
|
Loading…
Reference in New Issue
Block a user