Replace enough of the old PS so we can join an activity instance on the network.
* src/sugar/activity/activity.py: Get the shared activity wrapper from sugar.presence. * src/sugar/activity/activityfactory.py: Disable checking in the PS for activity_id duplicates. * src/sugar/presence/activity.py: Remove the PS dependency and query Telepathy directly. Implemented enough to join an activity. * src/sugar/presence/buddy.py: Remove the PS dependency and query Telepathy directly. Implemented enough to join an activity. Added an Owner subclass of Buddy() * src/sugar/presence/presenceservice.py: Remove the PS dependency and query Telepathy directly. Implemented enough to join an activity. * src/sugar/presence/util.py: Add ConnectionManager for discovering and tracking connections.
This commit is contained in:
parent
d6da506dfd
commit
98cc77f1fb
@ -70,6 +70,7 @@ from sugar.graphics.alert import Alert
|
||||
from sugar.graphics.icon import Icon
|
||||
from sugar.datastore import datastore
|
||||
from sugar.session import XSMPClient
|
||||
from sugar.presence import presenceservice
|
||||
from sugar import wm
|
||||
|
||||
# support deprecated imports
|
||||
@ -266,7 +267,6 @@ class Activity(Window, gtk.Container):
|
||||
|
||||
self._active = False
|
||||
self._activity_id = handle.activity_id
|
||||
self._pservice = presenceservice.get_instance()
|
||||
self.shared_activity = None
|
||||
self._share_id = None
|
||||
self._join_id = None
|
||||
@ -302,8 +302,9 @@ class Activity(Window, gtk.Container):
|
||||
share_scope = self._jobject.metadata['share-scope']
|
||||
|
||||
# handle activity share/join
|
||||
mesh_instance = self._pservice.get_activity(self._activity_id,
|
||||
warn_if_none=False)
|
||||
pservice = presenceservice.get_instance()
|
||||
mesh_instance = pservice.get_activity(self._activity_id,
|
||||
warn_if_none=False)
|
||||
logging.debug("*** Act %s, mesh instance %r, scope %s",
|
||||
self._activity_id, mesh_instance, share_scope)
|
||||
if mesh_instance is not None:
|
||||
|
@ -75,11 +75,14 @@ def create_activity_id():
|
||||
|
||||
# check through network activities
|
||||
found = False
|
||||
logging.info('KILL_PS check the activity_id is not used in the network')
|
||||
"""
|
||||
activities = pservice.get_activities()
|
||||
for act in activities:
|
||||
if act_id == act.props.id:
|
||||
found = True
|
||||
break
|
||||
"""
|
||||
if not found:
|
||||
return act_id
|
||||
raise RuntimeError("Cannot generate unique activity id.")
|
||||
|
@ -25,7 +25,14 @@ import logging
|
||||
import dbus
|
||||
import gobject
|
||||
import telepathy
|
||||
from telepathy.client import Channel
|
||||
from telepathy.interfaces import CHANNEL, \
|
||||
CHANNEL_TYPE_TUBES, \
|
||||
CHANNEL_TYPE_TEXT, \
|
||||
CONNECTION
|
||||
from telepathy.constants import HANDLE_TYPE_ROOM
|
||||
|
||||
CONN_INTERFACE_ACTIVITY_PROPERTIES = 'org.laptop.Telepathy.ActivityProperties'
|
||||
|
||||
_logger = logging.getLogger('sugar.presence.activity')
|
||||
|
||||
@ -64,34 +71,14 @@ class Activity(gobject.GObject):
|
||||
'joined': (bool, None, None, False, gobject.PARAM_READABLE),
|
||||
}
|
||||
|
||||
_PRESENCE_SERVICE = "org.laptop.Sugar.Presence"
|
||||
_ACTIVITY_DBUS_INTERFACE = "org.laptop.Sugar.Presence.Activity"
|
||||
|
||||
def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
|
||||
"""Initialse the activity interface, connecting to service"""
|
||||
def __init__(self, connection, room_handle):
|
||||
gobject.GObject.__init__(self)
|
||||
self.telepathy_room_handle = None
|
||||
self._object_path = object_path
|
||||
self._ps_new_object = new_obj_cb
|
||||
self._ps_del_object = del_obj_cb
|
||||
bobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
|
||||
self._activity = dbus.Interface(bobj, self._ACTIVITY_DBUS_INTERFACE)
|
||||
self._activity.connect_to_signal('BuddyHandleJoined',
|
||||
self._buddy_handle_joined_cb)
|
||||
self._activity.connect_to_signal('BuddyLeft',
|
||||
self._buddy_left_cb)
|
||||
self._activity.connect_to_signal('NewChannel', self._new_channel_cb)
|
||||
self._activity.connect_to_signal('PropertiesChanged',
|
||||
self._properties_changed_cb,
|
||||
utf8_strings=True)
|
||||
# FIXME: this *would* just use a normal proxy call, but I want the
|
||||
# pending call object so I can block on it, and normal proxy methods
|
||||
# don't return those as of dbus-python 0.82.1; so do it the hard way
|
||||
self._get_properties_call = bus.call_async(self._PRESENCE_SERVICE,
|
||||
object_path, self._ACTIVITY_DBUS_INTERFACE, 'GetProperties',
|
||||
'', (), self._get_properties_reply_cb,
|
||||
self._get_properties_error_cb, utf8_strings=True)
|
||||
|
||||
self.telepathy_conn = connection
|
||||
self.telepathy_text_chan = None
|
||||
self.telepathy_tubes_chan = None
|
||||
|
||||
self._room_handle = room_handle
|
||||
self._id = None
|
||||
self._color = None
|
||||
self._name = None
|
||||
@ -99,31 +86,32 @@ class Activity(gobject.GObject):
|
||||
self._tags = None
|
||||
self._private = True
|
||||
self._joined = False
|
||||
# Cache for get_buddy_by_handle, maps handles to buddy object paths
|
||||
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
|
||||
bus = dbus.SessionBus()
|
||||
self._get_properties_call = bus.call_async(
|
||||
connection.requested_bus_name,
|
||||
connection.object_path,
|
||||
CONN_INTERFACE_ACTIVITY_PROPERTIES,
|
||||
'GetProperties',
|
||||
'u',
|
||||
(self._room_handle,),
|
||||
reply_handler=self._got_properties_cb,
|
||||
error_handler=self._error_handler_cb,
|
||||
utf8_strings=True)
|
||||
|
||||
def __repr__(self):
|
||||
return ('<proxy for %s at %x>' % (self._object_path, id(self)))
|
||||
|
||||
def _get_properties_reply_cb(self, new_props):
|
||||
def _got_properties_cb(self, properties):
|
||||
_logger.debug('_got_properties_cb', properties)
|
||||
self._get_properties_call = None
|
||||
_logger.debug('%r: initial GetProperties returned', self)
|
||||
self._properties_changed_cb(new_props)
|
||||
self._update_properties(properties)
|
||||
|
||||
def _get_properties_error_cb(self, e):
|
||||
self._get_properties_call = None
|
||||
# FIXME: do something with the error
|
||||
_logger.warning('%r: Error doing initial GetProperties: %s', self, e)
|
||||
def _error_handler_cb(self, error):
|
||||
_logger.debug('_error_handler_cb', error)
|
||||
|
||||
def _properties_changed_cb(self, new_props):
|
||||
_logger.debug('%r: Activity properties changed to %r', self, new_props)
|
||||
self._update_properties(new_props)
|
||||
|
||||
def _update_properties(self, new_props):
|
||||
val = new_props.get('name', self._name)
|
||||
if isinstance(val, str) and val != self._name:
|
||||
self._name = val
|
||||
@ -244,16 +232,8 @@ class Activity(gobject.GObject):
|
||||
returns list of presence Buddy objects that we can successfully
|
||||
create from the buddy object paths that PS has for this activity.
|
||||
"""
|
||||
resp = self._activity.GetJoinedBuddies()
|
||||
buddies = []
|
||||
for item in resp:
|
||||
try:
|
||||
buddies.append(self._ps_new_object(item))
|
||||
except dbus.DBusException:
|
||||
_logger.debug(
|
||||
'get_joined_buddies failed to get buddy object for %r',
|
||||
item)
|
||||
return buddies
|
||||
logging.info('KILL_PS return joined buddies')
|
||||
return []
|
||||
|
||||
def get_buddy_by_handle(self, handle):
|
||||
"""Retrieve the Buddy object given a telepathy handle.
|
||||
@ -293,62 +273,38 @@ class Activity(gobject.GObject):
|
||||
_logger.debug('%r: finished setting up tubes', self)
|
||||
reply_handler()
|
||||
|
||||
def tubes_chan_ready(chan):
|
||||
_logger.debug('%r: Tubes channel %r is ready', self, chan)
|
||||
self.telepathy_tubes_chan = chan
|
||||
def tubes_channel_ready_cb(channel):
|
||||
_logger.debug('%r: Tubes channel %r is ready', self, channel)
|
||||
self.telepathy_tubes_chan = channel
|
||||
tubes_ready()
|
||||
|
||||
def text_chan_ready(chan):
|
||||
_logger.debug('%r: Text channel %r is ready', self, chan)
|
||||
self.telepathy_text_chan = chan
|
||||
def text_channel_ready_cb(channel):
|
||||
_logger.debug('%r: Text channel %r is ready', self, channel)
|
||||
self.telepathy_text_chan = channel
|
||||
tubes_ready()
|
||||
|
||||
def conn_ready(conn):
|
||||
_logger.debug('%r: Connection %r is ready', self, conn)
|
||||
self.telepathy_conn = conn
|
||||
found_text_channel = False
|
||||
found_tubes_channel = False
|
||||
def create_text_channel_cb(channel_path):
|
||||
Channel(self.telepathy_conn.requested_bus_name, channel_path,
|
||||
ready_handler=text_channel_ready_cb)
|
||||
|
||||
for chan_path, chan_iface, handle_type, handle in chans:
|
||||
if handle_type != telepathy.HANDLE_TYPE_ROOM:
|
||||
return
|
||||
def create_tubes_channel_cb(channel_path):
|
||||
Channel(self.telepathy_conn.requested_bus_name, channel_path,
|
||||
ready_handler=tubes_channel_ready_cb)
|
||||
|
||||
if chan_iface == telepathy.CHANNEL_TYPE_TEXT:
|
||||
telepathy.client.Channel(
|
||||
conn.service_name, chan_path,
|
||||
ready_handler=text_chan_ready,
|
||||
error_handler=error_handler)
|
||||
found_text_channel = True
|
||||
self.telepathy_room_handle = handle
|
||||
def error_handler_cb(error):
|
||||
raise RuntimeError(error)
|
||||
|
||||
elif chan_iface == telepathy.CHANNEL_TYPE_TUBES:
|
||||
telepathy.client.Channel(
|
||||
conn.service_name, chan_path,
|
||||
ready_handler=tubes_chan_ready,
|
||||
error_handler=error_handler)
|
||||
found_tubes_channel = True
|
||||
self.telepathy_conn.RequestChannel(CHANNEL_TYPE_TEXT,
|
||||
HANDLE_TYPE_ROOM, self._room_handle, True,
|
||||
reply_handler=create_text_channel_cb,
|
||||
error_handler=error_handler_cb,
|
||||
dbus_interface=CONNECTION)
|
||||
|
||||
if not found_text_channel:
|
||||
error_handler(AssertionError("Presence Service didn't create "
|
||||
"a chatroom"))
|
||||
elif not found_tubes_channel:
|
||||
error_handler(AssertionError("Presence Service didn't create "
|
||||
"tubes channel"))
|
||||
|
||||
def channels_listed(bus_name, conn_path, channels):
|
||||
_logger.debug('%r: Connection on %s at %s, channels: %r',
|
||||
self, bus_name, conn_path, channels)
|
||||
|
||||
# can't use assignment for this due to Python scoping
|
||||
chans.extend(channels)
|
||||
|
||||
telepathy.client.Connection(bus_name, conn_path,
|
||||
ready_handler=conn_ready,
|
||||
error_handler=error_handler)
|
||||
|
||||
|
||||
self._activity.ListChannels(reply_handler=channels_listed,
|
||||
error_handler=error_handler)
|
||||
self.telepathy_conn.RequestChannel(CHANNEL_TYPE_TUBES,
|
||||
HANDLE_TYPE_ROOM, self._room_handle, True,
|
||||
reply_handler=create_tubes_channel_cb,
|
||||
error_handler=error_handler_cb,
|
||||
dbus_interface=CONNECTION)
|
||||
|
||||
def _join_cb(self):
|
||||
_logger.debug('%r: Join finished', self)
|
||||
@ -370,11 +326,7 @@ class Activity(gobject.GObject):
|
||||
|
||||
_logger.debug('%r: joining', self)
|
||||
|
||||
def joined():
|
||||
self.set_up_tubes(reply_handler=self._join_cb,
|
||||
error_handler=self._join_error_cb)
|
||||
|
||||
self._activity.Join(reply_handler=joined,
|
||||
self.set_up_tubes(reply_handler=self._join_cb,
|
||||
error_handler=self._join_error_cb)
|
||||
|
||||
# GetChannels() wrapper
|
||||
|
@ -20,12 +20,21 @@
|
||||
STABLE.
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
import gobject
|
||||
import gtk
|
||||
import dbus
|
||||
import gconf
|
||||
from telepathy.interfaces import CONNECTION_INTERFACE_ALIASING, \
|
||||
CONNECTION_INTERFACE_CONTACTS
|
||||
|
||||
CONN_INTERFACE_BUDDY_INFO = 'org.laptop.Telepathy.BuddyInfo'
|
||||
|
||||
_logger = logging.getLogger('sugar.presence.buddy')
|
||||
|
||||
|
||||
class Buddy(gobject.GObject):
|
||||
class BaseBuddy(gobject.GObject):
|
||||
"""UI interface for a Buddy in the presence service
|
||||
|
||||
Each buddy interface tracks a set of activities and properties
|
||||
@ -42,6 +51,8 @@ class Buddy(gobject.GObject):
|
||||
See __gproperties__
|
||||
"""
|
||||
|
||||
__gtype_name__ = 'PresenceBaseBuddy'
|
||||
|
||||
__gsignals__ = {
|
||||
'icon-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])),
|
||||
'joined-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
@ -52,53 +63,17 @@ class Buddy(gobject.GObject):
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
}
|
||||
|
||||
__gproperties__ = {
|
||||
'key': (str, None, None, None, gobject.PARAM_READABLE),
|
||||
'icon': (str, None, None, None, gobject.PARAM_READABLE),
|
||||
'nick': (str, None, None, None, gobject.PARAM_READABLE),
|
||||
'color': (str, None, None, None, gobject.PARAM_READABLE),
|
||||
'current-activity': (object, None, None, gobject.PARAM_READABLE),
|
||||
'owner': (bool, None, None, False, gobject.PARAM_READABLE),
|
||||
'ip4-address': (str, None, None, None, gobject.PARAM_READABLE),
|
||||
'tags': (str, None, None, None, gobject.PARAM_READABLE),
|
||||
}
|
||||
|
||||
_PRESENCE_SERVICE = "org.laptop.Sugar.Presence"
|
||||
_BUDDY_DBUS_INTERFACE = "org.laptop.Sugar.Presence.Buddy"
|
||||
|
||||
def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
|
||||
"""Initialise the reference to the buddy
|
||||
|
||||
bus -- dbus bus object
|
||||
new_obj_cb -- callback to call when this buddy joins an activity
|
||||
del_obj_cb -- callback to call when this buddy leaves an activity
|
||||
object_path -- path to the buddy object
|
||||
"""
|
||||
def __init__(self):
|
||||
gobject.GObject.__init__(self)
|
||||
self._object_path = object_path
|
||||
self._ps_new_object = new_obj_cb
|
||||
self._ps_del_object = del_obj_cb
|
||||
self._properties = {}
|
||||
self._activities = {}
|
||||
|
||||
bobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
|
||||
self._buddy = dbus.Interface(bobj, self._BUDDY_DBUS_INTERFACE)
|
||||
|
||||
self._icon_changed_signal = self._buddy.connect_to_signal(
|
||||
'IconChanged', self._icon_changed_cb, byte_arrays=True)
|
||||
self._joined_activity_signal = self._buddy.connect_to_signal(
|
||||
'JoinedActivity', self._joined_activity_cb)
|
||||
self._left_activity_signal = self._buddy.connect_to_signal(
|
||||
'LeftActivity', self._left_activity_cb)
|
||||
self._property_changed_signal = self._buddy.connect_to_signal(
|
||||
'PropertyChanged', self._property_changed_cb)
|
||||
|
||||
self._properties = self._get_properties_helper()
|
||||
|
||||
activities = self._buddy.GetJoinedActivities()
|
||||
for op in activities:
|
||||
self._activities[op] = self._ps_new_object(op)
|
||||
self._key = None
|
||||
self._icon = None
|
||||
self._nick = None
|
||||
self._color = None
|
||||
self._current_activity = None
|
||||
self._owner = False
|
||||
self._ip4_address = None
|
||||
self._tags = None
|
||||
|
||||
def destroy(self):
|
||||
self._icon_changed_signal.remove()
|
||||
@ -114,41 +89,68 @@ class Buddy(gobject.GObject):
|
||||
return {}
|
||||
return props
|
||||
|
||||
def do_get_property(self, pspec):
|
||||
"""Retrieve a particular property from our property dictionary
|
||||
def get_key(self):
|
||||
return self._key
|
||||
|
||||
pspec -- XXX some sort of GTK specifier object with attributes
|
||||
including 'name', 'active' and 'icon-name'
|
||||
"""
|
||||
if pspec.name == "key":
|
||||
return self._properties["key"]
|
||||
elif pspec.name == "nick":
|
||||
return self._properties["nick"]
|
||||
elif pspec.name == "color":
|
||||
return self._properties["color"]
|
||||
elif pspec.name == "tags":
|
||||
return self._properties["tags"]
|
||||
elif pspec.name == "current-activity":
|
||||
if not self._properties.has_key("current-activity"):
|
||||
return None
|
||||
curact = self._properties["current-activity"]
|
||||
if not len(curact):
|
||||
return None
|
||||
for activity in self._activities.values():
|
||||
if activity.props.id == curact:
|
||||
return activity
|
||||
def set_key(self, key):
|
||||
self._key = key
|
||||
|
||||
key = gobject.property(type=str, getter=get_key, setter=set_key)
|
||||
|
||||
def get_icon(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
icon = gobject.property(type=str, getter=get_icon)
|
||||
|
||||
def get_nick(self):
|
||||
return self._nick
|
||||
|
||||
def set_nick(self, nick):
|
||||
self._nick = nick
|
||||
|
||||
nick = gobject.property(type=str, getter=get_nick, setter=set_nick)
|
||||
|
||||
def get_color(self):
|
||||
return self._color
|
||||
|
||||
def set_color(self, color):
|
||||
self._color = color
|
||||
|
||||
color = gobject.property(type=str, getter=get_color, setter=set_color)
|
||||
|
||||
def get_current_activity(self):
|
||||
if self._current_activity is None:
|
||||
return None
|
||||
elif pspec.name == "owner":
|
||||
return self._properties["owner"]
|
||||
elif pspec.name == "icon":
|
||||
if not self._icon:
|
||||
self._icon = str(self._buddy.GetIcon(byte_arrays=True))
|
||||
return self._icon
|
||||
elif pspec.name == "ip4-address":
|
||||
# IPv4 address will go away quite soon
|
||||
if not self._properties.has_key("ip4-address"):
|
||||
return None
|
||||
return self._properties["ip4-address"]
|
||||
for activity in self._activities.values():
|
||||
if activity.props.id == self._current_activity:
|
||||
return activity
|
||||
return None
|
||||
|
||||
current_activity = gobject.property(type=object, getter=get_current_activity)
|
||||
|
||||
def get_owner(self):
|
||||
return self._owner
|
||||
|
||||
def set_owner(self, owner):
|
||||
self._owner = owner
|
||||
|
||||
owner = gobject.property(type=bool, getter=get_owner, setter=set_owner, default=False)
|
||||
|
||||
def get_ip4_address(self):
|
||||
return self._ip4_address
|
||||
|
||||
def set_ip4_address(self, ip4_address):
|
||||
self._ip4_address = ip4_address
|
||||
|
||||
ip4_address = gobject.property(type=str, getter=get_ip4_address, setter=set_ip4_address)
|
||||
|
||||
def get_tags(self):
|
||||
return self._tags
|
||||
|
||||
def set_tags(self, tags):
|
||||
self._tags = tags
|
||||
|
||||
tags = gobject.property(type=str, getter=get_tags, setter=set_tags)
|
||||
|
||||
def object_path(self):
|
||||
"""Retrieve our dbus object path"""
|
||||
@ -160,16 +162,16 @@ class Buddy(gobject.GObject):
|
||||
self.emit('icon-changed')
|
||||
return False
|
||||
|
||||
def _icon_changed_cb(self, icon_data):
|
||||
def __icon_changed_cb(self, icon_data):
|
||||
"""Handle dbus signal by emitting a GObject signal"""
|
||||
gobject.idle_add(self._emit_icon_changed_signal, icon_data)
|
||||
|
||||
def _emit_joined_activity_signal(self, object_path):
|
||||
def __emit_joined_activity_signal(self, object_path):
|
||||
"""Emit activity joined signal with Activity object"""
|
||||
self.emit('joined-activity', self._ps_new_object(object_path))
|
||||
return False
|
||||
|
||||
def _joined_activity_cb(self, object_path):
|
||||
def __joined_activity_cb(self, object_path):
|
||||
"""Handle dbus signal by emitting a GObject signal
|
||||
|
||||
Stores the activity in activities dictionary as well
|
||||
@ -187,7 +189,7 @@ class Buddy(gobject.GObject):
|
||||
self.emit('left-activity', self._ps_new_object(object_path))
|
||||
return False
|
||||
|
||||
def _left_activity_cb(self, object_path):
|
||||
def __left_activity_cb(self, object_path):
|
||||
"""Handle dbus signal by emitting a GObject signal
|
||||
|
||||
Also removes from the activities dictionary
|
||||
@ -207,7 +209,7 @@ class Buddy(gobject.GObject):
|
||||
self.emit('property-changed', prop_list)
|
||||
return False
|
||||
|
||||
def _property_changed_cb(self, prop_list):
|
||||
def __property_changed_cb(self, prop_list):
|
||||
"""Handle dbus signal by emitting a GObject signal"""
|
||||
gobject.idle_add(self._handle_property_changed_signal, prop_list)
|
||||
|
||||
@ -241,3 +243,92 @@ class Buddy(gobject.GObject):
|
||||
for item in resp:
|
||||
acts.append(self._ps_new_object(item))
|
||||
return acts
|
||||
|
||||
|
||||
class Buddy(BaseBuddy):
|
||||
__gtype_name__ = 'PresenceBuddy'
|
||||
def __init__(self, connection, contact_handle):
|
||||
BaseBuddy.__init__(self)
|
||||
|
||||
self._contact_handle = contact_handle
|
||||
|
||||
bus = dbus.SessionBus()
|
||||
self._get_properties_call = bus.call_async(
|
||||
connection.requested_bus_name,
|
||||
connection.object_path,
|
||||
CONN_INTERFACE_BUDDY_INFO,
|
||||
'GetProperties',
|
||||
'u',
|
||||
(self._contact_handle,),
|
||||
reply_handler=self.__got_properties_cb,
|
||||
error_handler=self.__error_handler_cb,
|
||||
utf8_strings=True,
|
||||
byte_arrays=True)
|
||||
|
||||
self._get_attributes_call = bus.call_async(
|
||||
connection.requested_bus_name,
|
||||
connection.object_path,
|
||||
CONNECTION_INTERFACE_CONTACTS,
|
||||
'GetContactAttributes',
|
||||
'auasb',
|
||||
([self._contact_handle], [CONNECTION_INTERFACE_ALIASING], False),
|
||||
reply_handler=self.__got_attributes_cb,
|
||||
error_handler=self.__error_handler_cb)
|
||||
|
||||
def __got_properties_cb(self, properties):
|
||||
_logger.debug('__got_properties_cb', properties)
|
||||
self._get_properties_call = None
|
||||
self._update_properties(properties)
|
||||
|
||||
def __got_attributes_cb(self, attributes):
|
||||
_logger.debug('__got_attributes_cb', attributes)
|
||||
self._get_attributes_call = None
|
||||
self._update_attributes(attributes[self._contact_handle])
|
||||
|
||||
def __error_handler_cb(self, error):
|
||||
_logger.debug('__error_handler_cb', error)
|
||||
|
||||
def __properties_changed_cb(self, new_props):
|
||||
_logger.debug('%r: Buddy properties changed to %r', self, new_props)
|
||||
self._update_properties(new_props)
|
||||
|
||||
def _update_properties(self, properties):
|
||||
if 'key' in properties:
|
||||
self.props.key = properties['key']
|
||||
if 'icon' in properties:
|
||||
self.props.icon = properties['icon']
|
||||
if 'color' in properties:
|
||||
self.props.color = properties['color']
|
||||
if 'current-activity' in properties:
|
||||
self.props.current_activity = properties['current-activity']
|
||||
if 'owner' in properties:
|
||||
self.props.owner = properties['owner']
|
||||
if 'ip4-address' in properties:
|
||||
self.props.ip4_address = properties['ip4-address']
|
||||
if 'tags' in properties:
|
||||
self.props.tags = properties['tags']
|
||||
|
||||
def _update_attributes(self, attributes):
|
||||
nick_key = CONNECTION_INTERFACE_ALIASING + '/alias'
|
||||
if nick_key in attributes:
|
||||
self.props.nick = attributes[nick_key]
|
||||
|
||||
def do_get_property(self, pspec):
|
||||
if self._get_properties_call is not None:
|
||||
_logger.debug('%r: Blocking on GetProperties() because someone '
|
||||
'wants property %s', self, pspec.name)
|
||||
self._get_properties_call.block()
|
||||
|
||||
return BaseBuddy.do_get_property(self, pspec)
|
||||
|
||||
|
||||
class Owner(BaseBuddy):
|
||||
|
||||
__gtype_name__ = 'PresenceOwner'
|
||||
|
||||
def __init__(self):
|
||||
BaseBuddy.__init__(self)
|
||||
|
||||
client = gconf.client_get_default()
|
||||
self.props.nick = client.get_string("/desktop/sugar/user/nick")
|
||||
self.props.color = client.get_string("/desktop/sugar/user/color")
|
||||
|
@ -23,19 +23,16 @@ STABLE.
|
||||
import logging
|
||||
import traceback
|
||||
|
||||
import gobject
|
||||
import dbus
|
||||
import dbus.exceptions
|
||||
import dbus.glib
|
||||
import gobject
|
||||
|
||||
from sugar.presence.buddy import Buddy
|
||||
from sugar.presence.buddy import Buddy, Owner
|
||||
from sugar.presence.activity import Activity
|
||||
from sugar.presence.util import get_connection_manager
|
||||
|
||||
|
||||
DBUS_SERVICE = "org.laptop.Sugar.Presence"
|
||||
DBUS_INTERFACE = "org.laptop.Sugar.Presence"
|
||||
DBUS_PATH = "/org/laptop/Sugar/Presence"
|
||||
|
||||
_logger = logging.getLogger('sugar.presence.presenceservice')
|
||||
|
||||
|
||||
@ -66,92 +63,12 @@ class PresenceService(gobject.GObject):
|
||||
gobject.TYPE_PYOBJECT])),
|
||||
}
|
||||
|
||||
_PS_BUDDY_OP = DBUS_PATH + "/Buddies/"
|
||||
_PS_ACTIVITY_OP = DBUS_PATH + "/Activities/"
|
||||
|
||||
def __init__(self, allow_offline_iface=True):
|
||||
def __init__(self):
|
||||
"""Initialise the service and attempt to connect to events
|
||||
"""
|
||||
gobject.GObject.__init__(self)
|
||||
self._objcache = {}
|
||||
self._joined = None
|
||||
|
||||
# Get a connection to the session bus
|
||||
self._bus = dbus.SessionBus()
|
||||
self._bus.add_signal_receiver(self._name_owner_changed_cb,
|
||||
signal_name="NameOwnerChanged",
|
||||
dbus_interface="org.freedesktop.DBus")
|
||||
|
||||
# attempt to load the interface to the service...
|
||||
self._allow_offline_iface = allow_offline_iface
|
||||
self._get_ps()
|
||||
|
||||
def _name_owner_changed_cb(self, name, old, new):
|
||||
if name != DBUS_SERVICE:
|
||||
return
|
||||
if (old and len(old)) and (not new and not len(new)):
|
||||
# PS went away, clear out PS dbus service wrapper
|
||||
self._ps_ = None
|
||||
elif (not old and not len(old)) and (new and len(new)):
|
||||
# PS started up
|
||||
self._get_ps()
|
||||
|
||||
_ps_ = None
|
||||
|
||||
def _get_ps(self):
|
||||
"""Retrieve dbus interface to PresenceService
|
||||
|
||||
Also registers for updates from various dbus events on the
|
||||
interface.
|
||||
|
||||
If unable to retrieve the interface, we will temporarily
|
||||
return an _OfflineInterface object to allow the calling
|
||||
code to continue functioning as though it had accessed a
|
||||
real presence service.
|
||||
|
||||
If successful, caches the presence service interface
|
||||
for use by other methods and returns that interface
|
||||
"""
|
||||
if not self._ps_:
|
||||
try:
|
||||
# NOTE: We need to follow_name_owner_changes here
|
||||
# because we can not connect to a signal unless
|
||||
# we follow the changes or we start the service
|
||||
# before we connect. Starting the service here
|
||||
# causes a major bottleneck during startup
|
||||
ps = dbus.Interface(
|
||||
self._bus.get_object(DBUS_SERVICE,
|
||||
DBUS_PATH,
|
||||
follow_name_owner_changes=True),
|
||||
DBUS_INTERFACE)
|
||||
except dbus.exceptions.DBusException, err:
|
||||
_logger.error(
|
||||
"""Failure retrieving %r interface from
|
||||
the D-BUS service %r %r: %s""",
|
||||
DBUS_INTERFACE, DBUS_SERVICE, DBUS_PATH, err)
|
||||
if self._allow_offline_iface:
|
||||
return _OfflineInterface()
|
||||
raise RuntimeError('Failed to connect to the presence '
|
||||
'service.')
|
||||
else:
|
||||
self._ps_ = ps
|
||||
ps.connect_to_signal('BuddyAppeared',
|
||||
self._buddy_appeared_cb)
|
||||
ps.connect_to_signal('BuddyDisappeared',
|
||||
self._buddy_disappeared_cb)
|
||||
ps.connect_to_signal('ActivityAppeared',
|
||||
self._activity_appeared_cb)
|
||||
ps.connect_to_signal('ActivityDisappeared',
|
||||
self._activity_disappeared_cb)
|
||||
ps.connect_to_signal('ActivityInvitation',
|
||||
self._activity_invitation_cb)
|
||||
ps.connect_to_signal('PrivateInvitation',
|
||||
self._private_invitation_cb)
|
||||
return self._ps_
|
||||
|
||||
_ps = property(_get_ps, None, None,
|
||||
"""DBUS interface to the PresenceService
|
||||
(services/presence/presenceservice)""")
|
||||
self._buddy_cache = {}
|
||||
|
||||
def _new_object(self, object_path):
|
||||
"""Turn new object path into (cached) Buddy/Activity instance
|
||||
@ -289,17 +206,11 @@ class PresenceService(gobject.GObject):
|
||||
returns list of Activity objects for all object paths
|
||||
the service reports exist (using GetActivities)
|
||||
"""
|
||||
try:
|
||||
resp = self._ps.GetActivities()
|
||||
except dbus.exceptions.DBusException:
|
||||
_logger.exception('Unable to retrieve activity list from '
|
||||
'presence service')
|
||||
return []
|
||||
else:
|
||||
acts = []
|
||||
for item in resp:
|
||||
acts.append(self._new_object(item))
|
||||
return acts
|
||||
resp = self._ps.GetActivities()
|
||||
acts = []
|
||||
for item in resp:
|
||||
acts.append(self._new_object(item))
|
||||
return acts
|
||||
|
||||
def _get_activities_cb(self, reply_handler, resp):
|
||||
acts = []
|
||||
@ -338,14 +249,14 @@ class PresenceService(gobject.GObject):
|
||||
returns single Activity object or None if the activity
|
||||
is not found using GetActivityById on the service
|
||||
"""
|
||||
try:
|
||||
act_op = self._ps.GetActivityById(activity_id)
|
||||
except dbus.exceptions.DBusException, err:
|
||||
if warn_if_none:
|
||||
_logger.warn("Unable to retrieve activity handle for %r from "
|
||||
"presence service: %s", activity_id, err)
|
||||
return None
|
||||
return self._new_object(act_op)
|
||||
for connection in get_connection_manager().connections:
|
||||
try:
|
||||
room_handle = connection.GetActivity(activity_id)
|
||||
return Activity(connection, room_handle)
|
||||
except:
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
def get_buddies(self):
|
||||
"""Retrieve set of all buddies from service
|
||||
@ -426,26 +337,19 @@ class PresenceService(gobject.GObject):
|
||||
channel-specific handle.
|
||||
:Returns: the Buddy object, or None if the buddy is not found
|
||||
"""
|
||||
try:
|
||||
buddy_op = self._ps.GetBuddyByTelepathyHandle(tp_conn_name,
|
||||
tp_conn_path,
|
||||
handle)
|
||||
except dbus.exceptions.DBusException, err:
|
||||
_logger.warn('Unable to retrieve buddy handle for handle %u at '
|
||||
'conn %s:%s from presence service: %s',
|
||||
handle, tp_conn_name, tp_conn_path, err)
|
||||
return None
|
||||
return self._new_object(buddy_op)
|
||||
logging.info('KILL_PS decide how to invalidate this cache')
|
||||
if (tp_conn_path, handle) in self._buddy_cache:
|
||||
return self._buddy_cache[(tp_conn_path, handle)]
|
||||
else:
|
||||
bus = dbus.SessionBus()
|
||||
connection = bus.get_object(tp_conn_name, tp_conn_path)
|
||||
buddy = Buddy(connection, handle)
|
||||
self._buddy_cache[(tp_conn_path, handle)] = buddy
|
||||
return buddy
|
||||
|
||||
def get_owner(self):
|
||||
"""Retrieves the laptop "owner" Buddy object."""
|
||||
try:
|
||||
owner_op = self._ps.GetOwner()
|
||||
except dbus.exceptions.DBusException:
|
||||
_logger.exception('Unable to retrieve local user/owner from '
|
||||
'presence service')
|
||||
raise RuntimeError("Could not get owner object.")
|
||||
return self._new_object(owner_op)
|
||||
"""Retrieves the laptop Buddy object."""
|
||||
return Owner()
|
||||
|
||||
def _share_activity_cb(self, activity, op):
|
||||
"""Finish sharing the activity
|
||||
@ -505,14 +409,11 @@ class PresenceService(gobject.GObject):
|
||||
should use when talking directly to telepathy
|
||||
|
||||
returns the bus name and the object path of the Telepathy connection"""
|
||||
|
||||
try:
|
||||
bus_name, object_path = self._ps.GetPreferredConnection()
|
||||
except dbus.exceptions.DBusException:
|
||||
logging.error(traceback.format_exc())
|
||||
connection = get_connection_manager().get_preferred_connection()
|
||||
if connection is None:
|
||||
return None
|
||||
|
||||
return bus_name, object_path
|
||||
else:
|
||||
return connection.requested_bus_name, connection.object_path
|
||||
|
||||
|
||||
class _OfflineInterface(object):
|
||||
@ -596,5 +497,5 @@ def get_instance(allow_offline_iface=False):
|
||||
"""Retrieve this process' view of the PresenceService"""
|
||||
global _ps
|
||||
if not _ps:
|
||||
_ps = PresenceService(allow_offline_iface)
|
||||
_ps = PresenceService()
|
||||
return _ps
|
||||
|
Loading…
Reference in New Issue
Block a user