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:
parent
c36089522b
commit
b39eff3365
@ -1,9 +1,11 @@
|
||||
import os
|
||||
import random
|
||||
import base64
|
||||
import time
|
||||
|
||||
import conf
|
||||
from sugar import env
|
||||
import logging
|
||||
from sugar.p2p import Stream
|
||||
from sugar.presence import PresenceService
|
||||
from Friends import Friends
|
||||
@ -15,7 +17,7 @@ class ShellOwner(object):
|
||||
"""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
|
||||
server portion of the Owner, paired with the client portion in Buddy.py."""
|
||||
def __init__(self):
|
||||
def __init__(self, shell):
|
||||
profile = conf.get_profile()
|
||||
|
||||
self._nick = profile.get_nick_name()
|
||||
@ -34,6 +36,12 @@ class ShellOwner(object):
|
||||
self._friends = Friends()
|
||||
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):
|
||||
return self._friends
|
||||
|
||||
@ -43,10 +51,14 @@ class ShellOwner(object):
|
||||
def announce(self):
|
||||
# Create and announce our presence
|
||||
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,
|
||||
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.register_reader_handler(self._handle_buddy_icon_request, "get_buddy_icon")
|
||||
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."""
|
||||
self._invites.add_invite(issuer, bundle_id, activity_id)
|
||||
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)
|
||||
|
@ -56,6 +56,38 @@ class ServiceAdv(object):
|
||||
raise ValueError("Can't reset to resolve pending from resolved.")
|
||||
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_DBUS_INTERFACE = "org.laptop.Presence"
|
||||
@ -169,8 +201,9 @@ class PresenceServiceDBusHelper(dbus.service.Object):
|
||||
return owner.object_path()
|
||||
|
||||
@dbus.service.method(_PRESENCE_DBUS_INTERFACE,
|
||||
in_signature="os", out_signature="o")
|
||||
def joinActivity(self, activity_op, stype):
|
||||
in_signature="os", out_signature="o",
|
||||
sender_keyword="sender")
|
||||
def joinActivity(self, activity_op, stype, sender):
|
||||
found_activity = None
|
||||
acts = self._parent.get_activities()
|
||||
for act in acts:
|
||||
@ -179,29 +212,34 @@ class PresenceServiceDBusHelper(dbus.service.Object):
|
||||
break
|
||||
if not found_activity:
|
||||
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,
|
||||
in_signature="ssa{ss}sis", out_signature="o")
|
||||
def shareActivity(self, activity_id, stype, properties, address, port, domain):
|
||||
in_signature="ssa{ss}sis", out_signature="o",
|
||||
sender_keyword="sender")
|
||||
def shareActivity(self, activity_id, stype, properties, address, port,
|
||||
domain, sender=None):
|
||||
if not len(address):
|
||||
address = None
|
||||
service = self._parent.share_activity(activity_id, stype, properties, address,
|
||||
port, domain)
|
||||
port, domain, sender)
|
||||
return service.object_path()
|
||||
|
||||
@dbus.service.method(_PRESENCE_DBUS_INTERFACE,
|
||||
in_signature="ssa{ss}sis", out_signature="o")
|
||||
def registerService(self, name, stype, properties, address, port, domain):
|
||||
in_signature="ssa{ss}sis", out_signature="o",
|
||||
sender_keyword="sender")
|
||||
def registerService(self, name, stype, properties, address, port, domain,
|
||||
sender=None):
|
||||
if not len(address):
|
||||
address = None
|
||||
service = self._parent.register_service(name, stype, properties, address,
|
||||
port, domain)
|
||||
port, domain, sender)
|
||||
return service.object_path()
|
||||
|
||||
@dbus.service.method(_PRESENCE_DBUS_INTERFACE,
|
||||
in_signature="o", out_signature="")
|
||||
def unregisterService(self, service_op):
|
||||
in_signature="o", out_signature="",
|
||||
sender_keyword="sender")
|
||||
def unregisterService(self, service_op, sender):
|
||||
found_serv = None
|
||||
services = self._parent.get_services()
|
||||
for serv in services:
|
||||
@ -210,7 +248,7 @@ class PresenceServiceDBusHelper(dbus.service.Object):
|
||||
break
|
||||
if not found_serv:
|
||||
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,
|
||||
in_signature="s", out_signature="")
|
||||
@ -424,9 +462,10 @@ class PresenceService(object):
|
||||
key = (full_name, stype)
|
||||
if not self._services.has_key(key):
|
||||
objid = self._get_next_object_id()
|
||||
props = _txt_to_dict(txt)
|
||||
service = Service.Service(self._bus_name, objid, name=full_name,
|
||||
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
|
||||
else:
|
||||
# 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):
|
||||
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)
|
||||
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]
|
||||
props = act_service.get_properties()
|
||||
color = activity.get_color()
|
||||
if color:
|
||||
props['color'] = color
|
||||
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."""
|
||||
if not util.validate_activity_id(activity_id):
|
||||
raise ValueError("invalid activity id")
|
||||
@ -621,14 +663,19 @@ class PresenceService(object):
|
||||
if color:
|
||||
properties['color'] = color
|
||||
|
||||
logging.debug('Share activity %s, type %s, address %s, port %d, properties %s' % (activity_id, stype, address, port, properties))
|
||||
return self.register_service(real_name, stype, properties, address, port, domain)
|
||||
logging.debug('Share activity %s, type %s, address %s, port %d, " \
|
||||
"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."""
|
||||
(actid, person_name) = Service.decompose_service_name(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):
|
||||
domain = u"local"
|
||||
if not port or port == -1:
|
||||
@ -647,12 +694,14 @@ class PresenceService(object):
|
||||
objid = self._get_next_object_id()
|
||||
service = Service.Service(self._bus_name, objid, name=name,
|
||||
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
|
||||
port = service.get_port()
|
||||
|
||||
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),
|
||||
dbus.String(stype), dbus.String(domain), dbus.String(""), # let Avahi figure the 'host' out
|
||||
dbus.UInt16(port), info)
|
||||
@ -667,7 +716,10 @@ class PresenceService(object):
|
||||
self.register_service_type(stype)
|
||||
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()
|
||||
if not group:
|
||||
raise ValueError("Service was not a local service provided by this laptop!")
|
||||
@ -678,9 +730,16 @@ class PresenceService(object):
|
||||
a certain mDNS service types."""
|
||||
if type(stype) != type(u""):
|
||||
raise ValueError("service type must be a unicode string.")
|
||||
if stype in self._registered_service_types:
|
||||
return
|
||||
self._registered_service_types.append(stype)
|
||||
|
||||
# If we've already registered it as a service type, ref it and return
|
||||
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
|
||||
# we're now interested in, and resolve them
|
||||
@ -698,8 +757,15 @@ class PresenceService(object):
|
||||
"""Stop tracking a certain mDNS service."""
|
||||
if type(stype) != type(u""):
|
||||
raise ValueError("service type must be a unicode string.")
|
||||
if stype in self._registered_service_types:
|
||||
self._registered_service_types.remove(stype)
|
||||
item = None
|
||||
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():
|
||||
|
@ -5,23 +5,6 @@ from sugar import util
|
||||
import dbus, dbus.service
|
||||
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):
|
||||
if type(name) == type(""):
|
||||
name = unicode(name)
|
||||
@ -67,6 +50,11 @@ class ServiceDBusHelper(dbus.service.Object):
|
||||
self._object_path = 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,
|
||||
in_signature="", out_signature="a{sv}")
|
||||
def getProperties(self):
|
||||
@ -90,14 +78,33 @@ class ServiceDBusHelper(dbus.service.Object):
|
||||
return pary
|
||||
|
||||
@dbus.service.method(SERVICE_DBUS_INTERFACE,
|
||||
in_signature="s", out_signature="s")
|
||||
in_signature="s")
|
||||
def getPublishedValue(self, key):
|
||||
"""Return the value belonging to the requested key from the
|
||||
service's TXT records."""
|
||||
value = self._parent.get_one_property(key)
|
||||
if type(value) == type(True):
|
||||
value = str(value)
|
||||
return value
|
||||
val = self._parent.get_one_property(key)
|
||||
if not val:
|
||||
raise KeyError("Value was not found.")
|
||||
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):
|
||||
@ -105,7 +112,7 @@ class Service(object):
|
||||
service as advertised on the network."""
|
||||
def __init__(self, bus_name, object_id, name, stype, domain=u"local",
|
||||
address=None, port=-1, properties=None, source_address=None,
|
||||
local=False):
|
||||
local=False, local_publisher=None):
|
||||
if not bus_name:
|
||||
raise ValueError("DBus bus name must be valid")
|
||||
if not object_id or type(object_id) != type(1):
|
||||
@ -137,7 +144,7 @@ class Service(object):
|
||||
self._port = -1
|
||||
self.set_port(port)
|
||||
self._properties = {}
|
||||
self.set_properties(properties)
|
||||
self._internal_set_properties(properties, first_time=True)
|
||||
self._avahi_entry_group = None
|
||||
self._local = local
|
||||
|
||||
@ -159,13 +166,19 @@ class Service(object):
|
||||
if self._properties.has_key(_ACTIVITY_ID_TAG):
|
||||
prop_actid = self._properties[_ACTIVITY_ID_TAG]
|
||||
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
|
||||
if actid and not self._properties.has_key(_ACTIVITY_ID_TAG):
|
||||
self._properties[_ACTIVITY_ID_TAG] = actid
|
||||
|
||||
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
|
||||
self._object_id = 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")
|
||||
self._owner = owner
|
||||
|
||||
def get_local_publisher(self):
|
||||
return self._local_publisher
|
||||
|
||||
def is_local(self):
|
||||
return self._local
|
||||
|
||||
@ -207,19 +223,55 @@ class Service(object):
|
||||
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
|
||||
TXT record (a list of lists of integers), or a
|
||||
python dictionary."""
|
||||
if type(properties) != type({}):
|
||||
raise ValueError("Properties must be a dictionary.")
|
||||
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
|
||||
for key, value in props.items():
|
||||
for key, value in properties.items():
|
||||
if len(key) == 0:
|
||||
continue
|
||||
tmp_key = key
|
||||
@ -230,6 +282,9 @@ class Service(object):
|
||||
tmp_val = unicode(tmp_val)
|
||||
self._properties[tmp_key] = tmp_val
|
||||
|
||||
if not first_time:
|
||||
self._dbus_helper.PublishedValueChanged(self._properties.keys())
|
||||
|
||||
def get_type(self):
|
||||
"""Return the service's service type."""
|
||||
return self._stype
|
||||
|
@ -73,7 +73,7 @@ class Shell(gobject.GObject):
|
||||
PresenceService.start()
|
||||
self._pservice = PresenceService.get_instance()
|
||||
|
||||
self._owner = ShellOwner()
|
||||
self._owner = ShellOwner(self)
|
||||
self._owner.announce()
|
||||
|
||||
self._home_window.set_owner(self._owner)
|
||||
|
@ -2,11 +2,29 @@ import gobject
|
||||
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):
|
||||
|
||||
_PRESENCE_SERVICE = "org.laptop.Presence"
|
||||
_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):
|
||||
gobject.GObject.__init__(self)
|
||||
self._object_path = object_path
|
||||
@ -14,17 +32,40 @@ class Service(gobject.GObject):
|
||||
self._ps_del_object = del_obj_cb
|
||||
sobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
|
||||
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._pubvals = self._service.getPublishedValues()
|
||||
|
||||
def object_path(self):
|
||||
return self._object_path
|
||||
|
||||
def _property_changed_cb(self, prop_list):
|
||||
def __property_changed_cb(self, prop_list):
|
||||
self._props = self._service.getProperties()
|
||||
|
||||
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):
|
||||
return self._props['name']
|
||||
|
Loading…
Reference in New Issue
Block a user