From 249521253dfc61248a22133c6624225234515eb5 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Mon, 29 Oct 2007 17:21:33 +0000 Subject: [PATCH] Do some standard Tubes boilerplate in sugar.presence, so activities don't have to (#4503) --- NEWS | 3 + lib/sugar/presence/activity.py | 113 ++++++++++++++++++++++++-- lib/sugar/presence/presenceservice.py | 22 +++-- 3 files changed, 124 insertions(+), 14 deletions(-) diff --git a/NEWS b/NEWS index 3230ecef..a4f8c431 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,6 @@ +* #4503: Do some standard Tubes boilerplate in sugar.presence, so activities + don't have to (smcv) + Snapshot fdb4e49b14 * Save journal files on nand, not tmpfs (tomeu) diff --git a/lib/sugar/presence/activity.py b/lib/sugar/presence/activity.py index 5ce507d3..b0110a0e 100644 --- a/lib/sugar/presence/activity.py +++ b/lib/sugar/presence/activity.py @@ -18,8 +18,9 @@ import logging -import gobject import dbus +import gobject +import telepathy _logger = logging.getLogger('sugar.presence.activity') @@ -95,6 +96,12 @@ class Activity(gobject.GObject): self._handle_to_buddy_path = {} self._buddy_path_to_handle = {} + # Set up by set_up_tubes() + self.telepathy_conn = None + self.telepathy_tubes_chan = None + self.telepathy_text_chan = None + self._telepathy_room = None + def __repr__(self): return ('' % (self._object_path, id(self))) @@ -180,6 +187,11 @@ class Activity(gobject.GObject): self._activity.SetProperties({'private': val}) self._private = val + def set_private(self, val, reply_handler, error_handler): + self._activity.SetProperties({'private': bool(val)}, + reply_handler=reply_handler, + error_handler=error_handler) + def _emit_buddy_joined_signal(self, object_path): """Generate buddy-joined GObject signal with presence Buddy object""" self.emit('buddy-joined', self._ps_new_object(object_path)) @@ -254,23 +266,112 @@ class Activity(gobject.GObject): reply_handler=lambda: response_cb(None), error_handler=response_cb) + # Joining and sharing (FIXME: sharing is actually done elsewhere) + + def set_up_tubes(self, reply_handler, error_handler): + + cpaths = [] + + def tubes_chan_ready(chan): + _logger.debug('%r: Tubes channel %r is ready', self, chan) + self.telepathy_tubes_chan = chan + + _logger.debug('%r: finished setting up tubes', self) + reply_handler() + + def got_tubes_chan(path): + _logger.debug('%r: got Tubes channel at %s', self, path) + telepathy.client.Channel(self.telepathy_conn.service_name, + path, ready_handler=tubes_chan_ready, + error_handler=error_handler) + + def text_chan_ready(chan): + _logger.debug('%r: Text channel %r is ready', self, chan) + self.telepathy_text_chan = chan + + self.telepathy_conn.RequestChannel(telepathy.CHANNEL_TYPE_TUBES, + telepathy.HANDLE_TYPE_ROOM, + self._telepathy_room_handle, + True, + reply_handler=got_tubes_chan, + error_handler=error_handler) + + def got_text_chan(path): + _logger.debug('%r: got Text channel at %s', self, path) + telepathy.client.Channel(self.telepathy_conn.service_name, + path, ready_handler=text_chan_ready, + error_handler=error_handler) + + def conn_ready(conn): + _logger.debug('%r: Connection %r is ready', self, conn) + self.telepathy_conn = conn + + # For the moment we'll do this synchronously. + # If the PS gained a GetRoom method, we could + # do this async too + + for channel_path in cpaths: + channel = telepathy.client.Channel(conn.service_name, + channel_path) + handle_type, handle = channel.GetHandle() + if handle_type == telepathy.HANDLE_TYPE_ROOM: + room = handle + break + + if room is None: + error_handler(AssertionError("Presence Service didn't create " + "a chatroom")) + else: + self._telepathy_room_handle = room + + conn.RequestChannel(telepathy.CHANNEL_TYPE_TEXT, + telepathy.HANDLE_TYPE_ROOM, + room, True, + reply_handler=got_text_chan, + error_handler=error_handler) + + def got_channels(bus_name, conn_path, channel_paths): + _logger.debug('%r: Connection on %s at %s, channel paths: %r', + self, bus_name, conn_path, channel_paths) + + # can't use assignment for this due to Python scoping + cpaths.extend(channel_paths) + + telepathy.client.Connection(bus_name, conn_path, + ready_handler=conn_ready, + error_handler=error_handler) + + self._activity.GetChannels(reply_handler=got_channels, + error_handler=error_handler) + def _join_cb(self): + _logger.debug('%r: Join finished', self) self._joined = True self.emit("joined", True, None) def _join_error_cb(self, err): + _logger.debug('%r: Join failed because: %s', 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? + """Join this activity. + + Emits 'joined' and otherwise does nothing if we're already joined. """ if self._joined: self.emit("joined", True, None) return + _logger.debug('%r: joining', self) - self._activity.Join(reply_handler=self._join_cb, error_handler=self._join_error_cb) + + def joined(): + self.set_up_tubes(reply_handler=self._join_cb, + error_handler=self._join_error_cb) + + self._activity.Join(reply_handler=joined, + error_handler=self._join_error_cb) + + # GetChannels() wrapper def get_channels(self): """Retrieve communications channel descriptions for the activity @@ -288,6 +389,8 @@ class Activity(gobject.GObject): self, bus_name, connection, channels) return bus_name, connection, channels + # Leaving + def _leave_cb(self): """Callback for async action of leaving shared activity.""" self.emit("joined", False, "left activity") diff --git a/lib/sugar/presence/presenceservice.py b/lib/sugar/presence/presenceservice.py index dea0c7c8..2107f4ac 100644 --- a/lib/sugar/presence/presenceservice.py +++ b/lib/sugar/presence/presenceservice.py @@ -425,20 +425,24 @@ class PresenceService(gobject.GObject): return self._new_object(owner_op) def _share_activity_cb(self, activity, psact): - """Notify with GObject event of successful sharing of activity + """Finish sharing the activity """ psact._joined = True - self.emit("activity-shared", True, psact, None) + _logger.debug('%r: Just shared, setting up tubes', activity) + psact.set_up_tubes(reply_handler=lambda: + self.emit("activity-shared", True, psact, None), + error_handler=lambda e: + self._share_activity_error_cb(activity, e)) def _share_activity_privacy_cb(self, activity, private, op): psact = self._new_object(op) - # FIXME: this should be done asynchronously (more API needed) - try: - psact.props.private = private - except Exception, e: - self._share_activity_error_cb(activity, e) - else: - self._share_activity_cb(activity, psact) + _logger.debug('%r: Just shared, setting privacy to %r', activity, + private) + psact.set_private(private, + reply_handler=lambda: + self._share_activity_cb(activity, psact), + error_handler=lambda e: + self._share_activity_error_cb(activity, e)) def _share_activity_error_cb(self, activity, err): """Notify with GObject event of unsuccessful sharing of activity"""