Continue to fill out presence service to the spec

This commit is contained in:
Dan Williams 2006-07-19 00:10:35 -04:00
parent 08a52809a6
commit f413416e15
4 changed files with 339 additions and 118 deletions

View File

@ -1,5 +1,7 @@
import dbus import dbus
class NotFoundError(Exception):
pass
class ActivityDBusHelper(dbus.service.Object): class ActivityDBusHelper(dbus.service.Object):
def __init__(self, parent, bus_name, object_path): def __init__(self, parent, bus_name, object_path):
@ -8,22 +10,129 @@ class ActivityDBusHelper(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.method(BUDDY_DBUS_INTERFACE,
in_signature="s", out_signature="ao")
def getServicesOfType(self, stype):
services = self._parent.get_services_of_type(stype)
if not services:
raise NotFoundError("Not found")
ret = []
for serv in services:
ret.append(serv.object_path())
return ret
@dbus.service.method(BUDDY_DBUS_INTERFACE,
in_signature="", out_signature="ao")
def getServices(self):
services = self._parent.get_services()
if not services:
raise NotFoundError("Not found")
ret = []
for serv in services:
ret.append(serv.object_path())
return ret
@dbus.service.method(BUDDY_DBUS_INTERFACE,
in_signature="", out_signature="s")
def getId(self):
return self._parent.get_id()
@dbus.service.method(BUDDY_DBUS_INTERFACE,
in_signature="", out_signature="ao")
def getJoinedBuddies(self):
buddies = self._parent.get_joined_buddies()
if not buddies:
raise NotFoundError("Not found")
ret = []
for buddy in buddies:
ret.append(buddy.object_path())
return ret
@dbus.service.signal(BUDDY_DBUS_INTERFACE,
out_signature="o")
def ServiceAppeared(self, object_path):
pass
@dbus.service.signal(BUDDY_DBUS_INTERFACE,
out_signature="o")
def ServiceDisappeared(self, object_path):
pass
@dbus.service.signal(BUDDY_DBUS_INTERFACE,
out_signature="o")
def BuddyJoined(self, object_path):
pass
@dbus.service.signal(BUDDY_DBUS_INTERFACE,
out_signature="o")
def BuddyLeft(self, object_path):
pass
class Activity(object): class Activity(object):
def __init__(self, bus_name, object_id, activity_id): def __init__(self, bus_name, object_id, activity_id):
if not activity_id:
raise ValueError("Service must have a valid Activity ID")
self._activity_id = activity_id self._activity_id = activity_id
self._buddies = [] self._buddies = []
self._services = {} # service type -> Service self._services = {} # service type -> list of Services
self._services[service.get_type()] = []
self._object_id = object_id self._object_id = object_id
self._object_path = "/org/laptop/Presence/Activities/%d" % self._object_id self._object_path = "/org/laptop/Presence/Activities/%d" % self._object_id
self._dbus_helper = ActivityDBusHelper(self, bus_name, self._object_path) self._dbus_helper = ActivityDBusHelper(self, bus_name, self._object_path)
def object_path(self):
return dbus.ObjectPath(self._object_path)
def get_id(self): def get_id(self):
return self._activity_id return self._activity_id
def get_service_of_type(self, stype): def get_services(self):
return self._services.values()
def get_services_of_type(self, stype):
if self._services.has_key(stype): if self._services.has_key(stype):
return self._services[stype] return self._services[stype]
return None return None
def get_joined_buddies(self):
buddies = []
for serv in self._services.values():
buddies.append(serv.get_owner())
return buddies
def add_service(self, service):
stype = service.get_type()
if not self._services.has_key(stype):
self._services[stype] = []
# Send out the BuddyJoined signal if this is the first
# service from the buddy that we've seen
buddies = self.get_joined_buddies()
serv_owner = service.get_owner()
if serv_owner and serv_owner not in buddies:
self._dbus_helper.BuddyJoined(serv_owner.object_path())
serv_owner.add_activity(self)
if not service in self._services[stype]:
self._services[stype].append(service)
self._dbus_helper.ServiceAppeared(service.object_path())
def remove_service(self, service):
stype = service.get_type()
if not self._services.has_key(stype):
return
self._services[stype].remove(service)
self._dbus_helper.ServiceDisappeared(service.object_path())
if len(self._services[stype]) == 0:
del self._services[stype]
# Send out the BuddyLeft signal if this is the last
# service from the buddy
buddies = self.get_joined_buddies()
serv_owner = service.get_owner()
if serv_owner and serv_owner not in buddies:
serv_owner.remove_activity(self)
self._dbus_helper.BuddyLeft(serv_owner.object_path())

View File

@ -3,10 +3,8 @@ import logging
import gtk import gtk
import gobject import gobject
import dbus, dbus.service
from sugar.p2p import Stream
from sugar.p2p import network
from sugar.presence import Service
PRESENCE_SERVICE_TYPE = "_presence_olpc._tcp" PRESENCE_SERVICE_TYPE = "_presence_olpc._tcp"
BUDDY_DBUS_INTERFACE = "org.laptop.Presence.Buddy" BUDDY_DBUS_INTERFACE = "org.laptop.Presence.Buddy"
@ -21,11 +19,13 @@ class BuddyDBusHelper(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(BUDDY_DBUS_INTERFACE) @dbus.service.signal(BUDDY_DBUS_INTERFACE,
out_signature="o")
def ServiceAppeared(self, object_path): def ServiceAppeared(self, object_path):
pass pass
@dbus.service.signal(BUDDY_DBUS_INTERFACE) @dbus.service.signal(BUDDY_DBUS_INTERFACE,
out_signature="o")
def ServiceDisappeared(self, object_path): def ServiceDisappeared(self, object_path):
pass pass
@ -33,11 +33,13 @@ class BuddyDBusHelper(dbus.service.Object):
def IconChanged(self): def IconChanged(self):
pass pass
@dbus.service.signal(BUDDY_DBUS_INTERFACE) @dbus.service.signal(BUDDY_DBUS_INTERFACE,
out_signature="o")
def JoinedActivity(self, object_path): def JoinedActivity(self, object_path):
pass pass
@dbus.service.signal(BUDDY_DBUS_INTERFACE) @dbus.service.signal(BUDDY_DBUS_INTERFACE,
out_signature="o")
def LeftActivity(self, object_path): def LeftActivity(self, object_path):
pass pass
@ -77,7 +79,7 @@ class Buddy(object):
"""Represents another person on the network and keeps track of the """Represents another person on the network and keeps track of the
activities and resources they make available for sharing.""" activities and resources they make available for sharing."""
def __init__(self, bus_name, object_id, service): def __init__(self, bus_name, object_id, service, owner=False):
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):
@ -91,18 +93,20 @@ class Buddy(object):
self._valid = False self._valid = False
self._icon = None self._icon = None
self._icon_tries = 0 self._icon_tries = 0
self._owner = False self._owner = owner
self.add_service(service)
self._object_id = object_id self._object_id = object_id
self._object_path = "/org/laptop/Presence/Buddies/%d" % self._object_id self._object_path = "/org/laptop/Presence/Buddies/%d" % self._object_id
self._dbus_helper = BuddyDBusHelper(self, bus_name, self._object_path) self._dbus_helper = BuddyDBusHelper(self, bus_name, self._object_path)
self.add_service(service)
def object_path(self): def object_path(self):
return self._object_path return dbus.ObjectPath(self._object_path)
def _request_buddy_icon_cb(self, result_status, response, user_data): def _request_buddy_icon_cb(self, result_status, response, user_data):
"""Callback when icon request has completed.""" """Callback when icon request has completed."""
from sugar.p2p import network
icon = response icon = response
service = user_data service = user_data
if result_status == network.RESULT_SUCCESS: if result_status == network.RESULT_SUCCESS:
@ -120,6 +124,7 @@ class Buddy(object):
def _request_buddy_icon(self, service): def _request_buddy_icon(self, service):
"""Contact the buddy to retrieve the buddy icon.""" """Contact the buddy to retrieve the buddy icon."""
from sugar.p2p import Stream
buddy_stream = Stream.Stream.new_from_service(service, start_reader=False) buddy_stream = Stream.Stream.new_from_service(service, start_reader=False)
writer = buddy_stream.new_writer(service) writer = buddy_stream.new_writer(service)
success = writer.custom_request("get_buddy_icon", self._request_buddy_icon_cb, service) success = writer.custom_request("get_buddy_icon", self._request_buddy_icon_cb, service)
@ -141,21 +146,7 @@ class Buddy(object):
if stype in self._services.keys(): if stype in self._services.keys():
return False return False
self._services[stype] = service self._services[stype] = service
if self._valid: service.set_owner(self)
self._dbus_helper.ServiceAppeared(dbus.ObjectPath(service.object_path()))
# If this is the first service we've seen that's owned by
# a particular activity, send out the 'joined-activity' signal
actid = service.get_activity_id()
if actid is not None:
found = False
for serv in self._services.values():
if serv.get_activity_id() == actid and serv.get_type() != stype:
found = True
break
if not found:
print "Buddy (%s) joined activity %s." % (self._nick_name, actid)
self._dbus_helper.JoinedActivity(dbus.ObjectPath(activity.object_path()))
if stype == PRESENCE_SERVICE_TYPE: if stype == PRESENCE_SERVICE_TYPE:
# A buddy isn't valid until its official presence # A buddy isn't valid until its official presence
@ -163,8 +154,26 @@ class Buddy(object):
self._valid = True self._valid = True
print 'Requesting buddy icon %s' % self._nick_name print 'Requesting buddy icon %s' % self._nick_name
self._request_buddy_icon(service) self._request_buddy_icon(service)
if self._valid:
self._dbus_helper.ServiceAppeared(service.object_path())
return True return True
def add_activity(self, activity):
actid = activity.get_id()
if activity in self._activities.values():
raise RuntimeError("Tried to add activity twice")
found = False
for serv in self._services.values():
if serv.get_activity_id() == activity.get_id():
found = True
break
if not found:
raise RuntimeError("Tried to add activity for which we had no service")
self._activities[actid] = activity
print "Buddy (%s) joined activity %s." % (self._nick_name, actid)
self._dbus_helper.JoinedActivity(activity.object_path())
def remove_service(self, service): def remove_service(self, service):
"""Remove a service from a buddy; ie, the activity was closed """Remove a service from a buddy; ie, the activity was closed
or the buddy went away.""" or the buddy went away."""
@ -175,25 +184,20 @@ class Buddy(object):
stype = service.get_type() stype = service.get_type()
if self._services.has_key(stype): if self._services.has_key(stype):
if self._valid: if self._valid:
self._dbus_helper.ServiceDisappeared(dbus.ObjectPath(service.object_path())) self._dbus_helper.ServiceDisappeared(service.object_path())
del self._services[stype] del self._services[stype]
# If this is the lase service owned by a particular activity,
# and it's just been removed, send out the 'left-actvity' signal
actid = service.get_activity_id()
if actid is not None:
found = False
for serv in self._services.values():
if serv.get_activity_id() == actid:
found = True
break
if not found:
print "Buddy (%s) left activity %s." % (self._nick_name, actid)
self._dbus_helper.LeftActivity(dbus.ObjectPath(activity.object_path()))
if stype == PRESENCE_SERVICE_TYPE: if stype == PRESENCE_SERVICE_TYPE:
self._valid = False self._valid = False
def remove_activity(self, activity):
actid = activity.get_id()
if not self._activities.has_key(actid):
return
del self._activities[actid]
print "Buddy (%s) left activity %s." % (self._nick_name, actid)
self._dbus_helper.LeftActivity(activity.object_path())
def get_service_of_type(self, stype=None, activity=None): def get_service_of_type(self, stype=None, activity=None):
"""Return a service of a certain type, or None if the buddy """Return a service of a certain type, or None if the buddy
doesn't provide that service.""" doesn't provide that service."""
@ -248,6 +252,5 @@ class Buddy(object):
class Owner(Buddy): class Owner(Buddy):
"""Class representing the owner of the machine. This is the client """Class representing the owner of the machine. This is the client
portion of the Owner, paired with the server portion in Owner.py.""" portion of the Owner, paired with the server portion in Owner.py."""
def __init__(self, service): def __init__(self, bus_name, object_id, service):
Buddy.__init__(self, service) Buddy.__init__(self, bus_name, object_id, service, owner=True)
self._owner = True

View File

@ -64,13 +64,54 @@ class ServiceAdv(object):
self._resolved = resolved self._resolved = resolved
_PRESENCE_INTERFACE = "org.laptop.Presence" _PRESENCE_SERVICE = "org.laptop.Presence"
_PRESENCE_DBUS_INTERFACE = "org.laptop.Presence"
_PRESENCE_OBJECT_PATH = "/org/laptop/Presence"
class PresenceService(dbus.service.Object): class PresenceServiceDBusHelper(dbus.service.Object):
def __init__(self, parent, bus_name):
self._parent = parent
self._bus_name = bus_name
dbus.service.Object.__init__(self, bus_name, _PRESENCE_OBJECT_PATH)
@dbus.service.signal(_PRESENCE_DBUS_INTERFACE,
out_signature="o")
def BuddyAppeared(self, object_path):
pass
@dbus.service.signal(_PRESENCE_DBUS_INTERFACE,
out_signature="o")
def BuddyDisappeared(self, object_path):
pass
@dbus.service.signal(_PRESENCE_DBUS_INTERFACE,
out_signature="o")
def ServiceAppeared(self, object_path):
pass
@dbus.service.signal(_PRESENCE_DBUS_INTERFACE,
out_signature="o")
def ServiceDisappeared(self, object_path):
pass
@dbus.service.signal(_PRESENCE_DBUS_INTERFACE,
out_signature="o")
def ActivityAppeared(self, object_path):
pass
@dbus.service.signal(_PRESENCE_DBUS_INTERFACE,
out_signature="o")
def ActivityDisappeared(self, object_path):
pass
class PresenceService(object):
def __init__(self): def __init__(self):
# interface -> IP address: interfaces we've gotten events on so far # interface -> IP address: interfaces we've gotten events on so far
self._local_addrs = {} self._local_addrs = {}
self._next_object_id = 0
# Our owner object # Our owner object
self._owner = None self._owner = None
@ -86,19 +127,19 @@ class PresenceService(dbus.service.Object):
# Resolved service list # Resolved service list
self._service_advs = [] self._service_advs = []
# Service types we care about resolving
self._registered_service_types = []
# Set up the dbus service we provide # Set up the dbus service we provide
session_bus = dbus.SessionBus() session_bus = dbus.SessionBus()
bus_name = dbus.service.BusName('org.laptop.Presence', bus=session_bus) self._bus_name = dbus.service.BusName(_PRESENCE_SERVICE, bus=session_bus)
dbus.service.Object.__init__(self, bus_name, '/org/laptop/Presence') self._dbus_helper = PresenceServiceDBusHelper(self, self._bus_name)
# Connect to Avahi for mDNS stuff # Connect to Avahi for mDNS stuff
self._system_bus = dbus.SystemBus() self._system_bus = dbus.SystemBus()
self._mdns_service = dbus.Interface(self._bus.get_object(avahi.DBUS_NAME, self._mdns_service = dbus.Interface(self._bus.get_object(avahi.DBUS_NAME,
avahi.DBUS_PATH_SERVER), avahi.DBUS_INTERFACE_SERVER) avahi.DBUS_PATH_SERVER), avahi.DBUS_INTERFACE_SERVER)
# Start browsing the local mDNS domain
self._start()
def _start(self):
# Always browse .local # Always browse .local
self._new_domain_cb(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, "local") self._new_domain_cb(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, "local")
@ -108,6 +149,11 @@ class PresenceService(dbus.service.Object):
db = dbus.Interface(self._system_bus.get_object(avahi.DBUS_NAME, domain_browser), avahi.DBUS_INTERFACE_DOMAIN_BROWSER) db = dbus.Interface(self._system_bus.get_object(avahi.DBUS_NAME, domain_browser), avahi.DBUS_INTERFACE_DOMAIN_BROWSER)
db.connect_to_signal('ItemNew', self._new_domain_cb_glue) db.connect_to_signal('ItemNew', self._new_domain_cb_glue)
def _get_next_object_id(self):
"""Increment and return the object ID counter."""
self._next_object_id = self._next_object_id + 1
return self._next_object_id
def _find_service_adv(self, interface=None, protocol=None, name=None, stype=None, domain=None): def _find_service_adv(self, interface=None, protocol=None, name=None, stype=None, domain=None):
"""Search a list of service advertisements for ones matching certain criteria.""" """Search a list of service advertisements for ones matching certain criteria."""
adv_list = [] adv_list = []
@ -125,6 +171,110 @@ class PresenceService(dbus.service.Object):
adv_list.append(adv) adv_list.append(adv)
return adv_list return adv_list
def _handle_new_service_for_buddy(self, service):
"""Deal with a new discovered service object."""
# Once a service is resolved, we match it up to an existing buddy,
# or create a new Buddy if this is the first service known about the buddy
buddy_was_valid = False
name = service.get_name()
buddy = None
try:
buddy = self._buddies[name]
buddy_was_valid = buddy.is_valid()
service_added = buddy.add_service(service)
if service_added:
self._dbus_helper.ServiceAppeared(service.object_path())
except KeyError:
# Should this service mark the owner?
owner_nick = env.get_nick_name()
publisher_addr = service.get_publisher_address()
objid = self._get_next_object_id()
if name == owner_nick and publisher_addr in self._local_addrs.values():
buddy = Buddy.Owner(self._bus_name, objid, service)
self._owner = buddy
logging.debug("Owner is '%s'." % name)
else:
buddy = Buddy.Buddy(self._bus_name, objid, service)
self._buddies[name] = buddy
self._dbus_helper.ServiceAppeared(service.object_path())
if not buddy_was_valid and buddy.is_valid():
self._dbus_helper.BuddyAppeared(buddy.object_path())
return buddy
def _handle_new_activity_service(self, service):
# If the serivce is an activity service, merge it into our activities list
actid = service.get_activity_id()
if not actid:
return
activity = None
if not self._activities.has_key(actid):
objid = self._get_next_object_id()
activity = Activity.Activity(self._bus_name, objid, service)
self._activities[actid] = activity
self._dbus_helper.ActivityAppeared(activity.object_path())
else:
activity = self._activities[actid]
if activity:
activity.add_service(service)
def _handle_remove_activity_service(self, service):
actid = service.get_activity_id()
if not actid:
return
if not self._activities.has_key(actid):
return
activity = self._activities[actid]
activity.remove_service(service)
if len(activity.get_services()) == 0:
# Kill the activity
self._dbus_helper.ActivityDisappeared(activity.object_path())
del self._activities[actid]
def _resolve_service_reply_cb(self, interface, protocol, full_name, stype, domain, host, aprotocol, address, port, txt, flags):
"""When the service discovery finally gets here, we've got enough information about the
service to assign it to a buddy."""
logging.debug("resolved service '%s' type '%s' domain '%s' to %s:%s" % (full_name, stype, domain, address, port))
# If this service was previously unresolved, remove it from the
# unresolved list
adv_list = self._find_service_adv(interface=interface, protocol=protocol,
name=full_name, stype=stype, domain=domain)
if not adv_list:
return False
adv = adv_list[0]
adv.set_resolved(True)
if adv in self._resolve_queue:
self._resolve_queue.remove(adv)
# Update the service now that it's been resolved
objid = self._get_next_object_id()
service = Service.Service(self._bus_name, objid, name=full_name,
stype=stype, domain=domain, address=address, port=port,
properties=txt)
adv.set_service(service)
# Merge the service into our buddy and activity lists, if needed
buddy = self._handle_new_service_for_buddy(service)
if buddy and service.get_activity_id():
self._handle_new_activity_service(service)
return False
def _resolve_service_reply_cb_glue(self, interface, protocol, name, stype, domain, host, aprotocol, address, port, txt, flags):
gobject.idle_add(self._resolve_service_reply_cb, interface, protocol,
name, stype, domain, host, aprotocol, address, port, txt, flags)
def _resolve_service(self, adv):
"""Resolve and lookup a ZeroConf service to obtain its address and TXT records."""
# Ask avahi to resolve this particular service
logging.debug('resolving service %s %s' % (adv.name(), adv.stype()))
self._server.ResolveService(int(adv.interface()), int(adv.protocol()), adv.name(),
adv.stype(), adv.domain(), avahi.PROTO_UNSPEC, dbus.UInt32(0),
reply_handler=self._resolve_service_reply_cb_glue,
error_handler=self._resolve_service_error_handler)
return False
def _service_appeared_cb(self, interface, protocol, full_name, stype, domain, flags): def _service_appeared_cb(self, interface, protocol, full_name, stype, domain, flags):
logging.debug("found service '%s' (%d) of type '%s' in domain '%s' on %i.%i." % (full_name, flags, stype, domain, interface, protocol)) logging.debug("found service '%s' (%d) of type '%s' in domain '%s' on %i.%i." % (full_name, flags, stype, domain, interface, protocol))
@ -150,14 +300,9 @@ class PresenceService(dbus.service.Object):
# Decompose service name if we can # Decompose service name if we can
(actid, buddy_name) = Service._decompose_service_name(full_name) (actid, buddy_name) = Service._decompose_service_name(full_name)
# FIXME: find a better way of letting the StartPage get everything
self.emit('new-service-adv', actid, stype)
# If we care about the service right now, resolve it # If we care about the service right now, resolve it
resolve = False resolve = False
if actid is not None or stype in self._allowed_service_types: if actid is not None or stype in self._registered_service_types:
resolve = True
if self._is_special_service_type(stype):
resolve = True resolve = True
if resolve and not adv in self._resolve_queue: if resolve and not adv in self._resolve_queue:
self._resolve_queue.append(adv) self._resolve_queue.append(adv)
@ -197,11 +342,11 @@ class PresenceService(dbus.service.Object):
pass pass
else: else:
buddy.remove_service(service) buddy.remove_service(service)
self.emit('service-disappeared', buddy, service) self._dbus_helper.ServiceDisappeared(service.object_path())
self._handle_remove_activity_service(service)
if not buddy.is_valid(): if not buddy.is_valid():
self.emit("buddy-disappeared", buddy) self._dbus_helper.BuddyDisappeared(buddy.object_path())
del self._buddies[buddy_name] del self._buddies[buddy_name]
self._handle_remove_service_for_activity(service, buddy)
return False return False
@ -257,3 +402,13 @@ class PresenceService(dbus.service.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 main():
import gtk
ps = PresenceService()
gtk.main()
if __name__ == "__main__":
main()

View File

@ -63,44 +63,6 @@ def is_multicast_address(address):
return True return True
return False return False
def deserialize(sdict):
try:
name = sdict['name']
if type(name) != type(u""):
raise ValueError("name must be unicode.")
stype = sdict['stype']
if type(stype) != type(u""):
raise ValueError("type must be unicode.")
domain = sdict['domain']
if type(domain) != type(u""):
raise ValueError("domain must be unicode.")
port = sdict['port']
properties = sdict['properties']
except KeyError, exc:
raise ValueError("Serialized service object was not valid.")
address = None
try:
address = sdict['address']
if type(address) != type(u""):
raise ValueError("address must be unicode.")
except KeyError:
pass
activity_id = None
try:
activity_id = sdict['activity_id']
if type(activity_id) != type(u""):
raise ValueError("activity id must be unicode.")
except KeyError:
pass
if activity_id is not None:
name = compose_service_name(name, activity_id)
return Service(name, stype, domain, address=address,
port=port, properties=properties)
_ACTIVITY_ID_TAG = "ActivityID" _ACTIVITY_ID_TAG = "ActivityID"
SERVICE_DBUS_INTERFACE = "org.laptop.Presence.Service" SERVICE_DBUS_INTERFACE = "org.laptop.Presence.Service"
@ -197,29 +159,23 @@ class Service(object):
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
# register ourselves with dbus # register ourselves with dbus
self._object_id = object_id self._object_id = object_id
self._object_path = "/org/laptop/Presence/Services/%d" % self._object_id self._object_path = "/org/laptop/Presence/Services/%d" % self._object_id
self._dbus_helper = ServiceDBusHelper(self, bus_name, self._object_path) self._dbus_helper = ServiceDBusHelper(self, bus_name, self._object_path)
def object_path(self): def object_path(self):
return self._object_path return dbus.ObjectPath(self._object_path)
def serialize(self, owner=None): def get_owner(self):
sdict = {} return self._owner
if owner is not None:
sdict['name'] = dbus.Variant(owner.get_nick_name()) def set_owner(self, owner):
else: if self._owner is not None:
sdict['name'] = dbus.Variant(self._name) raise RuntimeError("Can only set a service's owner once")
sdict['stype'] = dbus.Variant(self._stype) self._owner = owner
if self._activity_id:
sdict['activity_id'] = dbus.Variant(self._activity_id)
sdict['domain'] = dbus.Variant(self._domain)
if self._address:
sdict['address'] = dbus.Variant(self._address)
sdict['port'] = dbus.Variant(self._port)
sdict['properties'] = dbus.Variant(self._properties)
return sdict
def get_name(self): def get_name(self):
"""Return the service's name, usually that of the """Return the service's name, usually that of the
@ -256,9 +212,7 @@ class Service(object):
elif type(properties) == type({}): elif type(properties) == type({}):
props = properties props = properties
# Set key/value pairs on internal property list, # Set key/value pairs on internal property list
# also convert everything to local encoding (for now)
# to ensure consistency
for key, value in props.items(): for key, value in props.items():
tmp_key = key tmp_key = key
tmp_val = value tmp_val = value