Make the PresenceService stuff start to work

This commit is contained in:
Dan Williams 2006-07-22 23:56:40 -05:00
parent 1c35f8d92c
commit b63e78a174
8 changed files with 104 additions and 64 deletions

View File

@ -4,6 +4,9 @@ import base64
from sugar import env from sugar import env
from sugar.p2p import Stream from sugar.p2p import Stream
from sugar.presence import PresenceService
PRESENCE_SERVICE_TYPE = "_presence_olpc._tcp"
class ShellOwner(object): class ShellOwner(object):
"""Class representing the owner of this machine/instance. This class """Class representing the owner of this machine/instance. This class
@ -27,21 +30,12 @@ class ShellOwner(object):
fd.close() fd.close()
break break
# Our presence service # Create and announce our presence
port = random.randint(40000, 65000) self._pservice = PresenceService.PresenceService()
properties = {} self._service = self._pservice.registerService(nick, PRESENCE_SERVICE_TYPE)
print "Owner '%s' using port %d" % (nick, service.get_port())
# self._service = Service.Service(nick, Buddy.PRESENCE_SERVICE_TYPE, self._icon_stream = Stream.Stream.new_from_service(self._service)
# domain="", address=None, port=port, properties=properties) self._icon_stream.register_reader_handler(self._handle_buddy_icon_request, "get_buddy_icon")
# 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)
def _handle_buddy_icon_request(self): def _handle_buddy_icon_request(self):
"""XMLRPC method, return the owner's icon encoded with base64.""" """XMLRPC method, return the owner's icon encoded with base64."""

View File

@ -175,6 +175,12 @@ class PresenceServiceDBusHelper(dbus.service.Object):
raise NotFoundError("Not found") raise NotFoundError("Not found")
return owner.object_path() 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()
class PresenceService(object): class PresenceService(object):
def __init__(self): def __init__(self):
@ -202,8 +208,8 @@ class PresenceService(object):
self._registered_service_types = [] self._registered_service_types = []
# Set up the dbus service we provide # Set up the dbus service we provide
session_bus = dbus.SessionBus() self._session_bus = dbus.SessionBus()
self._bus_name = dbus.service.BusName(_PRESENCE_SERVICE, bus=session_bus) self._bus_name = dbus.service.BusName(_PRESENCE_SERVICE, bus=self._session_bus)
self._dbus_helper = PresenceServiceDBusHelper(self, self._bus_name) self._dbus_helper = PresenceServiceDBusHelper(self, self._bus_name)
# Connect to Avahi for mDNS stuff # Connect to Avahi for mDNS stuff
@ -515,17 +521,19 @@ class PresenceService(object):
def _new_domain_cb_glue(self, interface, protocol, domain, flags=0): def _new_domain_cb_glue(self, interface, protocol, domain, flags=0):
gobject.idle_add(self._new_domain_cb, interface, protocol, domain, flags) 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.""" """Register a new service, advertising it to other Buddies on the network."""
objid = self._get_next_object_id() objid = self._get_next_object_id()
service = Service.Service(self._bus_name, objid, name=name, service = Service.Service(self._bus_name, objid, name=name,
stype=stype, domain=domain, address=address, port=port, stype=stype, domain=domain, address=address, port=port,
properties=properties) properties=properties)
key = (name, stype)
self._services[key] = service self._services[key] = service
if self.get_owner() and name != self.get_owner().get_nick_name(): 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!") raise RuntimeError("Tried to register a service that didn't have Owner nick as the service name!")
actid = service.get_activity_id() actid = service.get_activity_id()
rs_name = name
if actid: if actid:
rs_name = Service.compose_service_name(rs_name, actid) rs_name = Service.compose_service_name(rs_name, actid)
rs_stype = service.get_type() rs_stype = service.get_type()
@ -538,11 +546,12 @@ class PresenceService(object):
logging.debug("registered service name '%s' type '%s' on port %d with args %s" % (rs_name, rs_stype, rs_port, rs_props)) logging.debug("registered service name '%s' type '%s' on port %d with args %s" % (rs_name, rs_stype, rs_port, rs_props))
try: try:
group = dbus.Interface(self._bus.get_object(avahi.DBUS_NAME, self._server.EntryGroupNew()), avahi.DBUS_INTERFACE_ENTRY_GROUP) obj = self._session_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 # Add properties; ensure they are converted to ByteArray types
# because python sometimes can't figure that out # because python sometimes can't figure that out
info = [] info = [""]
for k, v in rs_props.items(): for k, v in rs_props.items():
tmp_item = "%s=%s" % (k, v) tmp_item = "%s=%s" % (k, v)
info.append(dbus.types.ByteArray(tmp_item)) info.append(dbus.types.ByteArray(tmp_item))
@ -564,6 +573,7 @@ class PresenceService(object):
pass pass
activity_stype = service.get_type() activity_stype = service.get_type()
self.register_service_type(activity_stype) self.register_service_type(activity_stype)
return service
def register_service_type(self, stype): def register_service_type(self, stype):
"""Requests that the Presence service look for and recognize """Requests that the Presence service look for and recognize

View File

@ -3,6 +3,7 @@ import sys, os
sys.path.insert(0, os.path.abspath("../../")) sys.path.insert(0, os.path.abspath("../../"))
from sugar import util from sugar import util
import dbus, dbus.service import dbus, dbus.service
import random
def _txt_to_dict(txt): def _txt_to_dict(txt):
"""Convert an avahi-returned TXT record formatted """Convert an avahi-returned TXT record formatted
@ -53,18 +54,6 @@ def _decompose_service_name(name):
return (None, name) return (None, name)
return (activity_id, name[:start - 2]) 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" _ACTIVITY_ID_TAG = "ActivityID"
SERVICE_DBUS_INTERFACE = "org.laptop.Presence.Service" SERVICE_DBUS_INTERFACE = "org.laptop.Presence.Service"
@ -86,7 +75,9 @@ class ServiceDBusHelper(dbus.service.Object):
pary['name'] = self._parent.get_name() pary['name'] = self._parent.get_name()
pary['type'] = self._parent.get_type() pary['type'] = self._parent.get_type()
pary['domain'] = self._parent.get_domain() 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() port = self._parent.get_port()
if port: if port:
pary['port'] = self._parent.get_port() pary['port'] = self._parent.get_port()
@ -190,11 +181,6 @@ class Service(object):
def get_full_name(self): def get_full_name(self):
return self._full_name 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): def get_one_property(self, key):
"""Return one property of the service, or None """Return one property of the service, or None
if the property was not found. Cannot distinguish if the property was not found. Cannot distinguish
@ -222,12 +208,14 @@ class Service(object):
# Set key/value pairs on internal property list # Set key/value pairs on internal property list
for key, value in props.items(): for key, value in props.items():
if len(key) == 0:
continue
tmp_key = key tmp_key = key
tmp_val = value tmp_val = value
if type(tmp_key) == type(u""): if type(tmp_key) != type(u""):
tmp_key = tmp_key.encode() tmp_key = unicode(tmp_key)
if type(tmp_val) == type(u""): if type(tmp_val) != type(u""):
tmp_val = tmp_val.encode() tmp_val = unicode(tmp_val)
self._properties[tmp_key] = tmp_val self._properties[tmp_key] = tmp_val
def get_type(self): def get_type(self):
@ -242,6 +230,8 @@ class Service(object):
return self._port return self._port
def set_port(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): if type(port) != type(1) or (port <= 1024 and port > 65536):
raise ValueError("must specify a valid port number between 1024 and 65536.") raise ValueError("must specify a valid port number between 1024 and 65536.")
self._port = port self._port = port

View File

@ -1,6 +1,7 @@
import os import os
import gtk import gtk
import gobject import gobject
import time
from Shell import Shell from Shell import Shell
from Process import Process from Process import Process
@ -44,6 +45,17 @@ class MatchboxProcess(Process):
def get_name(self): def get_name(self):
return 'Matchbox' 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, True)
time.sleep(3)
class Session: class Session:
"""Takes care of running the shell and all the sugar processes""" """Takes care of running the shell and all the sugar processes"""
@ -58,6 +70,9 @@ class Session:
process = MatchboxProcess() process = MatchboxProcess()
process.start() process.start()
process = PresenceServiceProcess()
process.start()
shell = Shell() shell = Shell()
shell.start() shell.start()

View File

@ -56,7 +56,6 @@ class Shell:
bus_name = dbus.service.BusName('com.redhat.Sugar.Shell', bus=session_bus) bus_name = dbus.service.BusName('com.redhat.Sugar.Shell', bus=session_bus)
ShellDbusService(self, bus_name) ShellDbusService(self, bus_name)
self._ps = PresenceService.PresenceService()
self._owner = ShellOwner() self._owner = ShellOwner()
self._registry = ActivityRegistry() self._registry = ActivityRegistry()

View File

@ -8,6 +8,18 @@ import network
from MostlyReliablePipe import MostlyReliablePipe from MostlyReliablePipe import MostlyReliablePipe
from sugar.presence import Service 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): class Stream(object):
def __init__(self, service): def __init__(self, service):
if not service.get_port(): if not service.get_port():
@ -19,7 +31,7 @@ class Stream(object):
self._callback = None self._callback = None
def new_from_service(service, start_reader=True): def new_from_service(service, start_reader=True):
if service.is_multicast_service(): if is_multicast_address(service.get_address()):
return MulticastStream(service) return MulticastStream(service)
else: else:
return UnicastStream(service, start_reader) return UnicastStream(service, start_reader)
@ -75,28 +87,14 @@ class UnicastStream(Stream):
if start_reader: if start_reader:
self.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 """Start the stream's reader, which for UnicastStream objects is
and XMLRPC server. If there's a port conflict with some other and XMLRPC server. If there's a port conflict with some other
service, the reader will try to find another port to use instead. service, the reader will try to find another port to use instead.
Returns the port number used for the reader.""" Returns the port number used for the reader."""
# Set up 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 = network.GlibXMLRPCServer(("", self._reader_port))
self._reader.register_function(self._message, "message") 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
def _message(self, message): def _message(self, message):
"""Called by the XMLRPC server when network data arrives.""" """Called by the XMLRPC server when network data arrives."""

View File

@ -48,7 +48,7 @@ class PresenceService(gobject.GObject):
def __init__(self): def __init__(self):
gobject.GObject.__init__(self) gobject.GObject.__init__(self)
self._obcache = ObjectCache() self._objcache = ObjectCache()
self._bus = dbus.SessionBus() self._bus = dbus.SessionBus()
self._ps = dbus.Interface(self._bus.get_object(self._PRESENCE_SERVICE, self._ps = dbus.Interface(self._bus.get_object(self._PRESENCE_SERVICE,
self._PRESENCE_OBJECT_PATH), self._PRESENCE_DBUS_INTERFACE) self._PRESENCE_OBJECT_PATH), self._PRESENCE_DBUS_INTERFACE)
@ -174,3 +174,7 @@ class PresenceService(gobject.GObject):
return None return None
return self._new_object(buddy_op) return self._new_object(buddy_op)
def registerService(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)

View File

@ -14,12 +14,42 @@ class Service(gobject.GObject):
self._ps_del_object = del_obj_cb self._ps_del_object = del_obj_cb
sobj = bus.get_object(self._PRESENCE_SERVICE, object_path) sobj = bus.get_object(self._PRESENCE_SERVICE, object_path)
self._service = dbus.Interface(sobj, self._SERVICE_DBUS_INTERFACE) self._service = dbus.Interface(sobj, self._SERVICE_DBUS_INTERFACE)
self._props = self._service.getProperties()
def object_path(self): def object_path(self):
return self._object_path return self._object_path
def getProperties(self): def getProperties(self):
return self._service.getProperties() return self._props
def getPublishedValue(self, key): def getPublishedValue(self, key):
value = self._service.getPublishedValue(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