Make shareActivity work

This commit is contained in:
Dan Williams 2006-07-25 19:04:15 -05:00
parent e5065263a9
commit 164add907d
13 changed files with 84 additions and 82 deletions

View File

@ -65,7 +65,7 @@ class BrowserActivity(Activity):
self._initial_service.get_activity_id()) self._initial_service.get_activity_id())
self._pservice.join_shared_activity(self._initial_service) self._pservice.join_shared_activity(self._initial_service)
def _service_appeared_cb(self, pservice, buddy, service): def _service_appeared_cb(self, pservice, service):
# Make sure the service is for our activity # Make sure the service is for our activity
if service.get_activity_id() != self._activity_id: if service.get_activity_id() != self._activity_id:
return return

View File

@ -9,13 +9,13 @@ class ActivityInfo:
self._service = service self._service = service
def get_id(self): def get_id(self):
activity_id = self._service.get_one_property('activity_id') activity_id = self._service.get_activity_id()
def get_type(self): def get_type(self):
return self._service.get_type() return self._service.get_type()
def get_title(self): def get_title(self):
escaped_title = self._service.get_one_property('Title') escaped_title = self._service.get_published_value('Title')
title = xml.sax.saxutils.unescape(escaped_title) title = xml.sax.saxutils.unescape(escaped_title)
return title return title
@ -46,7 +46,8 @@ class ActivitiesModel(gobject.GObject):
def __iter__(self): def __iter__(self):
return self._activities.__iter__() return self._activities.__iter__()
def _on_activity_announced_cb(self, pservice, service, buddy): def _on_activity_announced_cb(self, pservice, activity):
# FIXME We should not hard code activity types here # FIXME We should not hard code activity types here
if service.get_type() == "_web_olpc._udp": services = activity.get_services_of_type("_web_olpc._udp")
self.add_activity(service) if len(services) > 0:
self.add_activity(services[0])

View File

@ -13,13 +13,14 @@ class ShellOwner(object):
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):
nick = env.get_nick_name() self._nick = env.get_nick_name()
user_dir = env.get_user_dir() user_dir = env.get_user_dir()
if not os.path.exists(user_dir):
try: try:
os.makedirs(user_dir) os.makedirs(user_dir)
except OSError: except OSError, exc:
print "Could not create user directory." if exc[0] != 17: # file exists
print "Could not create user directory %s: (%d) %s" % (user_dir, exc[0], exc[1])
self._icon = None self._icon = None
for fname in os.listdir(user_dir): for fname in os.listdir(user_dir):
@ -30,10 +31,12 @@ class ShellOwner(object):
fd.close() fd.close()
break break
# Create and announce our presence
self._pservice = PresenceService.PresenceService() self._pservice = PresenceService.PresenceService()
self._service = self._pservice.register_service(nick, PRESENCE_SERVICE_TYPE)
print "Owner '%s' using port %d" % (nick, self._service.get_port()) def announce(self):
# Create and announce our presence
self._service = self._pservice.register_service(self._nick, PRESENCE_SERVICE_TYPE)
print "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")

View File

@ -1,5 +1,9 @@
import dbus import dbus
PRESENCE_SERVICE_TYPE = "_presence_olpc._tcp"
ACTIVITY_DBUS_OBJECT_PATH = "/org/laptop/Presence/Activities/"
ACTIVITY_DBUS_INTERFACE = "org.laptop.Presence.Activity"
class NotFoundError(Exception): class NotFoundError(Exception):
pass pass
@ -10,7 +14,7 @@ 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, @dbus.service.method(ACTIVITY_DBUS_INTERFACE,
in_signature="s", out_signature="ao") in_signature="s", out_signature="ao")
def getServicesOfType(self, stype): def getServicesOfType(self, stype):
services = self._parent.get_services_of_type(stype) services = self._parent.get_services_of_type(stype)
@ -21,7 +25,7 @@ class ActivityDBusHelper(dbus.service.Object):
ret.append(serv.object_path()) ret.append(serv.object_path())
return ret return ret
@dbus.service.method(BUDDY_DBUS_INTERFACE, @dbus.service.method(ACTIVITY_DBUS_INTERFACE,
in_signature="", out_signature="ao") in_signature="", out_signature="ao")
def getServices(self): def getServices(self):
services = self._parent.get_services() services = self._parent.get_services()
@ -32,12 +36,12 @@ class ActivityDBusHelper(dbus.service.Object):
ret.append(serv.object_path()) ret.append(serv.object_path())
return ret return ret
@dbus.service.method(BUDDY_DBUS_INTERFACE, @dbus.service.method(ACTIVITY_DBUS_INTERFACE,
in_signature="", out_signature="s") in_signature="", out_signature="s")
def getId(self): def getId(self):
return self._parent.get_id() return self._parent.get_id()
@dbus.service.method(BUDDY_DBUS_INTERFACE, @dbus.service.method(ACTIVITY_DBUS_INTERFACE,
in_signature="", out_signature="ao") in_signature="", out_signature="ao")
def getJoinedBuddies(self): def getJoinedBuddies(self):
buddies = self._parent.get_joined_buddies() buddies = self._parent.get_joined_buddies()
@ -48,41 +52,42 @@ class ActivityDBusHelper(dbus.service.Object):
ret.append(buddy.object_path()) ret.append(buddy.object_path())
return ret return ret
@dbus.service.signal(BUDDY_DBUS_INTERFACE, @dbus.service.signal(ACTIVITY_DBUS_INTERFACE,
signature="o") signature="o")
def ServiceAppeared(self, object_path): def ServiceAppeared(self, object_path):
pass pass
@dbus.service.signal(BUDDY_DBUS_INTERFACE, @dbus.service.signal(ACTIVITY_DBUS_INTERFACE,
signature="o") signature="o")
def ServiceDisappeared(self, object_path): def ServiceDisappeared(self, object_path):
pass pass
@dbus.service.signal(BUDDY_DBUS_INTERFACE, @dbus.service.signal(ACTIVITY_DBUS_INTERFACE,
signature="o") signature="o")
def BuddyJoined(self, object_path): def BuddyJoined(self, object_path):
pass pass
@dbus.service.signal(BUDDY_DBUS_INTERFACE, @dbus.service.signal(ACTIVITY_DBUS_INTERFACE,
signature="o") signature="o")
def BuddyLeft(self, object_path): def BuddyLeft(self, object_path):
pass pass
class Activity(object): class Activity(object):
def __init__(self, bus_name, object_id, activity_id): def __init__(self, bus_name, object_id, initial_service):
if not activity_id: if not initial_service.get_activity_id():
raise ValueError("Service must have a valid Activity ID") raise ValueError("Service must have a valid Activity ID")
self._activity_id = activity_id self._activity_id = initial_service.get_activity_id()
self._buddies = [] self._buddies = []
self._services = {} # service type -> list of Services 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)
self.add_service(initial_service)
def object_path(self): def object_path(self):
return dbus.ObjectPath(self._object_path) return dbus.ObjectPath(self._object_path)
@ -99,8 +104,11 @@ class Activity(object):
def get_joined_buddies(self): def get_joined_buddies(self):
buddies = [] buddies = []
for serv in self._services.values(): for serv_list in self._services.values():
buddies.append(serv.get_owner()) for serv in serv_list:
owner = serv.get_owner()
if not owner in buddies:
buddies.append(owner)
return buddies return buddies
def add_service(self, service): def add_service(self, service):

View File

@ -71,7 +71,7 @@ class BuddyDBusHelper(dbus.service.Object):
in_signature="", out_signature="a{sv}") in_signature="", out_signature="a{sv}")
def getProperties(self): def getProperties(self):
props = {} props = {}
props['name'] = self._parent.get_nick_name() props['name'] = self._parent.get_name()
props['ip4_address'] = self._parent.get_address() props['ip4_address'] = self._parent.get_address()
props['owner'] = self._parent.is_owner() props['owner'] = self._parent.is_owner()
return props return props
@ -149,6 +149,7 @@ class Buddy(object):
stype = service.get_type() stype = service.get_type()
if stype in self._services.keys(): if stype in self._services.keys():
return False return False
logging.debug("Buddy %s added service type %s id %s" % (self._nick_name, service.get_type(), service.get_activity_id()))
self._services[stype] = service self._services[stype] = service
service.set_owner(self) service.set_owner(self)
@ -168,6 +169,7 @@ class Buddy(object):
if activity in self._activities.values(): if activity in self._activities.values():
raise RuntimeError("Tried to add activity twice") raise RuntimeError("Tried to add activity twice")
found = False found = False
logging.debug("Buddy %s looking for actid %s" % (self._nick_name, activity.get_id()))
for serv in self._services.values(): for serv in self._services.values():
if serv.get_activity_id() == activity.get_id(): if serv.get_activity_id() == activity.get_id():
found = True found = True
@ -239,7 +241,7 @@ class Buddy(object):
def get_address(self): def get_address(self):
return self._address return self._address
def get_nick_name(self): def get_name(self):
return self._nick_name return self._nick_name
def _set_icon(self, icon): def _set_icon(self, icon):
@ -310,7 +312,7 @@ class BuddyTestCase(unittest.TestCase):
self._DEF_ADDRESS, self._DEF_PORT) self._DEF_ADDRESS, self._DEF_PORT)
objid = _next_objid() objid = _next_objid()
buddy = Buddy(self._bus_name, objid, service) 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_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.get_address() == self._DEF_ADDRESS, "buddy address wasn't correct after init."
assert buddy.object_path() == BUDDY_DBUS_OBJECT_PATH + str(objid) assert buddy.object_path() == BUDDY_DBUS_OBJECT_PATH + str(objid)

View File

@ -1,6 +1,7 @@
import avahi, dbus, dbus.glib, gobject import avahi, dbus, dbus.glib, gobject
import Buddy import Buddy
import Service import Service
import Activity
import random import random
import logging import logging
from sugar import env from sugar import env
@ -178,13 +179,15 @@ class PresenceServiceDBusHelper(dbus.service.Object):
@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): def shareActivity(self, activity_id, stype, properties, address, port, domain):
service = self._parent.register_service(name, stype, properties, address, service = self._parent.share_activity(activity_id, stype, properties, address,
port, domain) port, domain)
return service.object_path() return service.object_path()
def shareActivity(self, activity_id, stype, properties, address, port, domain): @dbus.service.method(_PRESENCE_DBUS_INTERFACE,
service = self._parent.share_activity(name, stype, properties, address, in_signature="ssa{ss}sis", out_signature="o")
def registerService(self, name, stype, properties, address, port, domain):
service = self._parent.register_service(name, stype, properties, address,
port, domain) port, domain)
return service.object_path() return service.object_path()
@ -440,7 +443,7 @@ class PresenceService(object):
self._local_addrs[interface] = addr self._local_addrs[interface] = addr
# 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)
# If we care about the service right now, resolve it # If we care about the service right now, resolve it
resolve = False resolve = False
@ -475,7 +478,7 @@ class PresenceService(object):
return False return False
# 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)
# Remove the service from the buddy # Remove the service from the buddy
try: try:
@ -546,34 +549,28 @@ 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 share_activity(self, activity_id, stype, properties=None, address=None, port=None, domain=u"local"): def share_activity(self, activity_id, stype, properties=None, address=None, port=-1, domain=u"local"):
"""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")
owner_nick = self._owner.get_nick_name() owner_nick = self._owner.get_name()
real_name = Service.compose_service_name(owner_nick, actid) real_name = Service.compose_service_name(owner_nick, activity_id)
if address and type(address) != type(u""): if address and type(address) != type(u""):
raise ValueError("address must be a unicode string.") raise ValueError("address must be a unicode string.")
if address == None: if address == None:
# Use random currently unassigned multicast address # Use random currently unassigned multicast address
address = "232.%d.%d.%d" % (random.randint(0, 254), random.randint(1, 254), address = "232.%d.%d.%d" % (random.randint(0, 254), random.randint(1, 254),
random.randint(1, 254)) random.randint(1, 254))
if port and (type(port) != type(1) or port <= 1024 or port >= 65535): if port and port != -1 and (type(port) != type(1) or port <= 1024 or port >= 65535):
raise ValueError("port must be a number between 1024 and 65535") raise ValueError("port must be a number between 1024 and 65535")
if not port:
# random port #
port = random.randint(5000, 65535)
# Mark the activity as shared
if stype == activity.get_default_type():
activity.set_shared()
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, properties %s' % (activity_id, stype, address, port, properties))
return self.register_service(real_name, stype, properties, address, port, domain) return self.register_service(real_name, stype, properties, address, port, domain)
def register_service(self, name, stype, properties={}, address=None, port=None, domain=u"local"): def register_service(self, name, stype, properties={}, address=None, port=-1, domain=u"local"):
"""Register a new service, advertising it to other Buddies on the network.""" """Register a new service, advertising it to other Buddies on the network."""
if self.get_owner() and name != self.get_owner().get_nick_name(): (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): if not domain or not len(domain):
domain = u"local" domain = u"local"

View File

@ -34,7 +34,7 @@ def compose_service_name(name, activity_id):
composed = "%s [%s]" % (name, activity_id) composed = "%s [%s]" % (name, activity_id)
return composed 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."""
if type(name) != type(u""): if type(name) != type(u""):
raise ValueError("name must be a valid unicode string.") raise ValueError("name must be a valid unicode string.")
@ -127,7 +127,7 @@ class Service(object):
if 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._full_name = name
self._stype = stype self._stype = stype

View File

@ -56,7 +56,8 @@ class Shell:
bus_name = dbus.service.BusName('com.redhat.Sugar.Shell', bus=session_bus) bus_name = dbus.service.BusName('com.redhat.Sugar.Shell', bus=session_bus)
ShellDbusService(self, bus_name) ShellDbusService(self, bus_name)
#self._owner = ShellOwner() self._owner = ShellOwner()
self._owner.announce()
self._registry = ActivityRegistry() self._registry = ActivityRegistry()
self._registry.scan_directory(env.get_activities_dir()) self._registry.scan_directory(env.get_activities_dir())

View File

@ -192,11 +192,6 @@ class Activity(gtk.Window):
def get_default_type(self): def get_default_type(self):
return self._default_type return self._default_type
def set_shared(self):
"""Mark the activity as 'shared'."""
if not self._shared:
self._shared = True
def get_shared(self): def get_shared(self):
return self._shared return self._shared
@ -205,7 +200,9 @@ class Activity(gtk.Window):
return self._has_focus return self._has_focus
def _internal_on_share_cb(self): def _internal_on_share_cb(self):
"""Callback when the dbus service object tells us the user has shared our activity.""" """Callback when the dbus service object tells us the user wishes to share our activity."""
if not self._shared:
self._shared = True
self.share() self.share()
def get_id(self): def get_id(self):

View File

@ -18,9 +18,9 @@ class ActivityChat(GroupChat):
if ps_activity is not None: if ps_activity is not None:
service = ps_activity.get_service_of_type(ActivityChat.SERVICE_TYPE) service = ps_activity.get_service_of_type(ActivityChat.SERVICE_TYPE)
if service is not None: if service is not None:
self._service_appeared_cb(self._pservice, None, service) self._service_appeared_cb(self._pservice, service)
def _service_appeared_cb(self, pservice, buddy, service): def _service_appeared_cb(self, pservice, service):
if service.get_activity_id() != self._activity.get_id(): if service.get_activity_id() != self._activity.get_id():
return return
if service.get_type() != ActivityChat.SERVICE_TYPE: if service.get_type() != ActivityChat.SERVICE_TYPE:

View File

@ -44,16 +44,7 @@ class LocalModel(AbstractModel):
# FIXME this is duplicated with StreamReader # FIXME this is duplicated with StreamReader
def _setup_server(self, service): def _setup_server(self, service):
started = False
tries = 10
port = service.get_port() port = service.get_port()
while not started and tries > 0: logging.debug('Start model server on port %d' % (port))
try: p2p_server = network.GlibXMLRPCServer(("", port))
logging.debug('Start model server on port %d' % (port)) p2p_server.register_instance(ModelRequestHandler(self))
p2p_server = network.GlibXMLRPCServer(("", port))
p2p_server.register_instance(ModelRequestHandler(self))
started = True
except(socket.error):
port = port + 1
tries = tries - 1
service.set_port(port)

View File

@ -66,13 +66,6 @@ class Activity(gobject.GObject):
def get_icon(self): def get_icon(self):
return self._buddy.getIcon() return self._buddy.getIcon()
def get_service_of_type(self, stype):
try:
object_path = self._buddy.getServiceOfType(stype)
except dbus.exceptions.DBusException:
return None
return self._ps_new_object(object_path)
def get_services(self): def get_services(self):
resp = self._activity.getServices() resp = self._activity.getServices()
servs = [] servs = []

View File

@ -181,7 +181,16 @@ class PresenceService(gobject.GObject):
return None return None
return self._new_object(owner_op) return self._new_object(owner_op)
def register_service(self, name, stype, properties={"":""}, address="", port=-1, domain=u"local"): def share_activity(self, activity, stype, properties={}, address=None, port=-1, domain=u"local"):
actid = activity.get_id()
if address == None:
address = u""
serv_op = self._ps.shareActivity(actid, stype, properties, address, port, domain)
return self._new_object(serv_op)
def register_service(self, name, stype, properties={}, address=None, port=-1, domain=u"local"):
if address == None:
address = u""
serv_op = self._ps.registerService(name, stype, properties, address, port, domain) serv_op = self._ps.registerService(name, stype, properties, address, port, domain)
return self._new_object(serv_op) return self._new_object(serv_op)