services/presence/: Pass the SessionBus around, instead of a BusName object.

Delay making the BusName object until after the PS object has been exported,
to guarantee race-free activation.
This commit is contained in:
Simon McVittie 2007-05-25 16:21:02 +01:00
parent ad33f7dfdd
commit 9721436536
4 changed files with 52 additions and 39 deletions

View File

@ -39,7 +39,10 @@ _PROP_CUSTOM_PROPS = "custom-props"
_logger = logging.getLogger('s-p-s.activity') _logger = logging.getLogger('s-p-s.activity')
class Activity(ExportedGObject): class Activity(ExportedGObject):
"""Represents a potentially shareable activity on the network. """Represents a shared activity seen on the network, or a local activity
that has been, or will be, shared onto the network.
The activity might be public, restricted to a group, or invite-only.
""" """
__gtype_name__ = "Activity" __gtype_name__ = "Activity"
@ -68,12 +71,12 @@ class Activity(ExportedGObject):
_RESERVED_PROPNAMES = __gproperties__.keys() _RESERVED_PROPNAMES = __gproperties__.keys()
def __init__(self, bus_name, object_id, tp, **kwargs): def __init__(self, bus, object_id, tp, **kwargs):
"""Initializes the activity and sets its properties to default values. """Initializes the activity and sets its properties to default values.
:Parameters: :Parameters:
`bus_name` : dbus.service.BusName `bus` : dbus.bus.BusConnection
D-Bus well-known name for the Presence Service A connection to the D-Bus session bus
`object_id` : int `object_id` : int
PS ID for this activity, used to construct the object-path PS ID for this activity, used to construct the object-path
`tp` : server plugin `tp` : server plugin
@ -95,8 +98,6 @@ class Activity(ExportedGObject):
Activity-specific properties Activity-specific properties
""" """
if not bus_name:
raise ValueError("DBus bus name must be valid")
if not object_id or not isinstance(object_id, int): if not object_id or not isinstance(object_id, int):
raise ValueError("object id must be a valid number") raise ValueError("object id must be a valid number")
if not tp: if not tp:
@ -133,7 +134,7 @@ class Activity(ExportedGObject):
if not util.validate_activity_id(kwargs[_PROP_ID]): if not util.validate_activity_id(kwargs[_PROP_ID]):
raise ValueError("Invalid activity id '%s'" % kwargs[_PROP_ID]) raise ValueError("Invalid activity id '%s'" % kwargs[_PROP_ID])
ExportedGObject.__init__(self, bus_name, self._object_path, ExportedGObject.__init__(self, bus, self._object_path,
gobject_properties=kwargs) gobject_properties=kwargs)
if self.props.local and not self.props.valid: if self.props.local and not self.props.valid:
raise RuntimeError("local activities require color, type, and " raise RuntimeError("local activities require color, type, and "
@ -262,9 +263,9 @@ class Activity(ExportedGObject):
@dbus.service.method(_ACTIVITY_INTERFACE, @dbus.service.method(_ACTIVITY_INTERFACE,
in_signature="", out_signature="s") in_signature="", out_signature="s")
def GetId(self): def GetId(self):
"""DBUS method to get this activity's ID """DBUS method to get this activity's (randomly generated) unique ID
returns Activity ID :Returns: Activity ID as a string
""" """
return self.props.id return self.props.id
@ -273,7 +274,7 @@ class Activity(ExportedGObject):
def GetColor(self): def GetColor(self):
"""DBUS method to get this activity's colour """DBUS method to get this activity's colour
returns Activity colour :Returns: Activity colour as a string in the format #RRGGBB,#RRGGBB
""" """
return self.props.color return self.props.color
@ -282,7 +283,8 @@ class Activity(ExportedGObject):
def GetType(self): def GetType(self):
"""DBUS method to get this activity's type """DBUS method to get this activity's type
returns Activity type :Returns: Activity type as a string, in the same form as a D-Bus
well-known name
""" """
return self.props.type return self.props.type
@ -305,7 +307,10 @@ class Activity(ExportedGObject):
"""DBUS method to return a list of valid buddies who are joined in """DBUS method to return a list of valid buddies who are joined in
this activity this activity
returns A list of buddy object paths :Returns:
A list of buddy object paths corresponding to those buddies
in this activity who are 'valid' (i.e. for whom we have complete
information)
""" """
ret = [] ret = []
for buddy in self._buddies: for buddy in self._buddies:
@ -319,8 +324,14 @@ class Activity(ExportedGObject):
"""DBUS method to get the list of channels associated with this """DBUS method to get the list of channels associated with this
activity activity
returns XXX - Not sure what this returns as get_channels doesn't :Returns:
actually return a list of channels! a tuple containing:
- the D-Bus well-known service name of the connection
(FIXME: this is redundant; in Telepathy it can be derived
from that of the connection)
- the D-Bus object path of the connection
- a list of D-Bus object paths representing the channels
associated with this activity
""" """
return self.get_channels() return self.get_channels()

View File

@ -102,22 +102,19 @@ class Buddy(ExportedGObject):
_PROP_IP4_ADDRESS : (str, None, None, None, gobject.PARAM_READWRITE) _PROP_IP4_ADDRESS : (str, None, None, None, gobject.PARAM_READWRITE)
} }
def __init__(self, bus_name, object_id, **kwargs): def __init__(self, bus, object_id, **kwargs):
"""Initialize the Buddy object """Initialize the Buddy object
bus_name -- DBUS object bus name (identifier) bus -- connection to the D-Bus session bus
object_id -- the activity's unique identifier object_id -- the activity's unique identifier
kwargs -- used to initialize the object's properties kwargs -- used to initialize the object's properties
constructs a DBUS "object path" from the _BUDDY_PATH constructs a DBUS "object path" from the _BUDDY_PATH
and object_id and object_id
""" """
if not bus_name:
raise ValueError("DBus bus name must be valid")
if not object_id or not isinstance(object_id, int): if not object_id or not isinstance(object_id, int):
raise ValueError("object id must be a valid number") raise ValueError("object id must be a valid number")
self._bus_name = bus_name
self._object_path = _BUDDY_PATH + str(object_id) self._object_path = _BUDDY_PATH + str(object_id)
self._activities = {} # Activity ID -> Activity self._activities = {} # Activity ID -> Activity
@ -150,7 +147,7 @@ class Buddy(ExportedGObject):
icon_data = kwargs[_PROP_ICON] icon_data = kwargs[_PROP_ICON]
del kwargs[_PROP_ICON] del kwargs[_PROP_ICON]
ExportedGObject.__init__(self, bus_name, self._object_path, ExportedGObject.__init__(self, bus, self._object_path,
gobject_properties=kwargs) gobject_properties=kwargs)
if icon_data: if icon_data:
@ -499,11 +496,11 @@ class GenericOwner(Buddy):
""" """
__gtype_name__ = "GenericOwner" __gtype_name__ = "GenericOwner"
def __init__(self, ps, bus_name, object_id, **kwargs): def __init__(self, ps, bus, object_id, **kwargs):
"""Initialize the GenericOwner instance """Initialize the GenericOwner instance
ps -- presenceservice.PresenceService object ps -- presenceservice.PresenceService object
bus_name -- DBUS object bus name (identifier) bus -- a connection to the D-Bus session bus
object_id -- the activity's unique identifier object_id -- the activity's unique identifier
kwargs -- used to initialize the object's properties kwargs -- used to initialize the object's properties
@ -520,7 +517,7 @@ class GenericOwner(Buddy):
if self._ip4_addr_monitor.props.address: if self._ip4_addr_monitor.props.address:
kwargs["ip4-address"] = self._ip4_addr_monitor.props.address kwargs["ip4-address"] = self._ip4_addr_monitor.props.address
Buddy.__init__(self, bus_name, object_id, **kwargs) Buddy.__init__(self, bus, object_id, **kwargs)
self._owner = True self._owner = True
self._bus = dbus.SessionBus() self._bus = dbus.SessionBus()
@ -561,11 +558,11 @@ class ShellOwner(GenericOwner):
_SHELL_OWNER_INTERFACE = "org.laptop.Shell.Owner" _SHELL_OWNER_INTERFACE = "org.laptop.Shell.Owner"
_SHELL_PATH = "/org/laptop/Shell" _SHELL_PATH = "/org/laptop/Shell"
def __init__(self, ps, bus_name, object_id, test=False): def __init__(self, ps, bus, object_id, test=False):
"""Initialize the ShellOwner instance """Initialize the ShellOwner instance
ps -- presenceservice.PresenceService object ps -- presenceservice.PresenceService object
bus_name -- DBUS object bus name (identifier) bus -- a connection to the D-Bus session bus
object_id -- the activity's unique identifier object_id -- the activity's unique identifier
test -- ignored test -- ignored
@ -587,7 +584,7 @@ class ShellOwner(GenericOwner):
icon = f.read() icon = f.read()
f.close() f.close()
GenericOwner.__init__(self, ps, bus_name, object_id, key=key, GenericOwner.__init__(self, ps, bus, object_id, key=key,
nick=nick, color=color, icon=icon, server=server, nick=nick, color=color, icon=icon, server=server,
key_hash=key_hash, registered=registered) key_hash=key_hash, registered=registered)

View File

@ -57,7 +57,7 @@ class PresenceService(ExportedGObject):
def _create_owner(self): def _create_owner(self):
# Overridden by TestPresenceService # Overridden by TestPresenceService
return ShellOwner(self, self._bus_name, self._get_next_object_id()) return ShellOwner(self, self._session_bus, self._get_next_object_id())
def __init__(self): def __init__(self):
self._next_object_id = 0 self._next_object_id = 0
@ -67,11 +67,10 @@ class PresenceService(ExportedGObject):
self._handles_buddies = {} # tp client -> (handle -> Buddy) self._handles_buddies = {} # tp client -> (handle -> Buddy)
self._activities = {} # activity id -> Activity self._activities = {} # activity id -> Activity
bus = dbus.SessionBus() self._session_bus = dbus.SessionBus()
self._bus_name = dbus.service.BusName(_PRESENCE_SERVICE, bus=bus) self._session_bus.add_signal_receiver(self._connection_disconnected_cb,
bus.add_signal_receiver(self._connection_disconnected_cb, signal_name="Disconnected",
signal_name="Disconnected", dbus_interface="org.freedesktop.DBus")
dbus_interface="org.freedesktop.DBus")
# Create the Owner object # Create the Owner object
self._owner = self._create_owner() self._owner = self._create_owner()
@ -104,7 +103,13 @@ class PresenceService(ExportedGObject):
self._ll_plugin = LinkLocalPlugin(self._registry, self._owner) self._ll_plugin = LinkLocalPlugin(self._registry, self._owner)
self._handles_buddies[self._ll_plugin] = {} self._handles_buddies[self._ll_plugin] = {}
ExportedGObject.__init__(self, self._bus_name, _PRESENCE_PATH) ExportedGObject.__init__(self, self._session_bus, _PRESENCE_PATH)
# for activation to work in a race-free way, we should really
# export the bus name only after we export our initial object;
# so this comes after the parent __init__
self._bus_name = dbus.service.BusName(_PRESENCE_SERVICE,
bus=self._session_bus)
def _connection_disconnected_cb(self, foo=None): def _connection_disconnected_cb(self, foo=None):
"""Log event when D-Bus kicks us off the bus for some reason""" """Log event when D-Bus kicks us off the bus for some reason"""
@ -135,7 +140,7 @@ class PresenceService(ExportedGObject):
if not buddy: if not buddy:
# we don't know yet this buddy # we don't know yet this buddy
objid = self._get_next_object_id() objid = self._get_next_object_id()
buddy = Buddy(self._bus_name, objid, key=key) buddy = Buddy(self._session_bus, objid, key=key)
buddy.connect("validity-changed", self._buddy_validity_changed_cb) buddy.connect("validity-changed", self._buddy_validity_changed_cb)
buddy.connect("disappeared", self._buddy_disappeared_cb) buddy.connect("disappeared", self._buddy_disappeared_cb)
self._buddies[key] = buddy self._buddies[key] = buddy
@ -194,7 +199,7 @@ class PresenceService(ExportedGObject):
def _new_activity(self, activity_id, tp): def _new_activity(self, activity_id, tp):
try: try:
objid = self._get_next_object_id() objid = self._get_next_object_id()
activity = Activity(self._bus_name, objid, tp, id=activity_id) activity = Activity(self._session_bus, objid, tp, id=activity_id)
except Exception: except Exception:
# FIXME: catching bare Exception considered harmful # FIXME: catching bare Exception considered harmful
_logger.debug("Invalid activity:", exc_info=1) _logger.debug("Invalid activity:", exc_info=1)
@ -392,7 +397,7 @@ class PresenceService(ExportedGObject):
objid = self._get_next_object_id() objid = self._get_next_object_id()
# FIXME check which tp client we should use to share the activity # FIXME check which tp client we should use to share the activity
color = self._owner.props.color color = self._owner.props.color
activity = Activity(self._bus_name, objid, self._server_plugin, activity = Activity(self._session_bus, objid, self._server_plugin,
id=actid, type=atype, name=name, color=color, id=actid, type=atype, name=name, color=color,
local=True) local=True)
activity.connect("validity-changed", activity.connect("validity-changed",

View File

@ -20,7 +20,7 @@ class TestOwner(GenericOwner):
__gtype_name__ = "TestOwner" __gtype_name__ = "TestOwner"
def __init__(self, ps, bus_name, object_id, test_num, randomize): def __init__(self, ps, bus, object_id, test_num, randomize):
self._cp = ConfigParser() self._cp = ConfigParser()
self._section = "Info" self._section = "Info"
self._test_activities = [] self._test_activities = []
@ -45,7 +45,7 @@ class TestOwner(GenericOwner):
icon = _get_random_image() icon = _get_random_image()
_logger.debug("pubkey is %s" % pubkey) _logger.debug("pubkey is %s" % pubkey)
GenericOwner.__init__(self, ps, bus_name, object_id, key=pubkey, nick=nick, GenericOwner.__init__(self, ps, bus, object_id, key=pubkey, nick=nick,
color=color, icon=icon, registered=registered, key_hash=privkey_hash) color=color, icon=icon, registered=registered, key_hash=privkey_hash)
# Only do the random stuff if randomize is true # Only do the random stuff if randomize is true
@ -152,7 +152,7 @@ class TestPresenceService(PresenceService):
PresenceService.__init__(self) PresenceService.__init__(self)
def _create_owner(self): def _create_owner(self):
return TestOwner(self, self._bus_name, self._get_next_object_id(), return TestOwner(self, self._session_bus, self._get_next_object_id(),
self.__test_num, self.__randomize) self.__test_num, self.__randomize)
def internal_get_activity(self, actid): def internal_get_activity(self, actid):