Merge branch 'master' of git+ssh://dev.laptop.org/git/sugar
This commit is contained in:
commit
a292b642e1
@ -7,6 +7,7 @@ import dbus, dbus.service
|
|||||||
|
|
||||||
|
|
||||||
PRESENCE_SERVICE_TYPE = "_presence_olpc._tcp"
|
PRESENCE_SERVICE_TYPE = "_presence_olpc._tcp"
|
||||||
|
BUDDY_DBUS_OBJECT_PATH = "/org/laptop/Presence/Buddies/"
|
||||||
BUDDY_DBUS_INTERFACE = "org.laptop.Presence.Buddy"
|
BUDDY_DBUS_INTERFACE = "org.laptop.Presence.Buddy"
|
||||||
|
|
||||||
class NotFoundError(Exception):
|
class NotFoundError(Exception):
|
||||||
@ -85,6 +86,8 @@ class Buddy(object):
|
|||||||
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):
|
||||||
raise ValueError("object id must be a valid number")
|
raise ValueError("object id must be a valid number")
|
||||||
|
if not isinstance(service, Service.Service):
|
||||||
|
raise ValueError("service must be a valid service object")
|
||||||
|
|
||||||
self._services = {}
|
self._services = {}
|
||||||
self._activities = {}
|
self._activities = {}
|
||||||
@ -97,7 +100,7 @@ class Buddy(object):
|
|||||||
self._owner = owner
|
self._owner = owner
|
||||||
|
|
||||||
self._object_id = object_id
|
self._object_id = object_id
|
||||||
self._object_path = "/org/laptop/Presence/Buddies/%d" % self._object_id
|
self._object_path = BUDDY_DBUS_OBJECT_PATH + str(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)
|
self.add_service(service)
|
||||||
@ -255,3 +258,73 @@ class Owner(Buddy):
|
|||||||
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, bus_name, object_id, service):
|
def __init__(self, bus_name, object_id, service):
|
||||||
Buddy.__init__(self, bus_name, object_id, service, owner=True)
|
Buddy.__init__(self, bus_name, object_id, service, owner=True)
|
||||||
|
|
||||||
|
|
||||||
|
#################################################################
|
||||||
|
# Tests
|
||||||
|
#################################################################
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import Service
|
||||||
|
|
||||||
|
__objid_seq = 0
|
||||||
|
def _next_objid():
|
||||||
|
global __objid_seq
|
||||||
|
__objid_seq = __objid_seq + 1
|
||||||
|
return __objid_seq
|
||||||
|
|
||||||
|
|
||||||
|
class BuddyTestCase(unittest.TestCase):
|
||||||
|
_DEF_NAME = u"Tommy"
|
||||||
|
_DEF_STYPE = unicode(PRESENCE_SERVICE_TYPE)
|
||||||
|
_DEF_DOMAIN = u"local"
|
||||||
|
_DEF_ADDRESS = u"1.1.1.1"
|
||||||
|
_DEF_PORT = 1234
|
||||||
|
|
||||||
|
def __init__(self, name):
|
||||||
|
self._bus = dbus.SessionBus()
|
||||||
|
self._bus_name = dbus.service.BusName('org.laptop.Presence', bus=self._bus)
|
||||||
|
unittest.TestCase.__init__(self, name)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
del self._bus_name
|
||||||
|
del self._bus
|
||||||
|
|
||||||
|
def _test_init_fail(self, service, fail_msg):
|
||||||
|
"""Test something we expect to fail."""
|
||||||
|
try:
|
||||||
|
objid = _next_objid()
|
||||||
|
buddy = Buddy(self._bus_name, objid, service, owner=False)
|
||||||
|
except ValueError, exc:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.fail("expected a ValueError for %s." % fail_msg)
|
||||||
|
|
||||||
|
def testService(self):
|
||||||
|
service = None
|
||||||
|
self._test_init_fail(service, "invalid service")
|
||||||
|
|
||||||
|
def testGoodInit(self):
|
||||||
|
objid = _next_objid()
|
||||||
|
service = Service.Service(self._bus_name, objid, self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN,
|
||||||
|
self._DEF_ADDRESS, self._DEF_PORT)
|
||||||
|
objid = _next_objid()
|
||||||
|
buddy = Buddy(self._bus_name, objid, service)
|
||||||
|
assert buddy.get_nick_name() == self._DEF_NAME, "buddy name wasn't correct after init."
|
||||||
|
assert buddy.get_address() == self._DEF_ADDRESS, "buddy address wasn't correct after init."
|
||||||
|
assert buddy.object_path() == BUDDY_DBUS_OBJECT_PATH + str(objid)
|
||||||
|
|
||||||
|
def addToSuite(suite):
|
||||||
|
suite.addTest(BuddyTestCase("testService"))
|
||||||
|
suite.addTest(BuddyTestCase("testGoodInit"))
|
||||||
|
addToSuite = staticmethod(addToSuite)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
suite = unittest.TestSuite()
|
||||||
|
BuddyTestCase.addToSuite(suite)
|
||||||
|
runner = unittest.TextTestRunner()
|
||||||
|
runner.run(suite)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
@ -68,6 +68,9 @@ _PRESENCE_SERVICE = "org.laptop.Presence"
|
|||||||
_PRESENCE_DBUS_INTERFACE = "org.laptop.Presence"
|
_PRESENCE_DBUS_INTERFACE = "org.laptop.Presence"
|
||||||
_PRESENCE_OBJECT_PATH = "/org/laptop/Presence"
|
_PRESENCE_OBJECT_PATH = "/org/laptop/Presence"
|
||||||
|
|
||||||
|
class NotFoundError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
class PresenceServiceDBusHelper(dbus.service.Object):
|
class PresenceServiceDBusHelper(dbus.service.Object):
|
||||||
def __init__(self, parent, bus_name):
|
def __init__(self, parent, bus_name):
|
||||||
self._parent = parent
|
self._parent = parent
|
||||||
@ -104,6 +107,74 @@ class PresenceServiceDBusHelper(dbus.service.Object):
|
|||||||
def ActivityDisappeared(self, object_path):
|
def ActivityDisappeared(self, object_path):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@dbus.service.method(_PRESENCE_DBUS_INTERFACE,
|
||||||
|
in_signature="", out_signature="ao")
|
||||||
|
def getServices(self):
|
||||||
|
services = self._parent.get_services()
|
||||||
|
ret = []
|
||||||
|
for serv in services:
|
||||||
|
ret.append(serv.object_path())
|
||||||
|
return ret
|
||||||
|
|
||||||
|
@dbus.service.method(_PRESENCE_DBUS_INTERFACE,
|
||||||
|
in_signature="s", out_signature="ao")
|
||||||
|
def getServicesOfType(self, stype):
|
||||||
|
services = self._parent.get_services_of_type(stype)
|
||||||
|
ret = []
|
||||||
|
for serv in services:
|
||||||
|
ret.append(serv.object_path())
|
||||||
|
return ret
|
||||||
|
|
||||||
|
@dbus.service.method(_PRESENCE_DBUS_INTERFACE,
|
||||||
|
in_signature="", out_signature="ao")
|
||||||
|
def getActivities(self):
|
||||||
|
activities = self._parent.get_activities()
|
||||||
|
ret = []
|
||||||
|
for act in activities:
|
||||||
|
ret.append(act.object_path())
|
||||||
|
return ret
|
||||||
|
|
||||||
|
@dbus.service.method(_PRESENCE_DBUS_INTERFACE,
|
||||||
|
in_signature="s", out_signature="o")
|
||||||
|
def getActivity(self, actid):
|
||||||
|
act = self._parent.get_activity(actid)
|
||||||
|
if not act:
|
||||||
|
raise NotFoundError("Not found")
|
||||||
|
return act.object_path()
|
||||||
|
|
||||||
|
@dbus.service.method(_PRESENCE_DBUS_INTERFACE,
|
||||||
|
in_signature="", out_signature="ao")
|
||||||
|
def getBuddies(self):
|
||||||
|
buddies = self._parent.get_buddies()
|
||||||
|
ret = []
|
||||||
|
for buddy in buddies:
|
||||||
|
ret.append(buddy.object_path())
|
||||||
|
return ret
|
||||||
|
|
||||||
|
@dbus.service.method(_PRESENCE_DBUS_INTERFACE,
|
||||||
|
in_signature="s", out_signature="o")
|
||||||
|
def getBuddyByName(self, name):
|
||||||
|
buddy = self._parent.get_buddy_by_name(name)
|
||||||
|
if not buddy:
|
||||||
|
raise NotFoundError("Not found")
|
||||||
|
return buddy.object_path()
|
||||||
|
|
||||||
|
@dbus.service.method(_PRESENCE_DBUS_INTERFACE,
|
||||||
|
in_signature="s", out_signature="o")
|
||||||
|
def getBuddyByAddress(self, addr):
|
||||||
|
buddy = self._parent.get_buddy_by_address(addr)
|
||||||
|
if not buddy:
|
||||||
|
raise NotFoundError("Not found")
|
||||||
|
return buddy.object_path()
|
||||||
|
|
||||||
|
@dbus.service.method(_PRESENCE_DBUS_INTERFACE,
|
||||||
|
in_signature="", out_signature="o")
|
||||||
|
def getOwner(self):
|
||||||
|
owner = self._parent.get_owner()
|
||||||
|
if not owner:
|
||||||
|
raise NotFoundError("Not found")
|
||||||
|
return owner.object_path()
|
||||||
|
|
||||||
|
|
||||||
class PresenceService(object):
|
class PresenceService(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -154,6 +225,41 @@ class PresenceService(object):
|
|||||||
self._next_object_id = self._next_object_id + 1
|
self._next_object_id = self._next_object_id + 1
|
||||||
return self._next_object_id
|
return self._next_object_id
|
||||||
|
|
||||||
|
def get_services(self):
|
||||||
|
return self._services.values()
|
||||||
|
|
||||||
|
def get_services_of_type(self, stype):
|
||||||
|
ret = []
|
||||||
|
for serv in self._services.values():
|
||||||
|
if serv.get_type() == stype:
|
||||||
|
ret.append(serv)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def get_activities(self):
|
||||||
|
return self._activities.values()
|
||||||
|
|
||||||
|
def get_activity(self, actid):
|
||||||
|
if self._activities.has_key(actid):
|
||||||
|
return self._activities[actid]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_buddies(self):
|
||||||
|
return self._buddies.values()
|
||||||
|
|
||||||
|
def get_buddy_by_name(self, name):
|
||||||
|
if self._buddies.has_key(name):
|
||||||
|
return self._buddies[name]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_buddy_by_address(self, address):
|
||||||
|
for buddy in self._buddies.values():
|
||||||
|
if buddy.get_address() == address:
|
||||||
|
return buddy
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_owner(self):
|
||||||
|
return self._owner
|
||||||
|
|
||||||
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 = []
|
||||||
@ -247,11 +353,16 @@ class PresenceService(object):
|
|||||||
if adv in self._resolve_queue:
|
if adv in self._resolve_queue:
|
||||||
self._resolve_queue.remove(adv)
|
self._resolve_queue.remove(adv)
|
||||||
|
|
||||||
# Update the service now that it's been resolved
|
# See if we know about this service already
|
||||||
|
key = (full_name, stype)
|
||||||
|
if not self._services.has_key(key):
|
||||||
objid = self._get_next_object_id()
|
objid = self._get_next_object_id()
|
||||||
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)
|
properties=txt)
|
||||||
|
self._services[key] = service
|
||||||
|
else:
|
||||||
|
service = self._services[key]
|
||||||
adv.set_service(service)
|
adv.set_service(service)
|
||||||
|
|
||||||
# Merge the service into our buddy and activity lists, if needed
|
# Merge the service into our buddy and activity lists, if needed
|
||||||
@ -347,7 +458,8 @@ class PresenceService(object):
|
|||||||
if not buddy.is_valid():
|
if not buddy.is_valid():
|
||||||
self._dbus_helper.BuddyDisappeared(buddy.object_path())
|
self._dbus_helper.BuddyDisappeared(buddy.object_path())
|
||||||
del self._buddies[buddy_name]
|
del self._buddies[buddy_name]
|
||||||
|
key = (service.get_full_name(), service.get_type())
|
||||||
|
del self._services[key]
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _service_disappeared_cb_glue(self, interface, protocol, name, stype, domain, flags):
|
def _service_disappeared_cb_glue(self, interface, protocol, name, stype, domain, flags):
|
||||||
@ -403,6 +515,84 @@ 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 register_service(self, name, stype, properties, address, port, domain):
|
||||||
|
"""Register a new service, advertising it to other Buddies on the network."""
|
||||||
|
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)
|
||||||
|
self._services[key] = service
|
||||||
|
|
||||||
|
if self.get_owner() and name != self.get_owner().get_nick_name():
|
||||||
|
raise RuntimeError("Tried to register a service that didn't have Owner nick as the service name!")
|
||||||
|
actid = service.get_activity_id()
|
||||||
|
if actid:
|
||||||
|
rs_name = Service.compose_service_name(rs_name, actid)
|
||||||
|
rs_stype = service.get_type()
|
||||||
|
rs_port = service.get_port()
|
||||||
|
rs_props = service.get_properties()
|
||||||
|
rs_domain = service.get_domain()
|
||||||
|
rs_address = service.get_address()
|
||||||
|
if not rs_domain or not len(rs_domain):
|
||||||
|
rs_domain = ""
|
||||||
|
logging.debug("registered service name '%s' type '%s' on port %d with args %s" % (rs_name, rs_stype, rs_port, rs_props))
|
||||||
|
|
||||||
|
try:
|
||||||
|
group = dbus.Interface(self._bus.get_object(avahi.DBUS_NAME, self._server.EntryGroupNew()), avahi.DBUS_INTERFACE_ENTRY_GROUP)
|
||||||
|
|
||||||
|
# Add properties; ensure they are converted to ByteArray types
|
||||||
|
# because python sometimes can't figure that out
|
||||||
|
info = []
|
||||||
|
for k, v in rs_props.items():
|
||||||
|
tmp_item = "%s=%s" % (k, v)
|
||||||
|
info.append(dbus.types.ByteArray(tmp_item))
|
||||||
|
|
||||||
|
if rs_address and len(rs_address):
|
||||||
|
info.append("address=%s" % (rs_address))
|
||||||
|
logging.debug("PS: about to call AddService for Avahi with rs_name='%s' (%s), rs_stype='%s' (%s)," \
|
||||||
|
" rs_domain='%s' (%s), rs_port=%d (%s), info='%s' (%s)" % (rs_name, type(rs_name), rs_stype,
|
||||||
|
type(rs_stype), rs_domain, type(rs_domain), rs_port, type(rs_port), info, type(info)))
|
||||||
|
group.AddService(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, 0, rs_name, rs_stype,
|
||||||
|
rs_domain, "", # let Avahi figure the 'host' out
|
||||||
|
dbus.UInt16(rs_port), info,)
|
||||||
|
group.Commit()
|
||||||
|
except dbus.dbus_bindings.DBusException, exc:
|
||||||
|
# FIXME: ignore local name collisions, since that means
|
||||||
|
# the zeroconf service is already registered. Ideally we
|
||||||
|
# should un-register it an re-register with the correct info
|
||||||
|
if str(exc) == "Local name collision":
|
||||||
|
pass
|
||||||
|
activity_stype = service.get_type()
|
||||||
|
self.register_service_type(activity_stype)
|
||||||
|
|
||||||
|
def register_service_type(self, stype):
|
||||||
|
"""Requests that the Presence service look for and recognize
|
||||||
|
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)
|
||||||
|
|
||||||
|
# Find unresolved services that match the service type
|
||||||
|
# we're now interested in, and resolve them
|
||||||
|
resolv_list = []
|
||||||
|
|
||||||
|
# Find services of this type
|
||||||
|
resolv_list = self._find_service_adv(stype=stype)
|
||||||
|
# Request resolution for them if they aren't in-process already
|
||||||
|
for adv in resolv_list:
|
||||||
|
if adv not in self._resolve_queue:
|
||||||
|
self._resolve_queue.append(adv)
|
||||||
|
gobject.idle_add(self._resolve_service, adv)
|
||||||
|
|
||||||
|
def unregister_service_type(self, stype):
|
||||||
|
"""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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
@ -22,6 +22,8 @@ def _txt_to_dict(txt):
|
|||||||
return prop_dict
|
return prop_dict
|
||||||
|
|
||||||
def compose_service_name(name, activity_id):
|
def compose_service_name(name, activity_id):
|
||||||
|
if type(name) == type(""):
|
||||||
|
name = unicode(name)
|
||||||
if not name:
|
if not name:
|
||||||
raise ValueError("name must be a valid string.")
|
raise ValueError("name must be a valid string.")
|
||||||
if not activity_id:
|
if not activity_id:
|
||||||
@ -29,7 +31,7 @@ def compose_service_name(name, activity_id):
|
|||||||
if type(name) != type(u""):
|
if type(name) != type(u""):
|
||||||
raise ValueError("name must be in unicode.")
|
raise ValueError("name must be in unicode.")
|
||||||
composed = "%s [%s]" % (name, activity_id)
|
composed = "%s [%s]" % (name, activity_id)
|
||||||
return composed.encode()
|
return composed
|
||||||
|
|
||||||
def _decompose_service_name(name):
|
def _decompose_service_name(name):
|
||||||
"""Break a service name into the name and activity ID, if we can."""
|
"""Break a service name into the name and activity ID, if we can."""
|
||||||
@ -58,7 +60,7 @@ def is_multicast_address(address):
|
|||||||
return False
|
return False
|
||||||
if address[3] != '.':
|
if address[3] != '.':
|
||||||
return False
|
return False
|
||||||
first = int(address[:3])
|
first = int(float(address[:3]))
|
||||||
if first >= 224 and first <= 239:
|
if first >= 224 and first <= 239:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
@ -66,6 +68,7 @@ def is_multicast_address(address):
|
|||||||
|
|
||||||
_ACTIVITY_ID_TAG = "ActivityID"
|
_ACTIVITY_ID_TAG = "ActivityID"
|
||||||
SERVICE_DBUS_INTERFACE = "org.laptop.Presence.Service"
|
SERVICE_DBUS_INTERFACE = "org.laptop.Presence.Service"
|
||||||
|
SERVICE_DBUS_OBJECT_PATH = "/org/laptop/Presence/Services/"
|
||||||
|
|
||||||
class ServiceDBusHelper(dbus.service.Object):
|
class ServiceDBusHelper(dbus.service.Object):
|
||||||
"""Handle dbus requests and signals for Service objects"""
|
"""Handle dbus requests and signals for Service objects"""
|
||||||
@ -105,10 +108,11 @@ class ServiceDBusHelper(dbus.service.Object):
|
|||||||
value = str(value)
|
value = str(value)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
class Service(object):
|
class Service(object):
|
||||||
"""Encapsulates information about a specific ZeroConf/mDNS
|
"""Encapsulates information about a specific ZeroConf/mDNS
|
||||||
service as advertised on the network."""
|
service as advertised on the network."""
|
||||||
def __init__(self, bus_name, object_id, name, stype, domain, address=None, port=-1, properties=None):
|
def __init__(self, bus_name, object_id, name, stype, domain=u"local", address=None, port=-1, properties=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):
|
||||||
@ -127,13 +131,14 @@ class Service(object):
|
|||||||
if not stype.endswith("._tcp") and not stype.endswith("._udp"):
|
if not stype.endswith("._tcp") and not stype.endswith("._udp"):
|
||||||
raise ValueError("must specify a TCP or UDP service type.")
|
raise ValueError("must specify a TCP or UDP service type.")
|
||||||
|
|
||||||
if domain and type(domain) != type(u""):
|
if type(domain) != type(u""):
|
||||||
raise ValueError("domain must be in unicode.")
|
raise ValueError("domain must be in unicode.")
|
||||||
if len(domain) and domain != "local":
|
if domain and domain != "local":
|
||||||
raise ValueError("must use the 'local' domain (for now).")
|
raise ValueError("must use the 'local' domain (for now).")
|
||||||
|
|
||||||
(actid, real_name) = _decompose_service_name(name)
|
(actid, real_name) = _decompose_service_name(name)
|
||||||
self._name = real_name
|
self._name = real_name
|
||||||
|
self._full_name = name
|
||||||
self._stype = stype
|
self._stype = stype
|
||||||
self._domain = domain
|
self._domain = domain
|
||||||
self._port = -1
|
self._port = -1
|
||||||
@ -163,7 +168,7 @@ class Service(object):
|
|||||||
|
|
||||||
# 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 = SERVICE_DBUS_OBJECT_PATH + str(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):
|
||||||
@ -182,6 +187,9 @@ class Service(object):
|
|||||||
buddy who provides it."""
|
buddy who provides it."""
|
||||||
return self._name
|
return self._name
|
||||||
|
|
||||||
|
def get_full_name(self):
|
||||||
|
return self._full_name
|
||||||
|
|
||||||
def is_multicast_service(self):
|
def is_multicast_service(self):
|
||||||
"""Return True if the service's address is a multicast address,
|
"""Return True if the service's address is a multicast address,
|
||||||
False if it is not."""
|
False if it is not."""
|
||||||
@ -261,6 +269,13 @@ class Service(object):
|
|||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
__objid_seq = 0
|
||||||
|
def _next_objid():
|
||||||
|
global __objid_seq
|
||||||
|
__objid_seq = __objid_seq + 1
|
||||||
|
return __objid_seq
|
||||||
|
|
||||||
|
|
||||||
class ServiceTestCase(unittest.TestCase):
|
class ServiceTestCase(unittest.TestCase):
|
||||||
_DEF_NAME = u"foobar"
|
_DEF_NAME = u"foobar"
|
||||||
_DEF_STYPE = u"_foo._bar._tcp"
|
_DEF_STYPE = u"_foo._bar._tcp"
|
||||||
@ -268,13 +283,23 @@ class ServiceTestCase(unittest.TestCase):
|
|||||||
_DEF_ADDRESS = u"1.1.1.1"
|
_DEF_ADDRESS = u"1.1.1.1"
|
||||||
_DEF_PORT = 1234
|
_DEF_PORT = 1234
|
||||||
_DEF_PROPS = {'foobar': 'baz'}
|
_DEF_PROPS = {'foobar': 'baz'}
|
||||||
|
|
||||||
_STR_TEST_ARGS = [None, 0, [], {}]
|
_STR_TEST_ARGS = [None, 0, [], {}]
|
||||||
|
|
||||||
|
def __init__(self, name):
|
||||||
|
self._bus = dbus.SessionBus()
|
||||||
|
self._bus_name = dbus.service.BusName('org.laptop.Presence', bus=self._bus)
|
||||||
|
unittest.TestCase.__init__(self, name)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
del self._bus_name
|
||||||
|
del self._bus
|
||||||
|
|
||||||
def _test_init_fail(self, name, stype, domain, address, port, properties, fail_msg):
|
def _test_init_fail(self, name, stype, domain, address, port, properties, fail_msg):
|
||||||
"""Test something we expect to fail."""
|
"""Test something we expect to fail."""
|
||||||
try:
|
try:
|
||||||
service = Service(name, stype, domain, address, port, properties)
|
objid = _next_objid()
|
||||||
|
service = Service(self._bus_name, objid, name, stype, domain, address,
|
||||||
|
port, properties)
|
||||||
except ValueError, exc:
|
except ValueError, exc:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
@ -289,7 +314,7 @@ class ServiceTestCase(unittest.TestCase):
|
|||||||
for item in self._STR_TEST_ARGS:
|
for item in self._STR_TEST_ARGS:
|
||||||
self._test_init_fail(self._DEF_NAME, item, self._DEF_DOMAIN, self._DEF_ADDRESS,
|
self._test_init_fail(self._DEF_NAME, item, self._DEF_DOMAIN, self._DEF_ADDRESS,
|
||||||
self._DEF_PORT, self._DEF_PROPS, "invalid service type")
|
self._DEF_PORT, self._DEF_PROPS, "invalid service type")
|
||||||
self._test_init_fail(self._DEF_NAME, "_bork._foobar", self._DEF_DOMAIN, self._DEF_ADDRESS,
|
self._test_init_fail(self._DEF_NAME, u"_bork._foobar", self._DEF_DOMAIN, self._DEF_ADDRESS,
|
||||||
self._DEF_PORT, self._DEF_PROPS, "invalid service type")
|
self._DEF_PORT, self._DEF_PROPS, "invalid service type")
|
||||||
|
|
||||||
def testDomain(self):
|
def testDomain(self):
|
||||||
@ -297,14 +322,12 @@ class ServiceTestCase(unittest.TestCase):
|
|||||||
self._test_init_fail(self._DEF_NAME, self._DEF_STYPE, item, self._DEF_ADDRESS,
|
self._test_init_fail(self._DEF_NAME, self._DEF_STYPE, item, self._DEF_ADDRESS,
|
||||||
self._DEF_PORT, self._DEF_PROPS, "invalid domain")
|
self._DEF_PORT, self._DEF_PROPS, "invalid domain")
|
||||||
# Only accept local for now
|
# Only accept local for now
|
||||||
self._test_init_fail(self._DEF_NAME, self._DEF_STYPE, "foobar", self._DEF_ADDRESS,
|
self._test_init_fail(self._DEF_NAME, self._DEF_STYPE, u"foobar", self._DEF_ADDRESS,
|
||||||
self._DEF_PORT, self._DEF_PROPS, "invalid domain")
|
self._DEF_PORT, self._DEF_PROPS, "invalid domain")
|
||||||
# Make sure "" works
|
# Make sure "" works
|
||||||
session_bus = dbus.SessionBus()
|
objid = _next_objid()
|
||||||
bus_name = dbus.service.BusName('org.laptop.Presence', bus=session_bus)
|
service = Service(self._bus_name, objid, self._DEF_NAME, self._DEF_STYPE, u"",
|
||||||
service = Service(bus_name, 1, self._DEF_NAME, self._DEF_STYPE, "", self._DEF_ADDRESS,
|
self._DEF_ADDRESS, self._DEF_PORT, self._DEF_PROPS)
|
||||||
self._DEF_PORT, self._DEF_PROPS)
|
|
||||||
del bus_name, session_bus
|
|
||||||
assert service, "Empty domain was not accepted!"
|
assert service, "Empty domain was not accepted!"
|
||||||
|
|
||||||
def testAddress(self):
|
def testAddress(self):
|
||||||
@ -324,16 +347,15 @@ class ServiceTestCase(unittest.TestCase):
|
|||||||
"adf", self._DEF_PROPS, "invalid port")
|
"adf", self._DEF_PROPS, "invalid port")
|
||||||
|
|
||||||
def testGoodInit(self):
|
def testGoodInit(self):
|
||||||
session_bus = dbus.SessionBus()
|
objid = _next_objid()
|
||||||
bus_name = dbus.service.BusName('org.laptop.Presence', bus=session_bus)
|
service = Service(self._bus_name, objid, self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN,
|
||||||
service = Service(bus_name, 1, self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN, self._DEF_ADDRESS,
|
self._DEF_ADDRESS, self._DEF_PORT, self._DEF_PROPS)
|
||||||
self._DEF_PORT, self._DEF_PROPS)
|
|
||||||
del bus_name, session_bus
|
|
||||||
assert service.get_name() == self._DEF_NAME, "service name wasn't correct after init."
|
assert service.get_name() == self._DEF_NAME, "service name wasn't correct after init."
|
||||||
assert service.get_type() == self._DEF_STYPE, "service type wasn't correct after init."
|
assert service.get_type() == self._DEF_STYPE, "service type wasn't correct after init."
|
||||||
assert service.get_domain() == "local", "service domain wasn't correct after init."
|
assert service.get_domain() == "local", "service domain wasn't correct after init."
|
||||||
assert service.get_address() == self._DEF_ADDRESS, "service address wasn't correct after init."
|
assert service.get_address() == self._DEF_ADDRESS, "service address wasn't correct after init."
|
||||||
assert service.get_port() == self._DEF_PORT, "service port wasn't correct after init."
|
assert service.get_port() == self._DEF_PORT, "service port wasn't correct after init."
|
||||||
|
assert service.object_path() == SERVICE_DBUS_OBJECT_PATH + str(objid)
|
||||||
value = service.get_one_property('foobar')
|
value = service.get_one_property('foobar')
|
||||||
assert value and value == 'baz', "service property wasn't correct after init."
|
assert value and value == 'baz', "service property wasn't correct after init."
|
||||||
|
|
||||||
@ -341,11 +363,9 @@ class ServiceTestCase(unittest.TestCase):
|
|||||||
props = [[111, 114, 103, 46, 102, 114, 101, 101, 100, 101, 115, 107, 116, 111, 112, 46, 65, 118, 97, 104, 105, 46, 99, 111, 111, 107, 105, 101, 61, 50, 54, 48, 49, 53, 52, 51, 57, 53, 50]]
|
props = [[111, 114, 103, 46, 102, 114, 101, 101, 100, 101, 115, 107, 116, 111, 112, 46, 65, 118, 97, 104, 105, 46, 99, 111, 111, 107, 105, 101, 61, 50, 54, 48, 49, 53, 52, 51, 57, 53, 50]]
|
||||||
key = "org.freedesktop.Avahi.cookie"
|
key = "org.freedesktop.Avahi.cookie"
|
||||||
expected_value = "2601543952"
|
expected_value = "2601543952"
|
||||||
session_bus = dbus.SessionBus()
|
objid = _next_objid()
|
||||||
bus_name = dbus.service.BusName('org.laptop.Presence', bus=session_bus)
|
service = Service(self._bus_name, objid, self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN,
|
||||||
service = Service(bus_name, 1, self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN, self._DEF_ADDRESS,
|
self._DEF_ADDRESS, self._DEF_PORT, props)
|
||||||
self._DEF_PORT, props)
|
|
||||||
del bus_name, session_bus
|
|
||||||
value = service.get_one_property(key)
|
value = service.get_one_property(key)
|
||||||
assert value and value == expected_value, "service properties weren't correct after init."
|
assert value and value == expected_value, "service properties weren't correct after init."
|
||||||
value = service.get_one_property('bork')
|
value = service.get_one_property('bork')
|
||||||
@ -355,32 +375,29 @@ class ServiceTestCase(unittest.TestCase):
|
|||||||
props = [[111, 114, 103, 46, 102, 114, 101, 101, 100, 101, 115, 107, 116, 111, 112, 46, 65, 118, 97, 104, 105, 46, 99, 111, 111, 107, 105, 101]]
|
props = [[111, 114, 103, 46, 102, 114, 101, 101, 100, 101, 115, 107, 116, 111, 112, 46, 65, 118, 97, 104, 105, 46, 99, 111, 111, 107, 105, 101]]
|
||||||
key = "org.freedesktop.Avahi.cookie"
|
key = "org.freedesktop.Avahi.cookie"
|
||||||
expected_value = True
|
expected_value = True
|
||||||
session_bus = dbus.SessionBus()
|
objid = _next_objid()
|
||||||
bus_name = dbus.service.BusName('org.laptop.Presence', bus=session_bus)
|
service = Service(self._bus_name, objid, self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN, self._DEF_ADDRESS,
|
||||||
service = Service(bus_name, 1, self._DEF_NAME, self._DEF_STYPE, self._DEF_DOMAIN, self._DEF_ADDRESS,
|
|
||||||
self._DEF_PORT, props)
|
self._DEF_PORT, props)
|
||||||
value = service.get_one_property(key)
|
value = service.get_one_property(key)
|
||||||
del bus_name, session_bus
|
|
||||||
assert value is not None and value == expected_value, "service properties weren't correct after init."
|
assert value is not None and value == expected_value, "service properties weren't correct after init."
|
||||||
|
|
||||||
def testGroupService(self):
|
def testActivityService(self):
|
||||||
# Valid group service type, non-multicast address
|
# Valid group service type, non-multicast address
|
||||||
group_stype = u"_af5e5a7c998e89b9a_group_olpc._udp"
|
actid = "4569a71b80805aa96a847f7ac1c407327b3ec2b4"
|
||||||
self._test_init_fail(self._DEF_NAME, group_stype, self._DEF_DOMAIN, self._DEF_ADDRESS,
|
name = compose_service_name("Tommy", actid)
|
||||||
self._DEF_PORT, self._DEF_PROPS, "group service type, but non-multicast address")
|
|
||||||
|
|
||||||
# Valid group service type, None address
|
# Valid activity service name, None address
|
||||||
session_bus = dbus.SessionBus()
|
objid = _next_objid()
|
||||||
bus_name = dbus.service.BusName('org.laptop.Presence', bus=session_bus)
|
service = Service(self._bus_name, objid, name, self._DEF_STYPE, self._DEF_DOMAIN, None,
|
||||||
service = Service(bus_name, 1, self._DEF_NAME, group_stype, self._DEF_DOMAIN, None,
|
|
||||||
self._DEF_PORT, self._DEF_PROPS)
|
self._DEF_PORT, self._DEF_PROPS)
|
||||||
assert service.get_address() == None, "address was not None as expected!"
|
assert service.get_address() == None, "address was not None as expected!"
|
||||||
|
assert service.get_activity_id() == actid, "activity id was different than expected!"
|
||||||
|
|
||||||
# Valid group service type and multicast address, ensure it works
|
# Valid activity service name and multicast address, ensure it works
|
||||||
mc_addr = u"224.0.0.34"
|
mc_addr = u"224.0.0.34"
|
||||||
service = Service(bus_name, 1, self._DEF_NAME, group_stype, self._DEF_DOMAIN, mc_addr,
|
objid = _next_objid()
|
||||||
|
service = Service(self._bus_name, objid, name, self._DEF_STYPE, self._DEF_DOMAIN, mc_addr,
|
||||||
self._DEF_PORT, self._DEF_PROPS)
|
self._DEF_PORT, self._DEF_PROPS)
|
||||||
del bus_name, session_bus
|
|
||||||
assert service.get_address() == mc_addr, "address was not expected address!"
|
assert service.get_address() == mc_addr, "address was not expected address!"
|
||||||
|
|
||||||
def addToSuite(suite):
|
def addToSuite(suite):
|
||||||
@ -392,7 +409,7 @@ class ServiceTestCase(unittest.TestCase):
|
|||||||
suite.addTest(ServiceTestCase("testGoodInit"))
|
suite.addTest(ServiceTestCase("testGoodInit"))
|
||||||
suite.addTest(ServiceTestCase("testAvahiProperties"))
|
suite.addTest(ServiceTestCase("testAvahiProperties"))
|
||||||
suite.addTest(ServiceTestCase("testBoolProperty"))
|
suite.addTest(ServiceTestCase("testBoolProperty"))
|
||||||
suite.addTest(ServiceTestCase("testGroupService"))
|
suite.addTest(ServiceTestCase("testActivityService"))
|
||||||
addToSuite = staticmethod(addToSuite)
|
addToSuite = staticmethod(addToSuite)
|
||||||
|
|
||||||
|
|
||||||
|
@ -10,8 +10,6 @@ from sugar.presence import Service
|
|||||||
|
|
||||||
class Stream(object):
|
class Stream(object):
|
||||||
def __init__(self, service):
|
def __init__(self, service):
|
||||||
if not isinstance(service, Service.Service):
|
|
||||||
raise ValueError("service must be valid.")
|
|
||||||
if not service.get_port():
|
if not service.get_port():
|
||||||
raise ValueError("service must have an address.")
|
raise ValueError("service must have an address.")
|
||||||
self._service = service
|
self._service = service
|
||||||
@ -21,8 +19,6 @@ class Stream(object):
|
|||||||
self._callback = None
|
self._callback = None
|
||||||
|
|
||||||
def new_from_service(service, start_reader=True):
|
def new_from_service(service, start_reader=True):
|
||||||
if not isinstance(service, Service.Service):
|
|
||||||
raise ValueError("service must be valid.")
|
|
||||||
if service.is_multicast_service():
|
if service.is_multicast_service():
|
||||||
return MulticastStream(service)
|
return MulticastStream(service)
|
||||||
else:
|
else:
|
||||||
@ -40,8 +36,6 @@ class Stream(object):
|
|||||||
class UnicastStreamWriter(object):
|
class UnicastStreamWriter(object):
|
||||||
def __init__(self, stream, service):
|
def __init__(self, stream, service):
|
||||||
# set up the writer
|
# set up the writer
|
||||||
if not isinstance(service, Service.Service):
|
|
||||||
raise ValueError("service must be valid")
|
|
||||||
self._service = service
|
self._service = service
|
||||||
if not service.get_address():
|
if not service.get_address():
|
||||||
raise ValueError("service must have a valid address.")
|
raise ValueError("service must have a valid address.")
|
||||||
|
Loading…
Reference in New Issue
Block a user