From 7774073276de007dbf02c4f36aeeef3d56151bff Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 2 May 2007 23:25:15 -0400 Subject: [PATCH] Make joining asynchronous on the activity side --- sugar/activity/activity.py | 71 ++++++++++++++++++------------- sugar/activity/activityhandle.py | 4 +- sugar/presence/activity.py | 24 +++++++---- sugar/presence/presenceservice.py | 17 +++++++- 4 files changed, 76 insertions(+), 40 deletions(-) diff --git a/sugar/activity/activity.py b/sugar/activity/activity.py index a859810c..06166dec 100644 --- a/sugar/activity/activity.py +++ b/sugar/activity/activity.py @@ -42,6 +42,7 @@ class ActivityToolbar(gtk.Toolbar): self._activity = activity activity.connect('shared', self._activity_shared_cb) + activity.connect('joined', self._activity_shared_cb) button = ToolButton('window-close') button.connect('clicked', self._close_button_clicked_cb) @@ -105,7 +106,8 @@ class Activity(Window, gtk.Container): __gtype_name__ = 'SugarActivity' __gsignals__ = { - 'shared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])) + 'shared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])), + 'joined': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])) } def __init__(self, handle): @@ -133,53 +135,64 @@ class Activity(Window, gtk.Container): self.connect('destroy', self._destroy_cb) - self._shared = False self._activity_id = handle.activity_id self._pservice = presenceservice.get_instance() - self._service = None - self._share_sigid = None + self._shared_activity = None + self._share_id = None + self._join_id = None - service = handle.get_presence_service() - if service: - self._join(service) + shared_activity = handle.get_shared_activity() + if shared_activity: + # Join an existing instance of this activity on the network + self._shared_activity = shared_activity + self._join_id = self._shared_activity.connect("joined", self._internal_joined_cb) + if not self._shared_activity.props.joined: + self._shared_activity.join() + else: + self._joined_cb(self._shared_activity, True, None) self._bus = ActivityService(self) + def _internal_joined_cb(self, activity, success, err): + """Callback when join has finished""" + self._shared_activity.disconnect(self._join_id) + self._join_id = None + if not success: + logging.debug("Failed to join activity: %s" % err) + return + self.present() + self.emit('joined') + def get_service_name(self): """Gets the activity service name.""" return os.environ['SUGAR_BUNDLE_SERVICE_NAME'] def get_shared(self): """Returns TRUE if the activity is shared on the mesh.""" - return self._shared + if not self._shared_activity: + return False + return self._shared_activity.props.joined def get_id(self): """Get the unique activity identifier.""" return self._activity_id - def _join(self, service): - """Join an existing instance of this activity on the network.""" - self._service = service - self._shared = True - self._service.join() - self.present() + def _internal_share_cb(self, ps, success, activity, err): + self._pservice.disconnect(self._share_id) + self._share_id = None + if not success: + logging.debug('Share of activity %s failed: %s.' % (self._activity_id, err)) + return + logging.debug('Share of activity %s successful.' % self._activity_id) + self.shared_activity = activity self.emit('shared') - def _share_cb(self, ps, success, service, err): - self._pservice.disconnect(self._share_sigid) - self._share_sigid = None - if success: - logging.debug('Share of activity %s successful.' % self.get_id()) - self._service = service - self._shared = True - self.emit('shared') - else: - logging.debug('Share of activity %s failed: %s.' % (self.get_id(), err)) - def share(self): """Request that the activity be shared on the network.""" - logging.debug('Requesting share of activity %s.' % self.get_id()) - self._share_sigid = self._pservice.connect("activity-shared", self._share_cb) + if self._shared_activty and self._shared_activity.props.joined: + raise RuntimeError("Activity %s already shared." % self._activity_id) + logging.debug('Requesting share of activity %s.' % self._activity_id) + self._share_id = self._pservice.connect("activity-shared", self._internal_share_cb) self._pservice.share_activity(self) def execute(self, command, args): @@ -191,8 +204,8 @@ class Activity(Window, gtk.Container): if self._bus: del self._bus self._bus = None - if self._service: - self._pservice.unregister_service(self._service) + if self._shared_activity: + self._shared_activity.leave() def _handle_close_cb(self, toolbar): self.destroy() diff --git a/sugar/activity/activityhandle.py b/sugar/activity/activityhandle.py index c87fb6b5..e683ac1b 100644 --- a/sugar/activity/activityhandle.py +++ b/sugar/activity/activityhandle.py @@ -52,8 +52,8 @@ class ActivityHandle(object): self.object_id = object_id self.uri = uri - def get_presence_service(self): - """Retrieve the "sharing service" for this activity + def get_shared_activity(self): + """Retrieve the shared instance of this activity Uses the PresenceService to find any existing dbus service which provides sharing mechanisms for this diff --git a/sugar/presence/activity.py b/sugar/presence/activity.py index 31638ac5..3681f917 100644 --- a/sugar/presence/activity.py +++ b/sugar/presence/activity.py @@ -36,10 +36,12 @@ class Activity(gobject.GObject): __gsignals__ = { 'buddy-joined': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), - 'buddy-left': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + 'buddy-left': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), - 'new-channel': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, - ([gobject.TYPE_PYOBJECT])) + 'new-channel': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + ([gobject.TYPE_PYOBJECT])), + 'joined': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + ([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT])) } __gproperties__ = { @@ -137,15 +139,22 @@ class Activity(gobject.GObject): buddies.append(self._ps_new_object(item)) return buddies + def _join_cb(self): + self._joined = True + self.emit("joined", True, None) + + def _join_error_cb(self, err): + self.emit("joined", False, str(err)) + def join(self): """Join this activity XXX if these are all activities, can I join my own activity? """ if self._joined: + self.emit("joined", True, None) return - self._activity.Join() - self._joined = True + self._activity.Join(reply_handler=self._join_cb, error_handler=self._join_error_cb) def get_channels(self): """Retrieve communications channel descriptions for the activity @@ -157,7 +166,6 @@ class Activity(gobject.GObject): (bus_name, connection, channels) = self._activity.GetChannels() return bus_name, connection, channels - def owner_has_joined(self): - """Retrieve whether the owner of the activity is active within it""" + def leave(self): # FIXME - return False + self._joined = False diff --git a/sugar/presence/presenceservice.py b/sugar/presence/presenceservice.py index 4044c4e3..f93c8310 100644 --- a/sugar/presence/presenceservice.py +++ b/sugar/presence/presenceservice.py @@ -160,6 +160,11 @@ class PresenceService(gobject.GObject): elif object_path.startswith(self._PS_ACTIVITY_OP): obj = activity.Activity(self._bus, self._new_object, self._del_object, object_path) + try: + # Pre-fill the activity's ID + foo = obj.props.id + except dbus.exceptions.DBusException, err: + pass else: raise RuntimeError("Unknown object type") self._objcache[object_path] = obj @@ -322,7 +327,9 @@ class PresenceService(gobject.GObject): def _share_activity_cb(self, activity, op): """Notify with GObject event of successful sharing of activity""" - self.emit("activity-shared", True, self._new_object(op), None) + psact = self._new_object(op) + psact._joined = True + self.emit("activity-shared", True, psact, None) def _share_activity_error_cb(self, activity, err): """Notify with GObject event of unsuccessful sharing of activity""" @@ -343,6 +350,14 @@ class PresenceService(gobject.GObject): returns None """ actid = activity.get_id() + + # Ensure the activity is not already shared/joined + for obj in self._objcache.values(): + if not isinstance(object, activity.Activity): + continue + if obj.props.id == actid or obj.props.joined: + raise RuntimeError("Activity %s is already shared." % actid) + atype = activity.get_service_name() name = activity.props.title self._ps.ShareActivity(actid, atype, name, properties,