diff --git a/activities/browser/BrowserActivity.py b/activities/browser/BrowserActivity.py index f1f40afd..5cb64c09 100644 --- a/activities/browser/BrowserActivity.py +++ b/activities/browser/BrowserActivity.py @@ -57,7 +57,7 @@ class BrowserActivity(Activity): vbox.show() self._pservice = PresenceService() - self._pservice.connect('ServiceAppeared', self._service_appeared_cb) + self._pservice.connect('service-appeared', self._service_appeared_cb) # Join the shared activity if we were started from one if self._initial_service: diff --git a/activities/chat/ChatActivity.py b/activities/chat/ChatActivity.py index 5a8f383a..3239b6e7 100644 --- a/activities/chat/ChatActivity.py +++ b/activities/chat/ChatActivity.py @@ -54,17 +54,14 @@ class ChatListener: self._chats = {} - self._pservice = PresenceService.get_instance() - self._pservice.start() - self._pservice.track_service_type(BuddyChat.SERVICE_TYPE) + self._pservice = PresenceService() + self._pservice.register_service_type(BuddyChat.SERVICE_TYPE) def start(self): - port = random.randint(5000, 65535) - service = Service.Service(sugar.env.get_nick_name(), BuddyChat.SERVICE_TYPE, - 'local', '', port) - self._buddy_stream = Stream.new_from_service(service) + self._service = self._pservice.register_service(sugar.env.get_nick_name(), + BuddyChat.SERVICE_TYPE) + self._buddy_stream = Stream.new_from_service(self._service) self._buddy_stream.set_data_listener(self._recv_message) - self._pservice.register_service(service) def _recv_message(self, address, message): [nick, msg] = Chat.deserialize_message(message) diff --git a/shell/ActivitiesModel.py b/shell/ActivitiesModel.py index 72d4ba56..078e0d3a 100644 --- a/shell/ActivitiesModel.py +++ b/shell/ActivitiesModel.py @@ -36,7 +36,7 @@ class ActivitiesModel(gobject.GObject): self._activities = [] self._pservice = PresenceService() - self._pservice.connect("ActivityAppeared", self._on_activity_announced_cb) + self._pservice.connect("activity-appeared", self._on_activity_announced_cb) def add_activity(self, service): activity_info = ActivityInfo(service) diff --git a/shell/Owner.py b/shell/Owner.py index db9f7afa..450fba80 100644 --- a/shell/Owner.py +++ b/shell/Owner.py @@ -4,6 +4,9 @@ import base64 from sugar import env from sugar.p2p import Stream +from sugar.presence import PresenceService + +PRESENCE_SERVICE_TYPE = "_presence_olpc._tcp" class ShellOwner(object): """Class representing the owner of this machine/instance. This class @@ -27,21 +30,12 @@ class ShellOwner(object): fd.close() break - # Our presence service - port = random.randint(40000, 65000) - properties = {} - -# self._service = Service.Service(nick, Buddy.PRESENCE_SERVICE_TYPE, -# domain="", address=None, port=port, properties=properties) -# print "Owner '%s' using port %d" % (nick, port) - -# self._icon_stream = Stream.Stream.new_from_service(self._service) -# self._icon_stream.register_reader_handler(self._handle_buddy_icon_request, "get_buddy_icon") - - # Announce ourselves to the world -# self._pservice = PresenceService.PresenceService.get_instance() -# self._pservice.start() -# self._pservice.register_service(self._service) + # Create and announce our presence + 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()) + self._icon_stream = Stream.Stream.new_from_service(self._service) + self._icon_stream.register_reader_handler(self._handle_buddy_icon_request, "get_buddy_icon") def _handle_buddy_icon_request(self): """XMLRPC method, return the owner's icon encoded with base64.""" diff --git a/shell/PresenceService/PresenceService.py b/shell/PresenceService/PresenceService.py index 92fa8199..04a4b63c 100644 --- a/shell/PresenceService/PresenceService.py +++ b/shell/PresenceService/PresenceService.py @@ -175,6 +175,23 @@ class PresenceServiceDBusHelper(dbus.service.Object): raise NotFoundError("Not found") return owner.object_path() + @dbus.service.method(_PRESENCE_DBUS_INTERFACE, + 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) + return service.object_path() + + @dbus.service.method(_PRESENCE_DBUS_INTERFACE, + in_signature="s", out_signature="") + def registerServiceType(self, stype): + self._parent.register_service_type(stype) + + @dbus.service.method(_PRESENCE_DBUS_INTERFACE, + in_signature="s", out_signature="") + def unregisterServiceType(self, stype): + self._parent.unregister_service_type(stype) + class PresenceService(object): def __init__(self): @@ -202,8 +219,8 @@ class PresenceService(object): self._registered_service_types = [] # Set up the dbus service we provide - session_bus = dbus.SessionBus() - self._bus_name = dbus.service.BusName(_PRESENCE_SERVICE, bus=session_bus) + self._session_bus = dbus.SessionBus() + self._bus_name = dbus.service.BusName(_PRESENCE_SERVICE, bus=self._session_bus) self._dbus_helper = PresenceServiceDBusHelper(self, self._bus_name) # Connect to Avahi for mDNS stuff @@ -363,6 +380,11 @@ class PresenceService(object): self._services[key] = service else: service = self._services[key] + if not service.get_address(): + set_addr = service.get_one_property('address') + if not set_addr: + set_addr = address + service.set_address(set_addr) adv.set_service(service) # Merge the service into our buddy and activity lists, if needed @@ -376,6 +398,9 @@ class PresenceService(object): gobject.idle_add(self._resolve_service_reply_cb, interface, protocol, name, stype, domain, host, aprotocol, address, port, txt, flags) + def _resolve_service_error_handler(self, err): + logging.error("error resolving service: %s" % err) + def _resolve_service(self, adv): """Resolve and lookup a ZeroConf service to obtain its address and TXT records.""" # Ask avahi to resolve this particular service @@ -515,46 +540,37 @@ class PresenceService(object): def _new_domain_cb_glue(self, interface, protocol, domain, flags=0): gobject.idle_add(self._new_domain_cb, interface, protocol, domain, flags) - def register_service(self, name, stype, properties, address, port, domain): + def register_service(self, name, stype, properties={}, address=None, port=None, domain=u"local"): """Register a new service, advertising it to other Buddies on the network.""" - objid = self._get_next_object_id() - service = Service.Service(self._bus_name, objid, name=name, - stype=stype, domain=domain, address=address, port=port, - properties=properties) - self._services[key] = service - if self.get_owner() and name != self.get_owner().get_nick_name(): raise RuntimeError("Tried to register a service that didn't have Owner nick as the service name!") - actid = service.get_activity_id() - if actid: - rs_name = Service.compose_service_name(rs_name, actid) - rs_stype = service.get_type() - rs_port = service.get_port() - rs_props = service.get_properties() - rs_domain = service.get_domain() - rs_address = service.get_address() - if not rs_domain or not len(rs_domain): - rs_domain = "" - logging.debug("registered service name '%s' type '%s' on port %d with args %s" % (rs_name, rs_stype, rs_port, rs_props)) + if not domain or not len(domain): + domain = u"local" try: - group = dbus.Interface(self._bus.get_object(avahi.DBUS_NAME, self._server.EntryGroupNew()), avahi.DBUS_INTERFACE_ENTRY_GROUP) + obj = self._system_bus.get_object(avahi.DBUS_NAME, self._mdns_service.EntryGroupNew()) + group = dbus.Interface(obj, avahi.DBUS_INTERFACE_ENTRY_GROUP) # Add properties; ensure they are converted to ByteArray types # because python sometimes can't figure that out info = [] - for k, v in rs_props.items(): - tmp_item = "%s=%s" % (k, v) - info.append(dbus.types.ByteArray(tmp_item)) + for k, v in properties.items(): + info.append(dbus.types.ByteArray("%s=%s" % (k, v))) - if rs_address and len(rs_address): - info.append("address=%s" % (rs_address)) - logging.debug("PS: about to call AddService for Avahi with rs_name='%s' (%s), rs_stype='%s' (%s)," \ - " rs_domain='%s' (%s), rs_port=%d (%s), info='%s' (%s)" % (rs_name, type(rs_name), rs_stype, - type(rs_stype), rs_domain, type(rs_domain), rs_port, type(rs_port), info, type(info))) - group.AddService(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, 0, rs_name, rs_stype, - rs_domain, "", # let Avahi figure the 'host' out - dbus.UInt16(rs_port), info,) + objid = self._get_next_object_id() + service = Service.Service(self._bus_name, objid, name=name, + stype=stype, domain=domain, address=address, port=port, + properties=properties) + self._services[(name, stype)] = service + port = service.get_port() + + if address and len(address): + info.append("address=%s" % (address)) + logging.debug("PS: Will register service with name='%s', stype='%s'," \ + " domain='%s', port=%d, info='%s'" % (name, stype, domain, port, info)) + group.AddService(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, 0, name, stype, + domain, "", # let Avahi figure the 'host' out + dbus.UInt16(port), info,) group.Commit() except dbus.dbus_bindings.DBusException, exc: # FIXME: ignore local name collisions, since that means @@ -562,8 +578,8 @@ class PresenceService(object): # should un-register it an re-register with the correct info if str(exc) == "Local name collision": pass - activity_stype = service.get_type() - self.register_service_type(activity_stype) + self.register_service_type(stype) + return service def register_service_type(self, stype): """Requests that the Presence service look for and recognize diff --git a/shell/PresenceService/Service.py b/shell/PresenceService/Service.py index d9a504cc..77cd8267 100644 --- a/shell/PresenceService/Service.py +++ b/shell/PresenceService/Service.py @@ -3,6 +3,7 @@ import sys, os sys.path.insert(0, os.path.abspath("../../")) from sugar import util import dbus, dbus.service +import random def _txt_to_dict(txt): """Convert an avahi-returned TXT record formatted @@ -53,18 +54,6 @@ def _decompose_service_name(name): return (None, name) return (activity_id, name[:start - 2]) -def is_multicast_address(address): - """Simple numerical check for whether an IP4 address - is in the range for multicast addresses or not.""" - if not address: - return False - if address[3] != '.': - return False - first = int(float(address[:3])) - if first >= 224 and first <= 239: - return True - return False - _ACTIVITY_ID_TAG = "ActivityID" SERVICE_DBUS_INTERFACE = "org.laptop.Presence.Service" @@ -86,7 +75,9 @@ class ServiceDBusHelper(dbus.service.Object): pary['name'] = self._parent.get_name() pary['type'] = self._parent.get_type() pary['domain'] = self._parent.get_domain() - pary['activityId'] = self._parent.get_activity_id() + actid = self._parent.get_activity_id() + if actid: + pary['activityId'] = actid port = self._parent.get_port() if port: pary['port'] = self._parent.get_port() @@ -190,11 +181,6 @@ class Service(object): def get_full_name(self): return self._full_name - def is_multicast_service(self): - """Return True if the service's address is a multicast address, - False if it is not.""" - return is_multicast_address(self._address) - def get_one_property(self, key): """Return one property of the service, or None if the property was not found. Cannot distinguish @@ -222,12 +208,14 @@ class Service(object): # Set key/value pairs on internal property list for key, value in props.items(): + if len(key) == 0: + continue tmp_key = key tmp_val = value - if type(tmp_key) == type(u""): - tmp_key = tmp_key.encode() - if type(tmp_val) == type(u""): - tmp_val = tmp_val.encode() + if type(tmp_key) != type(u""): + tmp_key = unicode(tmp_key) + if type(tmp_val) != type(u""): + tmp_val = unicode(tmp_val) self._properties[tmp_key] = tmp_val def get_type(self): @@ -242,6 +230,8 @@ class Service(object): return self._port def set_port(self, port): + if port == -1: + port = random.randint(4000, 65000) if type(port) != type(1) or (port <= 1024 and port > 65536): raise ValueError("must specify a valid port number between 1024 and 65536.") self._port = port @@ -257,6 +247,8 @@ class Service(object): if type(address) != type(u""): raise ValueError("address must be unicode") self._address = address + if not self._publisher_address: + self._publisher_address = address def get_domain(self): """Return the ZeroConf/mDNS domain the service was found in.""" diff --git a/shell/PresenceView.py b/shell/PresenceView.py index fafd5778..4b471bcf 100644 --- a/shell/PresenceView.py +++ b/shell/PresenceView.py @@ -21,8 +21,8 @@ class PresenceView(gtk.VBox): self._shell = shell self._pservice = PresenceService() - self._pservice.connect("BuddyAppeared", self._on_buddy_appeared_cb) - self._pservice.connect("BuddyDisappeared", self._on_buddy_disappeared_cb) + self._pservice.connect("buddy-appeared", self._on_buddy_appeared_cb) + self._pservice.connect("buddy-disappeared", self._on_buddy_disappeared_cb) self._setup_ui() diff --git a/shell/Session.py b/shell/Session.py index 87ea3dbd..412dd736 100644 --- a/shell/Session.py +++ b/shell/Session.py @@ -1,6 +1,7 @@ import os import gtk import gobject +import time from Shell import Shell from Process import Process @@ -44,6 +45,17 @@ class MatchboxProcess(Process): def get_name(self): return 'Matchbox' +class PresenceServiceProcess(Process): + def __init__(self): + Process.__init__(self, "python shell/PresenceService/PresenceService.py",) + + def get_name(self): + return "PresenceService" + + def start(self): + Process.start(self) + time.sleep(3) + class Session: """Takes care of running the shell and all the sugar processes""" @@ -57,7 +69,10 @@ class Session: process = MatchboxProcess() process.start() - + + process = PresenceServiceProcess() + process.start() + shell = Shell() shell.start() diff --git a/shell/Shell.py b/shell/Shell.py index 2dc411c2..6866cc42 100755 --- a/shell/Shell.py +++ b/shell/Shell.py @@ -56,7 +56,6 @@ class Shell: bus_name = dbus.service.BusName('com.redhat.Sugar.Shell', bus=session_bus) ShellDbusService(self, bus_name) - self._ps = PresenceService.PresenceService() self._owner = ShellOwner() self._registry = ActivityRegistry() diff --git a/sugar/chat/ActivityChat.py b/sugar/chat/ActivityChat.py index ff5c057f..85e61bf2 100644 --- a/sugar/chat/ActivityChat.py +++ b/sugar/chat/ActivityChat.py @@ -10,7 +10,7 @@ class ActivityChat(GroupChat): self._chat_service = None self._activity = activity - self._pservice.connect('ServiceAppeared', self._service_appeared_cb) + self._pservice.connect('service-appeared', self._service_appeared_cb) # Find an existing activity chat to latch onto #activity_ps = self._pservice.getActivity(activity.get_id()) diff --git a/sugar/chat/Chat.py b/sugar/chat/Chat.py index 20c566e4..df6e48a6 100644 --- a/sugar/chat/Chat.py +++ b/sugar/chat/Chat.py @@ -9,6 +9,7 @@ import dbus.glib import gtk import gobject import pango +import logging from sugar.chat.Emoticons import Emoticons from sugar.chat.ChatToolbar import ChatToolbar @@ -233,7 +234,7 @@ class Chat(gtk.VBox): return if self._stream_writer: self._stream_writer.write(self.serialize_message(svgdata)) - owner = PresenceService.get_instance().get_owner() + owner = self._pservice.get_owner() if owner: self._insert_sketch(owner, svgdata) @@ -245,12 +246,12 @@ class Chat(gtk.VBox): self._stream_writer.write(self.serialize_message(text)) else: print 'Cannot send message, there is no stream writer' - owner = PresenceService.get_instance().get_owner() + owner = self._pservice.get_owner() if owner: self._insert_rich_message(owner, text) def serialize_message(self, message): - owner = PresenceService.get_instance().get_owner() + owner = self._pservice.get_owner() return owner.get_nick_name() + '||' + message def deserialize_message(message): diff --git a/sugar/p2p/Stream.py b/sugar/p2p/Stream.py index 6a0df2d9..9350123d 100644 --- a/sugar/p2p/Stream.py +++ b/sugar/p2p/Stream.py @@ -8,6 +8,18 @@ import network from MostlyReliablePipe import MostlyReliablePipe from sugar.presence import Service +def is_multicast_address(address): + """Simple numerical check for whether an IP4 address + is in the range for multicast addresses or not.""" + if not address: + return False + if address[3] != '.': + return False + first = int(float(address[:3])) + if first >= 224 and first <= 239: + return True + return False + class Stream(object): def __init__(self, service): if not service.get_port(): @@ -19,7 +31,7 @@ class Stream(object): self._callback = None def new_from_service(service, start_reader=True): - if service.is_multicast_service(): + if is_multicast_address(service.get_address()): return MulticastStream(service) else: return UnicastStream(service, start_reader) @@ -75,28 +87,14 @@ class UnicastStream(Stream): if start_reader: self.start_reader() - def start_reader(self, update_service_port=True): + def start_reader(self): """Start the stream's reader, which for UnicastStream objects is and XMLRPC server. If there's a port conflict with some other service, the reader will try to find another port to use instead. Returns the port number used for the reader.""" # Set up the reader - started = False - tries = 10 - self._reader = None - while not started and tries > 0: - try: - self._reader = network.GlibXMLRPCServer(("", self._reader_port)) - self._reader.register_function(self._message, "message") - if update_service_port: - self._service.set_port(self._reader_port) # Update the service's port - started = True - except(socket.error): - self._reader_port = random.randint(self._reader_port + 1, 65500) - tries = tries - 1 - if self._reader is None: - print 'Could not start stream reader.' - return self._reader_port + self._reader = network.GlibXMLRPCServer(("", self._reader_port)) + self._reader.register_function(self._message, "message") def _message(self, message): """Called by the XMLRPC server when network data arrives.""" diff --git a/sugar/presence/Activity.py b/sugar/presence/Activity.py index 24281268..a7c2f7a1 100644 --- a/sugar/presence/Activity.py +++ b/sugar/presence/Activity.py @@ -4,13 +4,13 @@ import dbus, dbus_bindings class Activity(gobject.GObject): __gsignals__ = { - 'BuddyJoined': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + 'buddy-joined': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), - 'BuddyLeft': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + 'buddy-left': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), - 'ServiceAppeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + 'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), - 'ServiceDisappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + 'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])) } @@ -33,67 +33,67 @@ class Activity(gobject.GObject): return self._object_path def _emit_buddy_joined_signal(self, object_path): - self.emit('BuddyJoined', self._ps_new_object(object_path)) + self.emit('buddy-joined', self._ps_new_object(object_path)) return False def _buddy_joined_cb(self, object_path): gobject.idle_add(self._emit_buddy_joined_signal, object_path) def _emit_buddy_left_signal(self, object_path): - self.emit('BuddyLeft', self._ps_new_object(object_path)) + self.emit('buddy-left', self._ps_new_object(object_path)) return False def _buddy_left_cb(self, object_path): gobject.idle_add(self._emit_buddy_left_signal, object_path) def _emit_service_appeared_signal(self, object_path): - self.emit('ServiceAppeared', self._ps_new_object(object_path)) + self.emit('service-appeared', self._ps_new_object(object_path)) return False def _service_appeared_cb(self, object_path): gobject.idle_add(self._emit_service_appeared_signal, object_path) def _emit_service_disappeared_signal(self, object_path): - self.emit('ServiceDisappeared', self._ps_new_object(object_path)) + self.emit('service-disappeared', self._ps_new_object(object_path)) return False def _service_disappeared_cb(self, object_path): gobject.idle_add(self._emit_service_disappeared_signal, object_path) - def getId(self): + def get_id(self): return self._activity.getId() - def getIcon(self): + def get_icon(self): return self._buddy.getIcon() - def getServiceOfType(self, stype): + def get_service_of_type(self, stype): try: object_path = self._buddy.getServiceOfType(stype) except dbus_bindings.DBusException: return None return self._ps_new_object(object_path) - def getServices(self): + def get_services(self): resp = self._activity.getServices() servs = [] for item in resp: servs.append(self._ps_new_object(item)) return servs - def getServicesOfType(self, stype): + def get_services_of_type(self, stype): resp = self._activity.getServicesOfType(stype) servs = [] for item in resp: servs.append(self._ps_new_object(item)) return servs - def getJoinedBuddies(self): + def get_joined_buddies(self): resp = self._activity.getJoinedBuddies(stype) buddies = [] for item in resp: buddies.append(self._ps_new_object(item)) return buddies - def ownerHasJoined(self): + def owner_has_joined(self): # FIXME return False diff --git a/sugar/presence/Buddy.py b/sugar/presence/Buddy.py index ca269460..7baefdb6 100644 --- a/sugar/presence/Buddy.py +++ b/sugar/presence/Buddy.py @@ -1,18 +1,19 @@ import gobject +import gtk import dbus, dbus_bindings class Buddy(gobject.GObject): __gsignals__ = { - 'IconChanged': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + 'icon-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])), - 'ServiceAppeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + 'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), - 'ServiceDisappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + 'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), - 'JoinedActivity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + 'joined-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), - 'LeftActivity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + 'left-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])) } @@ -24,6 +25,7 @@ class Buddy(gobject.GObject): self._object_path = object_path self._ps_new_object = new_obj_cb self._ps_del_object = del_obj_cb + self._properties = {} 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) @@ -31,59 +33,83 @@ class Buddy(gobject.GObject): 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) + self._buddy.connect_to_signal('PropertyChanged', self._property_changed_cb) + self._properties = self._buddy.getProperties() def object_path(self): return self._object_path def _emit_icon_changed_signal(self): - self.emit('IconChanged') + self.emit('icon-changed') return False 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)) + self.emit('service-appeared', self._ps_new_object(object_path)) return False def _service_appeared_cb(self, object_path): gobject.idle_add(self._emit_service_appeared_signal, object_path) def _emit_service_disappeared_signal(self, object_path): - self.emit('ServiceDisappeared', self._ps_new_object(object_path)) + self.emit('service-disappeared', self._ps_new_object(object_path)) return False def _service_disappeared_cb(self, object_path): gobject.idle_add(self._emit_service_disappeared_signal, object_path) def _emit_joined_activity_signal(self, object_path): - self.emit('JoinedActivity', self._ps_new_object(object_path)) + self.emit('joined-activity', self._ps_new_object(object_path)) return False def _joined_activity_cb(self, object_path): gobject.idle_add(self._emit_joined_activity_signal, object_path) def _emit_left_activity_signal(self, object_path): - self.emit('LeftActivity', self._ps_new_object(object_path)) + self.emit('left-activity', self._ps_new_object(object_path)) return False def _left_activity_cb(self, object_path): gobject.idle_add(self._emit_left_activity_signal, object_path) - def getProperties(self): - return self._buddy.getProperties() + def _handle_property_changed_signal(self, prop_list): + self._properties = self._buddy.getProperties() - def getIcon(self): + def _property_changed_cb(self, prop_list): + gobject.idle_add(self._handle_property_changed_signal, prop_list) + + def get_name(self): + return self._properties['name'] + + def get_ip4_address(self): + return self._properties['ip4_address'] + + def is_owner(self): + return self._properties['owner'] + + def get_icon(self): return self._buddy.getIcon() - def getServiceOfType(self, stype): + def get_icon_pixbuf(self): + icon = self._buddy.getIcon() + if icon: + pbl = gtk.gdk.PixbufLoader() + pbl.write(icon) + pbl.close() + return pbl.get_pixbuf() + else: + return None + + def get_service_of_type(self, stype): try: object_path = self._buddy.getServiceOfType(stype) except dbus_bindings.DBusException: return None return self._ps_new_object(object_path) - def getJoinedActivities(self): + def get_joined_activities(self): try: resp = self._buddy.getJoinedActivities() except dbus_bindings.DBusException: diff --git a/sugar/presence/PresenceService.py b/sugar/presence/PresenceService.py index ac00d1fa..cfbaed97 100644 --- a/sugar/presence/PresenceService.py +++ b/sugar/presence/PresenceService.py @@ -24,17 +24,17 @@ class ObjectCache(object): class PresenceService(gobject.GObject): __gsignals__ = { - 'BuddyAppeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + 'buddy-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), - 'BuddyDisappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + 'buddy-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), - 'ServiceAppeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + 'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), - 'ServiceDisappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + 'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), - 'ActivityAppeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + 'activity-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])), - 'ActivityDisappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, + 'activity-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([gobject.TYPE_PYOBJECT])) } @@ -48,12 +48,16 @@ class PresenceService(gobject.GObject): def __init__(self): gobject.GObject.__init__(self) - self._obcache = ObjectCache() + self._objcache = ObjectCache() self._bus = dbus.SessionBus() self._ps = dbus.Interface(self._bus.get_object(self._PRESENCE_SERVICE, self._PRESENCE_OBJECT_PATH), self._PRESENCE_DBUS_INTERFACE) self._ps.connect_to_signal('BuddyAppeared', self._buddy_appeared_cb) self._ps.connect_to_signal('BuddyDisappeared', self._buddy_disappeared_cb) + self._ps.connect_to_signal('ServiceAppeared', self._service_appeared_cb) + self._ps.connect_to_signal('ServiceDisappeared', self._service_disappeared_cb) + self._ps.connect_to_signal('ActivityAppeared', self._activity_appeared_cb) + self._ps.connect_to_signal('ActivityDisappeared', self._activity_disappeared_cb) def _new_object(self, object_path): obj = self._objcache.get(object_path) @@ -77,100 +81,109 @@ class PresenceService(gobject.GObject): pass def _emit_buddy_appeared_signal(self, object_path): - self.emit('BuddyAppeared', self._new_object(object_path)) + self.emit('buddy-appeared', self._new_object(object_path)) return False def _buddy_appeared_cb(self, op): gobject.idle_add(self._emit_buddy_appeared_signal, op) def _emit_buddy_disappeared_signal(self, object_path): - self.emit('BuddyDisappeared', self._ps_new_object(object_path)) + self.emit('buddy-disappeared', self._new_object(object_path)) return False def _buddy_disappeared_cb(self, object_path): gobject.idle_add(self._emit_buddy_disappeared_signal, object_path) def _emit_service_appeared_signal(self, object_path): - self.emit('ServiceAppeared', self._ps_new_object(object_path)) + self.emit('service-appeared', self._new_object(object_path)) return False def _service_appeared_cb(self, object_path): gobject.idle_add(self._emit_service_appeared_signal, object_path) def _emit_service_disappeared_signal(self, object_path): - self.emit('ServiceDisappeared', self._ps_new_object(object_path)) + self.emit('service-disappeared', self._new_object(object_path)) return False def _service_disappeared_cb(self, object_path): gobject.idle_add(self._emit_service_disappeared_signal, object_path) def _emit_activity_appeared_signal(self, object_path): - self.emit('ActivityAppeared', self._ps_new_object(object_path)) + self.emit('activity-appeared', self._new_object(object_path)) return False def _activity_appeared_cb(self, object_path): gobject.idle_add(self._emit_activity_appeared_signal, object_path) def _emit_activity_disappeared_signal(self, object_path): - self.emit('ActivityDisappeared', self._ps_new_object(object_path)) + self.emit('activity-disappeared', self._new_object(object_path)) return False def _activity_disappeared_cb(self, object_path): gobject.idle_add(self._emit_activity_disappeared_signal, object_path) - def getServices(self): + def get_services(self): resp = self._ps.getServices() servs = [] for item in resp: servs.append(self._new_object(item)) return servs - def getServicesOfType(self, stype): + def get_services_of_type(self, stype): resp = self._ps.getServicesOfType(stype) servs = [] for item in resp: servs.append(self._new_object(item)) return servs - def getActivities(self): + def get_activities(self): resp = self._ps.getActivities() acts = [] for item in resp: acts.append(self._new_object(item)) return acts - def getActivity(self, activity_id): + def get_activity(self, activity_id): try: act_op = self._ps.getActivity(activity_id) except dbus_bindings.DBusException: return None return self._new_object(act_op) - def getBuddies(self): + def get_buddies(self): resp = self._ps.getBuddies() buddies = [] for item in resp: buddies.append(self._new_object(item)) return buddies - def getBuddyByName(self, name): + def get_buddy_by_name(self, name): try: buddy_op = self._ps.getBuddyByName(name) except dbus_bindings.DBusException: return None return self._new_object(buddy_op) - def getBuddyByAddress(self, addr): + def get_buddy_by_address(self, addr): try: buddy_op = self._ps.getBuddyByAddress(addr) except dbus_bindings.DBusException: return None return self._new_object(buddy_op) - def getOwner(self): + def get_owner(self): try: owner_op = self._ps.getOwner() except dbus_bindings.DBusException: return None - return self._new_object(buddy_op) + return self._new_object(owner_op) + def register_service(self, name, stype, properties={"":""}, address="", port=-1, domain=u"local"): + serv_op = self._ps.registerService(name, stype, properties, address, port, domain) + return self._new_object(serv_op) + + def register_service_type(self, stype): + self._ps.registerServiceType(stype) + + def unregister_service_type(self, stype): + self._ps.unregisterServiceType(stype) diff --git a/sugar/presence/Service.py b/sugar/presence/Service.py index f5e6eaec..1b09161f 100644 --- a/sugar/presence/Service.py +++ b/sugar/presence/Service.py @@ -14,12 +14,43 @@ class Service(gobject.GObject): self._ps_del_object = del_obj_cb sobj = bus.get_object(self._PRESENCE_SERVICE, object_path) self._service = dbus.Interface(sobj, self._SERVICE_DBUS_INTERFACE) + self._service.connect_to_signal('PropertyChanged', self._property_changed_cb) + self._props = self._service.getProperties() def object_path(self): return self._object_path - def getProperties(self): - return self._service.getProperties() + def _property_changed_cb(self, prop_list): + self._props = self._service.getProperties() - def getPublishedValue(self, key): + def get_published_value(self, key): value = self._service.getPublishedValue(key) + + def get_name(self): + return self._props['name'] + + def get_type(self): + return self._props['type'] + + def get_domain(self): + return self._props['domain'] + + def get_address(self): + if self._props.has_key('address'): + return self._props['address'] + return None + + def get_activity_id(self): + if self._props.has_key('activityId'): + return self._props['activityId'] + return None + + def get_port(self): + if self._props.has_key('port'): + return self._props['port'] + return None + + def get_source_address(self): + if self._props.has_key('sourceAddress'): + return self._props['sourceAddress'] + return None