Switch sugar/presence module over to a thin API wrapper around the PresenceService dbus API
This commit is contained in:
+67
-162
@@ -1,189 +1,94 @@
|
||||
import base64
|
||||
import logging
|
||||
|
||||
import gtk
|
||||
import gobject
|
||||
|
||||
from sugar.p2p import Stream
|
||||
from sugar.p2p import network
|
||||
from sugar.presence import Service
|
||||
|
||||
PRESENCE_SERVICE_TYPE = "_presence_olpc._tcp"
|
||||
import dbus, dbus_bindings
|
||||
|
||||
class Buddy(gobject.GObject):
|
||||
"""Represents another person on the network and keeps track of the
|
||||
activities and resources they make available for sharing."""
|
||||
|
||||
__gsignals__ = {
|
||||
'icon-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
'IconChanged': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([])),
|
||||
'service-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
'ServiceAppeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'service-removed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
'ServiceDisappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'joined-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_STRING])),
|
||||
'left-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_STRING]))
|
||||
'JoinedActivity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'LeftActivity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT]))
|
||||
}
|
||||
|
||||
def __init__(self, service):
|
||||
_PRESENCE_SERVICE = "org.laptop.Presence"
|
||||
_BUDDY_DBUS_INTERFACE = "org.laptop.Presence.Buddy"
|
||||
|
||||
def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
|
||||
gobject.GObject.__init__(self)
|
||||
self._services = {}
|
||||
self._nick_name = service.get_name()
|
||||
self._address = service.get_publisher_address()
|
||||
self._valid = False
|
||||
self._icon = None
|
||||
self._icon_tries = 0
|
||||
self._owner = False
|
||||
self.add_service(service)
|
||||
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._buddy = dbus.Interface(bobj, self._BUDDY_DBUS_INTERFACE)
|
||||
self._buddy.connect_to_signal('IconChanged', self._icon_changed_cb)
|
||||
self._buddy.connect_to_signal('ServiceAppeared', self._service_appeared_cb)
|
||||
self._buddy.connect_to_signal('ServiceDisappeared', self._service_disappeared_cb)
|
||||
self._buddy.connect_to_signal('JoinedActivity', self._joined_activity_cb)
|
||||
self._buddy.connect_to_signal('LeftActivity', self._left_activity_cb)
|
||||
|
||||
def _request_buddy_icon_cb(self, result_status, response, user_data):
|
||||
"""Callback when icon request has completed."""
|
||||
icon = response
|
||||
service = user_data
|
||||
if result_status == network.RESULT_SUCCESS:
|
||||
if icon and len(icon):
|
||||
icon = base64.b64decode(icon)
|
||||
print "Buddy icon for '%s' is size %d" % (self._nick_name, len(icon))
|
||||
self.set_icon(icon)
|
||||
def object_path(self):
|
||||
return self._object_path
|
||||
|
||||
if (result_status == network.RESULT_FAILED or not icon) and self._icon_tries < 3:
|
||||
self._icon_tries = self._icon_tries + 1
|
||||
print "Failed to retrieve buddy icon for '%s' on try %d of %d" % (self._nick_name, \
|
||||
self._icon_tries, 3)
|
||||
gobject.timeout_add(1000, self._request_buddy_icon, service)
|
||||
def _emit_icon_changed_signal(self):
|
||||
self.emit('IconChanged')
|
||||
return False
|
||||
|
||||
def _request_buddy_icon(self, service):
|
||||
"""Contact the buddy to retrieve the buddy icon."""
|
||||
buddy_stream = Stream.Stream.new_from_service(service, start_reader=False)
|
||||
writer = buddy_stream.new_writer(service)
|
||||
success = writer.custom_request("get_buddy_icon", self._request_buddy_icon_cb, service)
|
||||
if not success:
|
||||
del writer, buddy_stream
|
||||
gobject.timeout_add(1000, self._request_buddy_icon, service)
|
||||
def _icon_changed_cb(self):
|
||||
gobject.idle_add(self._emit_icon_changed_signal)
|
||||
|
||||
def _emit_service_appeared_signal(self, object_path):
|
||||
self.emit('ServiceAppeared', self._ps_new_object(object_path))
|
||||
return False
|
||||
|
||||
def add_service(self, service):
|
||||
"""Adds a new service to this buddy's service list, returning
|
||||
True if the service was successfully added, and False if it was not."""
|
||||
if service.get_name() != self._nick_name:
|
||||
return False
|
||||
publisher_addr = service.get_publisher_address()
|
||||
if publisher_addr != self._address:
|
||||
logging.error('Service publisher and buddy address doesnt match: %s %s' % (publisher_addr, self._address))
|
||||
return False
|
||||
stype = service.get_type()
|
||||
if stype in self._services.keys():
|
||||
return False
|
||||
self._services[stype] = service
|
||||
if self._valid:
|
||||
self.emit("service-added", service)
|
||||
def _service_appeared_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_service_appeared_signal, object_path)
|
||||
|
||||
# If this is the first service we've seen that's owned by
|
||||
# a particular activity, send out the 'joined-activity' signal
|
||||
actid = service.get_activity_id()
|
||||
if actid is not None:
|
||||
found = False
|
||||
for serv in self._services.values():
|
||||
if serv.get_activity_id() == actid and serv.get_type() != stype:
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
print "Buddy (%s) joined activity %s." % (self._nick_name, actid)
|
||||
self.emit("joined-activity", service)
|
||||
def _emit_service_disappeared_signal(self, object_path):
|
||||
self.emit('ServiceDisappeared', self._ps_new_object(object_path))
|
||||
return False
|
||||
|
||||
if stype == PRESENCE_SERVICE_TYPE:
|
||||
# A buddy isn't valid until its official presence
|
||||
# service has been found and resolved
|
||||
self._valid = True
|
||||
print 'Requesting buddy icon %s' % self._nick_name
|
||||
self._request_buddy_icon(service)
|
||||
return True
|
||||
def _service_disappeared_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_service_disappeared_signal, object_path)
|
||||
|
||||
def remove_service(self, service):
|
||||
"""Remove a service from a buddy; ie, the activity was closed
|
||||
or the buddy went away."""
|
||||
if service.get_publisher_address() != self._address:
|
||||
return
|
||||
if service.get_name() != self._nick_name:
|
||||
return
|
||||
stype = service.get_type()
|
||||
if self._services.has_key(stype):
|
||||
if self._valid:
|
||||
self.emit("service-removed", service)
|
||||
del self._services[stype]
|
||||
def _emit_joined_activity_signal(self, object_path):
|
||||
self.emit('JoinedActivity', self._ps_new_object(object_path))
|
||||
return False
|
||||
|
||||
# If this is the lase service owned by a particular activity,
|
||||
# and it's just been removed, send out the 'left-actvity' signal
|
||||
actid = service.get_activity_id()
|
||||
if actid is not None:
|
||||
found = False
|
||||
for serv in self._services.values():
|
||||
if serv.get_activity_id() == actid:
|
||||
found = True
|
||||
break
|
||||
if not found:
|
||||
print "Buddy (%s) left activity %s." % (self._nick_name, actid)
|
||||
self.emit("left-activity", service)
|
||||
def _joined_activity_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_joined_activity_signal, object_path)
|
||||
|
||||
if stype == PRESENCE_SERVICE_TYPE:
|
||||
self._valid = False
|
||||
def _emit_left_activity_signal(self, object_path):
|
||||
self.emit('LeftActivity', self._ps_new_object(object_path))
|
||||
return False
|
||||
|
||||
def get_service_of_type(self, stype=None, activity=None):
|
||||
"""Return a service of a certain type, or None if the buddy
|
||||
doesn't provide that service."""
|
||||
if not stype:
|
||||
raise RuntimeError("Need to specify a service type.")
|
||||
def _left_activity_cb(self, object_path):
|
||||
gobject.idle_add(self._emit_left_activity_signal, object_path)
|
||||
|
||||
if activity:
|
||||
actid = activity.get_id()
|
||||
for service in self._services.values():
|
||||
if service.get_type() == stype and service.get_activity_id() == actid:
|
||||
return service
|
||||
if self._services.has_key(stype):
|
||||
return self._services[stype]
|
||||
return None
|
||||
def getProperties(self):
|
||||
return self._buddy.getProperties()
|
||||
|
||||
def is_valid(self):
|
||||
"""Return whether the buddy is valid or not. A buddy is
|
||||
not valid until its official presence service has been found
|
||||
and successfully resolved."""
|
||||
return self._valid
|
||||
def getIcon(self):
|
||||
return self._buddy.getIcon()
|
||||
|
||||
def get_icon_pixbuf(self):
|
||||
if self._icon:
|
||||
pbl = gtk.gdk.PixbufLoader()
|
||||
pbl.write(self._icon)
|
||||
pbl.close()
|
||||
return pbl.get_pixbuf()
|
||||
else:
|
||||
def getServiceOfType(self, stype):
|
||||
try:
|
||||
object_path = self._buddy.getServiceOfType(stype)
|
||||
except dbus_bindings.DBusException:
|
||||
return None
|
||||
return self._ps_new_object(object_path)
|
||||
|
||||
def get_icon(self):
|
||||
"""Return the buddies icon, if any."""
|
||||
return self._icon
|
||||
|
||||
def get_address(self):
|
||||
return self._address
|
||||
|
||||
def get_nick_name(self):
|
||||
return self._nick_name
|
||||
|
||||
def set_icon(self, icon):
|
||||
"""Can only set icon for other buddies. The Owner
|
||||
takes care of setting it's own icon."""
|
||||
if icon != self._icon:
|
||||
self._icon = icon
|
||||
self.emit("icon-changed")
|
||||
|
||||
def is_owner(self):
|
||||
return self._owner
|
||||
|
||||
|
||||
class Owner(Buddy):
|
||||
"""Class representing the owner of the machine. This is the client
|
||||
portion of the Owner, paired with the server portion in Owner.py."""
|
||||
def __init__(self, service):
|
||||
Buddy.__init__(self, service)
|
||||
self._owner = True
|
||||
def getJoinedActivities(self):
|
||||
try:
|
||||
resp = self._buddy.getJoinedActivities()
|
||||
except dbus_bindings.DBusException:
|
||||
return []
|
||||
acts = []
|
||||
for item in resp:
|
||||
acts.append(self._ps_new_object(item))
|
||||
return acts
|
||||
|
||||
Reference in New Issue
Block a user