Refcount tracked service types; ensure only the process that registers a service can change it; add support for updated service properties/published values

This commit is contained in:
Dan Williams 2006-09-15 16:41:11 -04:00
parent c36089522b
commit b39eff3365
5 changed files with 270 additions and 68 deletions

View File

@ -1,9 +1,11 @@
import os import os
import random import random
import base64 import base64
import time
import conf import conf
from sugar import env from sugar import env
import logging
from sugar.p2p import Stream from sugar.p2p import Stream
from sugar.presence import PresenceService from sugar.presence import PresenceService
from Friends import Friends from Friends import Friends
@ -15,7 +17,7 @@ class ShellOwner(object):
"""Class representing the owner of this machine/instance. This class """Class representing the owner of this machine/instance. This class
runs in the shell and serves up the buddy icon and other stuff. It's the runs in the shell and serves up the buddy icon and other stuff. It's the
server portion of the Owner, paired with the client portion in Buddy.py.""" server portion of the Owner, paired with the client portion in Buddy.py."""
def __init__(self): def __init__(self, shell):
profile = conf.get_profile() profile = conf.get_profile()
self._nick = profile.get_nick_name() self._nick = profile.get_nick_name()
@ -34,6 +36,12 @@ class ShellOwner(object):
self._friends = Friends() self._friends = Friends()
self._invites = Invites() self._invites = Invites()
self._shell = shell
self._shell.connect('activity-changed', self.__activity_changed_cb)
self._last_activity_update = time.time()
self._pending_activity_update_timer = None
self._pending_activity_update = None
def get_friends(self): def get_friends(self):
return self._friends return self._friends
@ -43,10 +51,14 @@ class ShellOwner(object):
def announce(self): def announce(self):
# Create and announce our presence # Create and announce our presence
color = conf.get_profile().get_color() color = conf.get_profile().get_color()
props = { 'color': color.to_string() } props = {'color':color.to_string()}
activity = self._shell.get_current_activity()
if activity is not None:
props['cur_activity':activity.get_id()]
self._last_activity_update = time.time()
self._service = self._pservice.register_service(self._nick, self._service = self._pservice.register_service(self._nick,
PRESENCE_SERVICE_TYPE, properties=props) PRESENCE_SERVICE_TYPE, properties=props)
print "Owner '%s' using port %d" % (self._nick, self._service.get_port()) logging.debug("Owner '%s' using port %d" % (self._nick, self._service.get_port()))
self._icon_stream = Stream.Stream.new_from_service(self._service) self._icon_stream = Stream.Stream.new_from_service(self._service)
self._icon_stream.register_reader_handler(self._handle_buddy_icon_request, "get_buddy_icon") self._icon_stream.register_reader_handler(self._handle_buddy_icon_request, "get_buddy_icon")
self._icon_stream.register_reader_handler(self._handle_invite, "invite") self._icon_stream.register_reader_handler(self._handle_invite, "invite")
@ -61,3 +73,31 @@ class ShellOwner(object):
"""XMLRPC method, called when the owner is invited to an activity.""" """XMLRPC method, called when the owner is invited to an activity."""
self._invites.add_invite(issuer, bundle_id, activity_id) self._invites.add_invite(issuer, bundle_id, activity_id)
return '' return ''
def __update_advertised_current_activity_cb(self):
self._last_activity_update = time.time()
self._pending_activity_update_timer = None
logging.debug("*** Updating current activity to %s" % self._pending_activity_update)
return False
def __activity_changed_cb(self, shell, activity):
"""Update our presence service with the latest activity, but no
more frequently than every 30 seconds"""
self._pending_activity_update = activity.get_id()
# If there's no pending update, we must not have updated it in the
# last 30 seconds (except for the initial update, hence we also check
# for the last update)
if not self._pending_activity_update_timer or time.time() - self._last_activity_update > 30:
self.__update_advertised_current_activity_cb()
return
# If we have a pending update already, we have nothing left to do
if self._pending_activity_update_timer:
return
# Otherwise, we start a timer to update the activity at the next
# interval, which should be 30 seconds from the last update, or if that
# is in the past already, then now
next = 30 - max(30, time.time() - self._last_activity_update)
self._pending_activity_update_timer = gobject.timeout_add(next * 1000,
self.__update_advertised_current_activity_cb)

View File

@ -56,6 +56,38 @@ class ServiceAdv(object):
raise ValueError("Can't reset to resolve pending from resolved.") raise ValueError("Can't reset to resolve pending from resolved.")
self._state = state self._state = state
class RegisteredServiceType(object):
def __init__(self, stype):
self._stype = stype
self._refcount = 1
def get_type(self):
return self._stype
def ref(self):
self._refcount += 1
def unref(self):
self._refcount -= 1
return self._refcount
def _txt_to_dict(txt):
"""Convert an avahi-returned TXT record formatted
as nested arrays of integers (from dbus) into a dict
of key/value string pairs."""
prop_dict = {}
props = avahi.txt_array_to_string_array(txt)
for item in props:
key = value = None
if '=' not in item:
# No = means a boolean value of true
key = item
value = True
else:
(key, value) = item.split('=')
prop_dict[key] = value
return prop_dict
_PRESENCE_SERVICE = "org.laptop.Presence" _PRESENCE_SERVICE = "org.laptop.Presence"
_PRESENCE_DBUS_INTERFACE = "org.laptop.Presence" _PRESENCE_DBUS_INTERFACE = "org.laptop.Presence"
@ -169,8 +201,9 @@ class PresenceServiceDBusHelper(dbus.service.Object):
return owner.object_path() return owner.object_path()
@dbus.service.method(_PRESENCE_DBUS_INTERFACE, @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
in_signature="os", out_signature="o") in_signature="os", out_signature="o",
def joinActivity(self, activity_op, stype): sender_keyword="sender")
def joinActivity(self, activity_op, stype, sender):
found_activity = None found_activity = None
acts = self._parent.get_activities() acts = self._parent.get_activities()
for act in acts: for act in acts:
@ -179,29 +212,34 @@ class PresenceServiceDBusHelper(dbus.service.Object):
break break
if not found_activity: if not found_activity:
raise NotFoundError("The activity %s was not found." % activity_op) raise NotFoundError("The activity %s was not found." % activity_op)
return self._parent.join_activity(found_activity, stype) return self._parent.join_activity(found_activity, stype, sender)
@dbus.service.method(_PRESENCE_DBUS_INTERFACE, @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
in_signature="ssa{ss}sis", out_signature="o") in_signature="ssa{ss}sis", out_signature="o",
def shareActivity(self, activity_id, stype, properties, address, port, domain): sender_keyword="sender")
def shareActivity(self, activity_id, stype, properties, address, port,
domain, sender=None):
if not len(address): if not len(address):
address = None address = None
service = self._parent.share_activity(activity_id, stype, properties, address, service = self._parent.share_activity(activity_id, stype, properties, address,
port, domain) port, domain, sender)
return service.object_path() return service.object_path()
@dbus.service.method(_PRESENCE_DBUS_INTERFACE, @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
in_signature="ssa{ss}sis", out_signature="o") in_signature="ssa{ss}sis", out_signature="o",
def registerService(self, name, stype, properties, address, port, domain): sender_keyword="sender")
def registerService(self, name, stype, properties, address, port, domain,
sender=None):
if not len(address): if not len(address):
address = None address = None
service = self._parent.register_service(name, stype, properties, address, service = self._parent.register_service(name, stype, properties, address,
port, domain) port, domain, sender)
return service.object_path() return service.object_path()
@dbus.service.method(_PRESENCE_DBUS_INTERFACE, @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
in_signature="o", out_signature="") in_signature="o", out_signature="",
def unregisterService(self, service_op): sender_keyword="sender")
def unregisterService(self, service_op, sender):
found_serv = None found_serv = None
services = self._parent.get_services() services = self._parent.get_services()
for serv in services: for serv in services:
@ -210,7 +248,7 @@ class PresenceServiceDBusHelper(dbus.service.Object):
break break
if not found_serv: if not found_serv:
raise NotFoundError("The activity %s was not found." % service_op) raise NotFoundError("The activity %s was not found." % service_op)
return self._parent.unregister_service(found_serv) return self._parent.unregister_service(found_serv, sender)
@dbus.service.method(_PRESENCE_DBUS_INTERFACE, @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
in_signature="s", out_signature="") in_signature="s", out_signature="")
@ -424,9 +462,10 @@ class PresenceService(object):
key = (full_name, stype) key = (full_name, stype)
if not self._services.has_key(key): if not self._services.has_key(key):
objid = self._get_next_object_id() objid = self._get_next_object_id()
props = _txt_to_dict(txt)
service = Service.Service(self._bus_name, objid, name=full_name, service = Service.Service(self._bus_name, objid, name=full_name,
stype=stype, domain=domain, address=address, port=port, stype=stype, domain=domain, address=address, port=port,
properties=txt, source_address=address, local=adv.is_local()) properties=props, source_address=address, local=adv.is_local())
self._services[key] = service self._services[key] = service
else: else:
# Already tracking this service; likely we were the one that shared it # Already tracking this service; likely we were the one that shared it
@ -588,19 +627,22 @@ class PresenceService(object):
def _new_domain_cb_glue(self, interface, protocol, domain, flags=0): def _new_domain_cb_glue(self, interface, protocol, domain, flags=0):
gobject.idle_add(self._new_domain_cb, interface, protocol, domain, flags) gobject.idle_add(self._new_domain_cb, interface, protocol, domain, flags)
def join_activity(self, activity, stype): def join_activity(self, activity, stype, sender):
services = activity.get_services_of_type(stype) services = activity.get_services_of_type(stype)
if not len(services): if not len(services):
raise NotFoundError("The service type %s was not present within the activity %s" % (stype, activity.object_path())) raise NotFoundError("The service type %s was not present within " \
"the activity %s" % (stype, activity.object_path()))
act_service = services[0] act_service = services[0]
props = act_service.get_properties() props = act_service.get_properties()
color = activity.get_color() color = activity.get_color()
if color: if color:
props['color'] = color props['color'] = color
return self._share_activity(activity.get_id(), stype, properties, return self._share_activity(activity.get_id(), stype, properties,
act_service.get_address(), act_service.get_port(), act_service.get_domain()) act_service.get_address(), act_service.get_port(),
act_service.get_domain(), sender)
def share_activity(self, activity_id, stype, properties=None, address=None, port=-1, domain=u"local"): def share_activity(self, activity_id, stype, properties=None, address=None,
port=-1, domain=u"local", sender=None):
"""Convenience function to share an activity with other buddies.""" """Convenience function to share an activity with other buddies."""
if not util.validate_activity_id(activity_id): if not util.validate_activity_id(activity_id):
raise ValueError("invalid activity id") raise ValueError("invalid activity id")
@ -621,14 +663,19 @@ class PresenceService(object):
if color: if color:
properties['color'] = color properties['color'] = color
logging.debug('Share activity %s, type %s, address %s, port %d, properties %s' % (activity_id, stype, address, port, properties)) logging.debug('Share activity %s, type %s, address %s, port %d, " \
return self.register_service(real_name, stype, properties, address, port, domain) "properties %s' % (activity_id, stype, address, port,
properties))
return self.register_service(real_name, stype, properties, address,
port, domain, sender)
def register_service(self, name, stype, properties={}, address=None, port=-1, domain=u"local"): def register_service(self, name, stype, properties={}, address=None,
port=-1, domain=u"local", sender=None):
"""Register a new service, advertising it to other Buddies on the network.""" """Register a new service, advertising it to other Buddies on the network."""
(actid, person_name) = Service.decompose_service_name(name) (actid, person_name) = Service.decompose_service_name(name)
if self.get_owner() and person_name != self.get_owner().get_name(): if self.get_owner() and person_name != self.get_owner().get_name():
raise RuntimeError("Tried to register a service that didn't have Owner nick as the service name!") raise RuntimeError("Tried to register a service that didn't have" \
" Owner nick as the service name!")
if not domain or not len(domain): if not domain or not len(domain):
domain = u"local" domain = u"local"
if not port or port == -1: if not port or port == -1:
@ -647,12 +694,14 @@ class PresenceService(object):
objid = self._get_next_object_id() objid = self._get_next_object_id()
service = Service.Service(self._bus_name, objid, name=name, service = Service.Service(self._bus_name, objid, name=name,
stype=stype, domain=domain, address=address, port=port, stype=stype, domain=domain, address=address, port=port,
properties=properties, source_address=None, local=True) properties=properties, source_address=None, local=True,
local_publisher=sender)
self._services[(name, stype)] = service self._services[(name, stype)] = service
port = service.get_port() port = service.get_port()
logging.debug("PS: Will register service with name='%s', stype='%s'," \ logging.debug("PS: Will register service with name='%s', stype='%s'," \
" domain='%s', address='%s', port=%d, info='%s'" % (name, stype, domain, address, port, info)) " domain='%s', address='%s', port=%d, info='%s'" % (name, stype,
domain, address, port, info))
group.AddService(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, 0, dbus.String(name), group.AddService(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, 0, dbus.String(name),
dbus.String(stype), dbus.String(domain), dbus.String(""), # let Avahi figure the 'host' out dbus.String(stype), dbus.String(domain), dbus.String(""), # let Avahi figure the 'host' out
dbus.UInt16(port), info) dbus.UInt16(port), info)
@ -667,7 +716,10 @@ class PresenceService(object):
self.register_service_type(stype) self.register_service_type(stype)
return service return service
def unregister_service(self, service): def unregister_service(self, service, sender=None):
local_publisher = service.get_local_publisher()
if sender is not None and local_publisher != sender:
raise ValueError("Service was not not registered by requesting process!")
group = service.get_avahi_entry_group() group = service.get_avahi_entry_group()
if not group: if not group:
raise ValueError("Service was not a local service provided by this laptop!") raise ValueError("Service was not a local service provided by this laptop!")
@ -678,9 +730,16 @@ class PresenceService(object):
a certain mDNS service types.""" a certain mDNS service types."""
if type(stype) != type(u""): if type(stype) != type(u""):
raise ValueError("service type must be a unicode string.") raise ValueError("service type must be a unicode string.")
if stype in self._registered_service_types:
return # If we've already registered it as a service type, ref it and return
self._registered_service_types.append(stype) for item in self._registered_service_types:
if item.get_type() == stype:
item.ref()
return
# Otherwise track this type now
obj = RegisteredServiceType(stype)
self._registered_service_types.append(obj)
# Find unresolved services that match the service type # Find unresolved services that match the service type
# we're now interested in, and resolve them # we're now interested in, and resolve them
@ -698,8 +757,15 @@ class PresenceService(object):
"""Stop tracking a certain mDNS service.""" """Stop tracking a certain mDNS service."""
if type(stype) != type(u""): if type(stype) != type(u""):
raise ValueError("service type must be a unicode string.") raise ValueError("service type must be a unicode string.")
if stype in self._registered_service_types: item = None
self._registered_service_types.remove(stype) for item in self._registered_service_types:
if item.get_type() == stype:
break
# if it was found, unref it and possibly remove it
if item is not None:
if item.unref() <= 0:
self._registered_service_types.remove(item)
del item
def main(): def main():

View File

@ -5,23 +5,6 @@ from sugar import util
import dbus, dbus.service import dbus, dbus.service
import random import random
def _txt_to_dict(txt):
"""Convert an avahi-returned TXT record formatted
as nested arrays of integers (from dbus) into a dict
of key/value string pairs."""
prop_dict = {}
props = avahi.txt_array_to_string_array(txt)
for item in props:
key = value = None
if '=' not in item:
# No = means a boolean value of true
key = item
value = True
else:
(key, value) = item.split('=')
prop_dict[key] = value
return prop_dict
def compose_service_name(name, activity_id): def compose_service_name(name, activity_id):
if type(name) == type(""): if type(name) == type(""):
name = unicode(name) name = unicode(name)
@ -67,6 +50,11 @@ class ServiceDBusHelper(dbus.service.Object):
self._object_path = object_path self._object_path = object_path
dbus.service.Object.__init__(self, bus_name, self._object_path) dbus.service.Object.__init__(self, bus_name, self._object_path)
@dbus.service.signal(SERVICE_DBUS_INTERFACE,
signature="as")
def PublishedValueChanged(self, keylist):
pass
@dbus.service.method(SERVICE_DBUS_INTERFACE, @dbus.service.method(SERVICE_DBUS_INTERFACE,
in_signature="", out_signature="a{sv}") in_signature="", out_signature="a{sv}")
def getProperties(self): def getProperties(self):
@ -90,14 +78,33 @@ class ServiceDBusHelper(dbus.service.Object):
return pary return pary
@dbus.service.method(SERVICE_DBUS_INTERFACE, @dbus.service.method(SERVICE_DBUS_INTERFACE,
in_signature="s", out_signature="s") in_signature="s")
def getPublishedValue(self, key): def getPublishedValue(self, key):
"""Return the value belonging to the requested key from the """Return the value belonging to the requested key from the
service's TXT records.""" service's TXT records."""
value = self._parent.get_one_property(key) val = self._parent.get_one_property(key)
if type(value) == type(True): if not val:
value = str(value) raise KeyError("Value was not found.")
return value return val
@dbus.service.method(SERVICE_DBUS_INTERFACE,
in_signature="", out_signature="a{sv}")
def getPublishedValues(self):
pary = {}
props = self._parent.get_properties()
for key, value in props.items():
pary[key] = str(value)
return dbus.Dictionary(pary)
@dbus.service.method(SERVICE_DBUS_INTERFACE,
sender_keyword="sender")
def setPublishedValue(self, key, value, sender):
self._parent.set_property(key, value, sender)
@dbus.service.method(SERVICE_DBUS_INTERFACE,
in_signature="a{sv}", sender_keyword="sender")
def setPublishedValues(self, values, sender):
self._parent.set_properties(values, sender)
class Service(object): class Service(object):
@ -105,7 +112,7 @@ class Service(object):
service as advertised on the network.""" service as advertised on the network."""
def __init__(self, bus_name, object_id, name, stype, domain=u"local", def __init__(self, bus_name, object_id, name, stype, domain=u"local",
address=None, port=-1, properties=None, source_address=None, address=None, port=-1, properties=None, source_address=None,
local=False): local=False, local_publisher=None):
if not bus_name: if not bus_name:
raise ValueError("DBus bus name must be valid") raise ValueError("DBus bus name must be valid")
if not object_id or type(object_id) != type(1): if not object_id or type(object_id) != type(1):
@ -137,7 +144,7 @@ class Service(object):
self._port = -1 self._port = -1
self.set_port(port) self.set_port(port)
self._properties = {} self._properties = {}
self.set_properties(properties) self._internal_set_properties(properties, first_time=True)
self._avahi_entry_group = None self._avahi_entry_group = None
self._local = local self._local = local
@ -159,13 +166,19 @@ class Service(object):
if self._properties.has_key(_ACTIVITY_ID_TAG): if self._properties.has_key(_ACTIVITY_ID_TAG):
prop_actid = self._properties[_ACTIVITY_ID_TAG] prop_actid = self._properties[_ACTIVITY_ID_TAG]
if (prop_actid and not actid) or (prop_actid != actid): if (prop_actid and not actid) or (prop_actid != actid):
raise ValueError("ActivityID property specified, but the service names's activity ID didn't match it: %s, %s" % (prop_actid, actid)) raise ValueError("ActivityID property specified, but the " \
"service names's activity ID didn't match it: %s," \
" %s" % (prop_actid, actid))
self._activity_id = actid self._activity_id = actid
if actid and not self._properties.has_key(_ACTIVITY_ID_TAG): if actid and not self._properties.has_key(_ACTIVITY_ID_TAG):
self._properties[_ACTIVITY_ID_TAG] = actid self._properties[_ACTIVITY_ID_TAG] = actid
self._owner = None self._owner = None
# ID of the D-Bus connection that published this service, if any.
# We only let the local publisher modify the service.
self._local_publisher = local_publisher
# register ourselves with dbus # register ourselves with dbus
self._object_id = object_id self._object_id = object_id
self._object_path = SERVICE_DBUS_OBJECT_PATH + str(self._object_id) self._object_path = SERVICE_DBUS_OBJECT_PATH + str(self._object_id)
@ -182,6 +195,9 @@ class Service(object):
raise RuntimeError("Can only set a service's owner once") raise RuntimeError("Can only set a service's owner once")
self._owner = owner self._owner = owner
def get_local_publisher(self):
return self._local_publisher
def is_local(self): def is_local(self):
return self._local return self._local
@ -207,19 +223,55 @@ class Service(object):
properties.""" properties."""
return self._properties return self._properties
def set_properties(self, properties): def set_property(self, key, value, sender=None):
"""Set one service property"""
if sender is not None and self._local_publisher != sender:
raise ValueError("Service was not not registered by requesting process!")
if type(key) != type(u""):
raise ValueError("Key must be a unicode string.")
if type(value) != type(u"") or type(value) != type(True):
raise ValueError("Key must be a unicode string or a boolean.")
# Ignore setting the key to it's current value
if self._properties.has_key(key):
if self._properties[key] == value:
return
# Blank value means remove key
remove = False
if type(value) == type(u"") and len(value) == 0:
remove = True
if type(value) == type(False) and value == False:
remove = True
if remove:
# If the key wasn't present, return without error
if self._properties.has_key(key):
del self._properties[key]
else:
# Otherwise set it
if type(value) == type(True):
value = ""
self._properties[key] = value
self._dbus_helper.PublishedValueChanged(key)
def set_properties(self, properties, sender=None):
"""Set all service properties in one call"""
if sender is not None and self._local_publisher != sender:
raise ValueError("Service was not not registered by requesting process!")
self._internal_set_properties(properties)
def _internal_set_properties(self, properties, first_time=False):
"""Set the service's properties from either an Avahi """Set the service's properties from either an Avahi
TXT record (a list of lists of integers), or a TXT record (a list of lists of integers), or a
python dictionary.""" python dictionary."""
if type(properties) != type({}):
raise ValueError("Properties must be a dictionary.")
self._properties = {} self._properties = {}
props = {}
if type(properties) == type([]):
props = _txt_to_dict(properties)
elif type(properties) == type({}):
props = properties
# Set key/value pairs on internal property list # Set key/value pairs on internal property list
for key, value in props.items(): for key, value in properties.items():
if len(key) == 0: if len(key) == 0:
continue continue
tmp_key = key tmp_key = key
@ -230,6 +282,9 @@ class Service(object):
tmp_val = unicode(tmp_val) tmp_val = unicode(tmp_val)
self._properties[tmp_key] = tmp_val self._properties[tmp_key] = tmp_val
if not first_time:
self._dbus_helper.PublishedValueChanged(self._properties.keys())
def get_type(self): def get_type(self):
"""Return the service's service type.""" """Return the service's service type."""
return self._stype return self._stype

View File

@ -73,7 +73,7 @@ class Shell(gobject.GObject):
PresenceService.start() PresenceService.start()
self._pservice = PresenceService.get_instance() self._pservice = PresenceService.get_instance()
self._owner = ShellOwner() self._owner = ShellOwner(self)
self._owner.announce() self._owner.announce()
self._home_window.set_owner(self._owner) self._home_window.set_owner(self._owner)

View File

@ -2,11 +2,29 @@ import gobject
import dbus import dbus
def __one_dict_differs(dict1, dict2):
for key, value in dict1.items():
if not dict2.has_key(key) or dict2[key] != value:
return True
return False
def __dicts_differ(dict1, dict2):
if __one_dict_differs(dict1, dict2):
return True
if __one_dict_differs(dict2, dict1):
return True
return False
class Service(gobject.GObject): class Service(gobject.GObject):
_PRESENCE_SERVICE = "org.laptop.Presence" _PRESENCE_SERVICE = "org.laptop.Presence"
_SERVICE_DBUS_INTERFACE = "org.laptop.Presence.Service" _SERVICE_DBUS_INTERFACE = "org.laptop.Presence.Service"
__gsignals__ = {
'published-value-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT]))
}
def __init__(self, bus, new_obj_cb, del_obj_cb, object_path): def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
gobject.GObject.__init__(self) gobject.GObject.__init__(self)
self._object_path = object_path self._object_path = object_path
@ -14,17 +32,40 @@ class Service(gobject.GObject):
self._ps_del_object = del_obj_cb self._ps_del_object = del_obj_cb
sobj = bus.get_object(self._PRESENCE_SERVICE, object_path) sobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
self._service = dbus.Interface(sobj, self._SERVICE_DBUS_INTERFACE) self._service = dbus.Interface(sobj, self._SERVICE_DBUS_INTERFACE)
self._service.connect_to_signal('PropertyChanged', self._property_changed_cb) self._service.connect_to_signal('PropertyChanged', self.__property_changed_cb)
self._service.connect_to_signal('PublishedValueChanged',
self.__published_value_changed_cb)
self._props = self._service.getProperties() self._props = self._service.getProperties()
self._pubvals = self._service.getPublishedValues()
def object_path(self): def object_path(self):
return self._object_path return self._object_path
def _property_changed_cb(self, prop_list): def __property_changed_cb(self, prop_list):
self._props = self._service.getProperties() self._props = self._service.getProperties()
def get_published_value(self, key): def get_published_value(self, key):
return self._service.getPublishedValue(key) return self._pubvals[key]
def get_published_values(self):
self._pubvals = self._service.getPublishedValues()
def set_published_value(self, key, value):
if self._pubvals.has_key(key):
if self._pubvals[key] == value:
return
self._pubvals[key] = value
self._service.setPublishedValue(key, value)
def set_published_values(self, vals):
self._service.setPublishedValues(vals)
self._pubvals = vals
def __published_value_changed_cb(self, keys):
oldvals = self._pubvals
self.get_published_values()
if __dicts_differ(oldvals, self._pubvals):
self.emit('published-value-changed', keys)
def get_name(self): def get_name(self):
return self._props['name'] return self._props['name']