Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/sugar
diff options
context:
space:
mode:
authorJustin Gallardo <jirwin@suzy.(none)>2006-12-04 19:12:24 (GMT)
committer Justin Gallardo <jirwin@suzy.(none)>2006-12-04 19:12:24 (GMT)
commitb9f9ef0fe9e36cf6e5de59700154b16f2dae15cd (patch)
tree3d5403ec73e993a78c5e92f8b14a5b86e8b6ae60 /sugar
parentf5ae0662482de14f9d3812ddc4aba9be61024887 (diff)
Changed all tabs to 4 spaces for python style
Diffstat (limited to 'sugar')
-rw-r--r--sugar/TracebackUtils.py50
-rw-r--r--sugar/activity/Activity.py248
-rw-r--r--sugar/activity/ActivityFactory.py96
-rw-r--r--sugar/activity/__init__.py10
-rw-r--r--sugar/activity/bundle.py160
-rw-r--r--sugar/activity/bundlebuilder.py176
-rw-r--r--sugar/activity/bundleregistry.py86
-rw-r--r--sugar/chat/ActivityChat.py74
-rw-r--r--sugar/chat/Chat.py482
-rw-r--r--sugar/chat/ChatEditor.py140
-rw-r--r--sugar/chat/ChatToolbar.py252
-rw-r--r--sugar/chat/Emoticons.py120
-rw-r--r--sugar/chat/GroupChat.py20
-rw-r--r--sugar/chat/richtext.py832
-rw-r--r--sugar/chat/sketchpad/Sketch.py66
-rw-r--r--sugar/chat/sketchpad/SketchPad.py170
-rw-r--r--sugar/chat/sketchpad/Toolbox.py94
-rw-r--r--sugar/clipboard/ClipboardService.py118
-rw-r--r--sugar/emulator.py184
-rw-r--r--sugar/env.py48
-rw-r--r--sugar/graphics/ClipboardBubble.py210
-rw-r--r--sugar/graphics/bubble.py84
-rw-r--r--sugar/graphics/canvasicon.py240
-rw-r--r--sugar/graphics/grid.py24
-rw-r--r--sugar/graphics/iconcolor.py40
-rw-r--r--sugar/graphics/menu.py124
-rw-r--r--sugar/graphics/menuicon.py82
-rw-r--r--sugar/graphics/menushell.py160
-rw-r--r--sugar/graphics/snowflakebox.py100
-rw-r--r--sugar/graphics/spreadbox.py152
-rw-r--r--sugar/graphics/style.py24
-rw-r--r--sugar/graphics/stylesheet.py24
-rw-r--r--sugar/graphics/timeline.py182
-rw-r--r--sugar/logger.py118
-rw-r--r--sugar/p2p/MostlyReliablePipe.py2546
-rw-r--r--sugar/p2p/NotificationListener.py30
-rw-r--r--sugar/p2p/Notifier.py14
-rw-r--r--sugar/p2p/Stream.py242
-rw-r--r--sugar/p2p/network.py574
-rw-r--r--sugar/presence/Activity.py190
-rw-r--r--sugar/presence/Buddy.py340
-rw-r--r--sugar/presence/PresenceService.py394
-rw-r--r--sugar/presence/Service.py186
-rw-r--r--sugar/profile.py36
-rw-r--r--sugar/simulator.py226
-rw-r--r--sugar/util.py62
46 files changed, 4915 insertions, 4915 deletions
diff --git a/sugar/TracebackUtils.py b/sugar/TracebackUtils.py
index 86e28f9..940381e 100644
--- a/sugar/TracebackUtils.py
+++ b/sugar/TracebackUtils.py
@@ -22,33 +22,33 @@ import signal
haveThreadframe = True
try:
- import threadframe
+ import threadframe
except ImportError:
- haveThreadframe = False
+ haveThreadframe = False
class TracebackHelper(object):
- def __init__(self):
- fname = "%s-%d" % (os.path.basename(sys.argv[0]), os.getpid())
- self._fpath = os.path.join("/tmp", fname)
- print "Tracebacks will be written to %s on SIGUSR1" % self._fpath
- signal.signal(signal.SIGUSR1, self._handler)
+ def __init__(self):
+ fname = "%s-%d" % (os.path.basename(sys.argv[0]), os.getpid())
+ self._fpath = os.path.join("/tmp", fname)
+ print "Tracebacks will be written to %s on SIGUSR1" % self._fpath
+ signal.signal(signal.SIGUSR1, self._handler)
- def __del__(self):
- try:
- os.remove(self._fpath)
- except OSError:
- pass
+ def __del__(self):
+ try:
+ os.remove(self._fpath)
+ except OSError:
+ pass
- def _handler(self, signum, pframe):
- f = open(self._fpath, "a")
- if not haveThreadframe:
- f.write("Threadframe not installed. No traceback available.\n")
- else:
- frames = threadframe.dict()
- for thread_id, frame in frames.iteritems():
- f.write(('-' * 79) + '\n')
- f.write('[Thread %s] %d' % (thread_id, sys.getrefcount(frame)) + '\n')
- traceback.print_stack(frame, limit=None, file=f)
- f.write("\n")
- f.write('\n')
- f.close()
+ def _handler(self, signum, pframe):
+ f = open(self._fpath, "a")
+ if not haveThreadframe:
+ f.write("Threadframe not installed. No traceback available.\n")
+ else:
+ frames = threadframe.dict()
+ for thread_id, frame in frames.iteritems():
+ f.write(('-' * 79) + '\n')
+ f.write('[Thread %s] %d' % (thread_id, sys.getrefcount(frame)) + '\n')
+ traceback.print_stack(frame, limit=None, file=f)
+ f.write("\n")
+ f.write('\n')
+ f.close()
diff --git a/sugar/activity/Activity.py b/sugar/activity/Activity.py
index 2f27303..215ee85 100644
--- a/sugar/activity/Activity.py
+++ b/sugar/activity/Activity.py
@@ -32,133 +32,133 @@ ACTIVITY_SERVICE_PATH = "/org/laptop/Activity"
ACTIVITY_INTERFACE = "org.laptop.Activity"
def get_service_name(xid):
- return ACTIVITY_SERVICE_NAME + '%d' % xid
+ return ACTIVITY_SERVICE_NAME + '%d' % xid
def get_object_path(xid):
- return ACTIVITY_SERVICE_PATH + "/%s" % xid
+ return ACTIVITY_SERVICE_PATH + "/%s" % xid
class ActivityDbusService(dbus.service.Object):
- """Base dbus service object that each Activity uses to export dbus methods.
-
- The dbus service is separate from the actual Activity object so that we can
- tightly control what stuff passes through the dbus python bindings."""
-
- def start(self, pservice, activity):
- self._activity = activity
- self._pservice = pservice
-
- @dbus.service.method(ACTIVITY_INTERFACE)
- def share(self):
- """Called by the shell to request the activity to share itself on the network."""
- self._activity.share()
-
- @dbus.service.method(ACTIVITY_INTERFACE)
- def join(self, activity_ps_path):
- """Join the activity specified by its presence service path"""
- activity_ps = self._pservice.get(activity_ps_path)
- return self._activity.join(activity_ps)
-
- @dbus.service.method(ACTIVITY_INTERFACE)
- def get_id(self):
- """Get the activity identifier"""
- return self._activity.get_id()
-
- @dbus.service.method(ACTIVITY_INTERFACE)
- def get_type(self):
- """Get the activity type"""
- return self._activity.get_type()
-
- @dbus.service.method(ACTIVITY_INTERFACE)
- def get_shared(self):
- """Returns True if the activity is shared on the mesh."""
- return self._activity.get_shared()
-
- @dbus.service.method(ACTIVITY_INTERFACE,
- in_signature="sas", out_signature="")
- def execute(self, command, args):
- self._activity.execute(command, args)
+ """Base dbus service object that each Activity uses to export dbus methods.
+
+ The dbus service is separate from the actual Activity object so that we can
+ tightly control what stuff passes through the dbus python bindings."""
+
+ def start(self, pservice, activity):
+ self._activity = activity
+ self._pservice = pservice
+
+ @dbus.service.method(ACTIVITY_INTERFACE)
+ def share(self):
+ """Called by the shell to request the activity to share itself on the network."""
+ self._activity.share()
+
+ @dbus.service.method(ACTIVITY_INTERFACE)
+ def join(self, activity_ps_path):
+ """Join the activity specified by its presence service path"""
+ activity_ps = self._pservice.get(activity_ps_path)
+ return self._activity.join(activity_ps)
+
+ @dbus.service.method(ACTIVITY_INTERFACE)
+ def get_id(self):
+ """Get the activity identifier"""
+ return self._activity.get_id()
+
+ @dbus.service.method(ACTIVITY_INTERFACE)
+ def get_type(self):
+ """Get the activity type"""
+ return self._activity.get_type()
+
+ @dbus.service.method(ACTIVITY_INTERFACE)
+ def get_shared(self):
+ """Returns True if the activity is shared on the mesh."""
+ return self._activity.get_shared()
+
+ @dbus.service.method(ACTIVITY_INTERFACE,
+ in_signature="sas", out_signature="")
+ def execute(self, command, args):
+ self._activity.execute(command, args)
class Activity(gtk.Window):
- """Base Activity class that all other Activities derive from."""
-
- def __init__(self):
- gtk.Window.__init__(self)
-
- self.connect('destroy', self.__destroy_cb)
-
- self._shared = False
- self._activity_id = None
- self._default_type = None
- self._service = None
- self._pservice = PresenceService()
-
- self.present()
-
- group = gtk.Window()
- group.realize()
- self.window.set_group(group.window)
-
- bus = dbus.SessionBus()
- xid = self.window.xid
-
- bus_name = dbus.service.BusName(get_service_name(xid), bus=bus)
- self._bus = ActivityDbusService(bus_name, get_object_path(xid))
- self._bus.start(self._pservice, self)
-
- def set_type(self, activity_type):
- """Sets the activity type."""
- self._activity_type = activity_type
- self._default_type = activity.get_default_type(activity_type)
-
- def get_type(self):
- """Gets the activity type."""
- return self._activity_type
-
- def get_default_type(self):
- return self._default_type
-
- def get_shared(self):
- """Returns TRUE if the activity is shared on the mesh."""
- return self._shared
-
- def get_id(self):
- """Get the unique activity identifier."""
- if self._activity_id == None:
- self._activity_id = sugar.util.unique_id()
- return self._activity_id
-
- def join(self, activity_ps):
- """Join an activity shared on the network."""
- self._shared = True
- self._activity_id = activity_ps.get_id()
-
- # Publish the default service, it's a copy of
- # one of those we found on the network.
- services = activity_ps.get_services_of_type(self._default_type)
- if len(services) > 0:
- service = services[0]
- addr = service.get_address()
- port = service.get_port()
- properties = service.get_published_values()
- self._service = self._pservice.share_activity(
- self, self._default_type, properties, addr, port)
- else:
- logging.error('Cannot join the activity')
-
- def share(self):
- """Share the activity on the network."""
- logging.debug('Share activity %s on the network.' % self.get_id())
-
- self._service = self._pservice.share_activity(self, self._default_type)
- self._shared = True
-
- def execute(self, command, args):
- """Execute the given command with args"""
- pass
-
- def __destroy_cb(self, window):
- if self._bus:
- del self._bus
- self._bus = None
- if self._service:
- self._pservice.unregister_service(self._service)
+ """Base Activity class that all other Activities derive from."""
+
+ def __init__(self):
+ gtk.Window.__init__(self)
+
+ self.connect('destroy', self.__destroy_cb)
+
+ self._shared = False
+ self._activity_id = None
+ self._default_type = None
+ self._service = None
+ self._pservice = PresenceService()
+
+ self.present()
+
+ group = gtk.Window()
+ group.realize()
+ self.window.set_group(group.window)
+
+ bus = dbus.SessionBus()
+ xid = self.window.xid
+
+ bus_name = dbus.service.BusName(get_service_name(xid), bus=bus)
+ self._bus = ActivityDbusService(bus_name, get_object_path(xid))
+ self._bus.start(self._pservice, self)
+
+ def set_type(self, activity_type):
+ """Sets the activity type."""
+ self._activity_type = activity_type
+ self._default_type = activity.get_default_type(activity_type)
+
+ def get_type(self):
+ """Gets the activity type."""
+ return self._activity_type
+
+ def get_default_type(self):
+ return self._default_type
+
+ def get_shared(self):
+ """Returns TRUE if the activity is shared on the mesh."""
+ return self._shared
+
+ def get_id(self):
+ """Get the unique activity identifier."""
+ if self._activity_id == None:
+ self._activity_id = sugar.util.unique_id()
+ return self._activity_id
+
+ def join(self, activity_ps):
+ """Join an activity shared on the network."""
+ self._shared = True
+ self._activity_id = activity_ps.get_id()
+
+ # Publish the default service, it's a copy of
+ # one of those we found on the network.
+ services = activity_ps.get_services_of_type(self._default_type)
+ if len(services) > 0:
+ service = services[0]
+ addr = service.get_address()
+ port = service.get_port()
+ properties = service.get_published_values()
+ self._service = self._pservice.share_activity(
+ self, self._default_type, properties, addr, port)
+ else:
+ logging.error('Cannot join the activity')
+
+ def share(self):
+ """Share the activity on the network."""
+ logging.debug('Share activity %s on the network.' % self.get_id())
+
+ self._service = self._pservice.share_activity(self, self._default_type)
+ self._shared = True
+
+ def execute(self, command, args):
+ """Execute the given command with args"""
+ pass
+
+ def __destroy_cb(self, window):
+ if self._bus:
+ del self._bus
+ self._bus = None
+ if self._service:
+ self._pservice.unregister_service(self._service)
diff --git a/sugar/activity/ActivityFactory.py b/sugar/activity/ActivityFactory.py
index 66eba74..ee131ef 100644
--- a/sugar/activity/ActivityFactory.py
+++ b/sugar/activity/ActivityFactory.py
@@ -27,72 +27,72 @@ from sugar.presence.PresenceService import PresenceService
from sugar.activity import Activity
def get_path(activity_name):
- """Returns the activity path"""
- return '/' + activity_name.replace('.', '/')
+ """Returns the activity path"""
+ return '/' + activity_name.replace('.', '/')
class ActivityFactory(dbus.service.Object):
- """Dbus service that takes care of creating new instances of an activity"""
+ """Dbus service that takes care of creating new instances of an activity"""
- def __init__(self, activity_type, activity_class):
- self._activity_type = activity_type
- self._activities = []
+ def __init__(self, activity_type, activity_class):
+ self._activity_type = activity_type
+ self._activities = []
- splitted_module = activity_class.rsplit('.', 1)
- module_name = splitted_module[0]
- class_name = splitted_module[1]
+ splitted_module = activity_class.rsplit('.', 1)
+ module_name = splitted_module[0]
+ class_name = splitted_module[1]
- module = __import__(module_name)
- for comp in module_name.split('.')[1:]:
- module = getattr(module, comp)
- if hasattr(module, 'start'):
- module.start()
+ module = __import__(module_name)
+ for comp in module_name.split('.')[1:]:
+ module = getattr(module, comp)
+ if hasattr(module, 'start'):
+ module.start()
- self._module = module
- self._constructor = getattr(module, class_name)
-
- bus = dbus.SessionBus()
- factory = activity_type
- bus_name = dbus.service.BusName(factory, bus = bus)
- dbus.service.Object.__init__(self, bus_name, get_path(factory))
+ self._module = module
+ self._constructor = getattr(module, class_name)
+
+ bus = dbus.SessionBus()
+ factory = activity_type
+ bus_name = dbus.service.BusName(factory, bus = bus)
+ dbus.service.Object.__init__(self, bus_name, get_path(factory))
- @dbus.service.method("com.redhat.Sugar.ActivityFactory")
- def create(self):
- activity = self._constructor()
- activity.set_type(self._activity_type)
+ @dbus.service.method("com.redhat.Sugar.ActivityFactory")
+ def create(self):
+ activity = self._constructor()
+ activity.set_type(self._activity_type)
- self._activities.append(activity)
- activity.connect('destroy', self._activity_destroy_cb)
+ self._activities.append(activity)
+ activity.connect('destroy', self._activity_destroy_cb)
- return activity.window.xid
+ return activity.window.xid
- def _activity_destroy_cb(self, activity):
- self._activities.remove(activity)
+ def _activity_destroy_cb(self, activity):
+ self._activities.remove(activity)
- if hasattr(self._module, 'stop'):
- self._module.stop()
+ if hasattr(self._module, 'stop'):
+ self._module.stop()
- if len(self._activities) == 0:
- gtk.main_quit()
+ if len(self._activities) == 0:
+ gtk.main_quit()
def create(activity_name):
- """Create a new activity from his name."""
- bus = dbus.SessionBus()
+ """Create a new activity from his name."""
+ bus = dbus.SessionBus()
- factory_name = activity_name
- factory_path = get_path(factory_name)
+ factory_name = activity_name
+ factory_path = get_path(factory_name)
- proxy_obj = bus.get_object(factory_name, factory_path)
- factory = dbus.Interface(proxy_obj, "com.redhat.Sugar.ActivityFactory")
+ proxy_obj = bus.get_object(factory_name, factory_path)
+ factory = dbus.Interface(proxy_obj, "com.redhat.Sugar.ActivityFactory")
- xid = factory.create()
+ xid = factory.create()
- bus = dbus.SessionBus()
- proxy_obj = bus.get_object(Activity.get_service_name(xid),
- Activity.get_object_path(xid))
- activity = dbus.Interface(proxy_obj, Activity.ACTIVITY_INTERFACE)
+ bus = dbus.SessionBus()
+ proxy_obj = bus.get_object(Activity.get_service_name(xid),
+ Activity.get_object_path(xid))
+ activity = dbus.Interface(proxy_obj, Activity.ACTIVITY_INTERFACE)
- return activity
+ return activity
def register_factory(name, activity_class):
- """Register the activity factory."""
- factory = ActivityFactory(name, activity_class)
+ """Register the activity factory."""
+ factory = ActivityFactory(name, activity_class)
diff --git a/sugar/activity/__init__.py b/sugar/activity/__init__.py
index 959c0a1..1e606d5 100644
--- a/sugar/activity/__init__.py
+++ b/sugar/activity/__init__.py
@@ -9,10 +9,10 @@ sizes = 'gtk-large-toolbar=%d, %d' % (grid.dimension(1), grid.dimension(1))
settings.set_string_property('gtk-icon-sizes', sizes, '')
def get_default_type(activity_type):
- """Get the activity default type.
+ """Get the activity default type.
- It's the type of the main network service which tracks presence
+ It's the type of the main network service which tracks presence
and provides info about the activity, for example the title."""
- splitted_id = activity_type.split('.')
- splitted_id.reverse()
- return '_' + '_'.join(splitted_id) + '._udp'
+ splitted_id = activity_type.split('.')
+ splitted_id.reverse()
+ return '_' + '_'.join(splitted_id) + '._udp'
diff --git a/sugar/activity/bundle.py b/sugar/activity/bundle.py
index f9263a3..00d2d52 100644
--- a/sugar/activity/bundle.py
+++ b/sugar/activity/bundle.py
@@ -4,83 +4,83 @@ import os
from ConfigParser import ConfigParser
class Bundle:
- """Info about an activity bundle. Wraps the activity.info file."""
- def __init__(self, path):
- self._name = None
- self._icon = None
- self._service_name = None
- self._show_launcher = True
- self._valid = True
- self._path = path
- self._activity_version = 0
-
- info_path = os.path.join(path, 'activity', 'activity.info')
- if os.path.isfile(info_path):
- self._parse_info(info_path)
- else:
- self._valid = False
-
- def _parse_info(self, info_path):
- cp = ConfigParser()
- cp.read([info_path])
-
- section = 'Activity'
-
- if cp.has_option(section, 'service_name'):
- self._service_name = cp.get(section, 'service_name')
- else:
- self._valid = False
- logging.error('%s must specify a service name' % self._path)
-
- if cp.has_option(section, 'name'):
- self._name = cp.get(section, 'name')
- else:
- self._valid = False
- logging.error('%s must specify a name' % self._path)
-
- if cp.has_option(section, 'exec'):
- self._exec = cp.get(section, 'exec')
- else:
- self._valid = False
- logging.error('%s must specify an exec' % self._path)
-
- if cp.has_option(section, 'show_launcher'):
- if cp.get(section, 'show_launcher') == 'no':
- self._show_launcher = False
-
- if cp.has_option(section, 'icon'):
- self._icon = cp.get(section, 'icon')
-
- if cp.has_option(section, 'activity_version'):
- self._activity_version = int(cp.get(section, 'activity_version'))
-
- def is_valid(self):
- return self._valid
-
- def get_path(self):
- """Get the activity bundle path."""
- return self._path
-
- def get_name(self):
- """Get the activity user visible name."""
- return self._name
-
- def get_service_name(self):
- """Get the activity service name"""
- return self._service_name
-
- def get_icon(self):
- """Get the activity icon name"""
- return self._icon
-
- def get_activity_version(self):
- """Get the activity version"""
- return self._activity_version
-
- def get_exec(self):
- """Get the command to execute to launch the activity factory"""
- return self._exec
-
- def get_show_launcher(self):
- """Get whether there should be a visible launcher for the activity"""
- return self._show_launcher
+ """Info about an activity bundle. Wraps the activity.info file."""
+ def __init__(self, path):
+ self._name = None
+ self._icon = None
+ self._service_name = None
+ self._show_launcher = True
+ self._valid = True
+ self._path = path
+ self._activity_version = 0
+
+ info_path = os.path.join(path, 'activity', 'activity.info')
+ if os.path.isfile(info_path):
+ self._parse_info(info_path)
+ else:
+ self._valid = False
+
+ def _parse_info(self, info_path):
+ cp = ConfigParser()
+ cp.read([info_path])
+
+ section = 'Activity'
+
+ if cp.has_option(section, 'service_name'):
+ self._service_name = cp.get(section, 'service_name')
+ else:
+ self._valid = False
+ logging.error('%s must specify a service name' % self._path)
+
+ if cp.has_option(section, 'name'):
+ self._name = cp.get(section, 'name')
+ else:
+ self._valid = False
+ logging.error('%s must specify a name' % self._path)
+
+ if cp.has_option(section, 'exec'):
+ self._exec = cp.get(section, 'exec')
+ else:
+ self._valid = False
+ logging.error('%s must specify an exec' % self._path)
+
+ if cp.has_option(section, 'show_launcher'):
+ if cp.get(section, 'show_launcher') == 'no':
+ self._show_launcher = False
+
+ if cp.has_option(section, 'icon'):
+ self._icon = cp.get(section, 'icon')
+
+ if cp.has_option(section, 'activity_version'):
+ self._activity_version = int(cp.get(section, 'activity_version'))
+
+ def is_valid(self):
+ return self._valid
+
+ def get_path(self):
+ """Get the activity bundle path."""
+ return self._path
+
+ def get_name(self):
+ """Get the activity user visible name."""
+ return self._name
+
+ def get_service_name(self):
+ """Get the activity service name"""
+ return self._service_name
+
+ def get_icon(self):
+ """Get the activity icon name"""
+ return self._icon
+
+ def get_activity_version(self):
+ """Get the activity version"""
+ return self._activity_version
+
+ def get_exec(self):
+ """Get the command to execute to launch the activity factory"""
+ return self._exec
+
+ def get_show_launcher(self):
+ """Get whether there should be a visible launcher for the activity"""
+ return self._show_launcher
diff --git a/sugar/activity/bundlebuilder.py b/sugar/activity/bundlebuilder.py
index c313523..4ab4f7d 100644
--- a/sugar/activity/bundlebuilder.py
+++ b/sugar/activity/bundlebuilder.py
@@ -25,71 +25,71 @@ import shutil
from sugar.activity.bundle import Bundle
class _SvnFileList(list):
- def __init__(self):
- f = os.popen('svn list -R')
- for line in f.readlines():
- filename = line.strip()
- if os.path.isfile(filename):
- self.append(filename)
- f.close()
+ def __init__(self):
+ f = os.popen('svn list -R')
+ for line in f.readlines():
+ filename = line.strip()
+ if os.path.isfile(filename):
+ self.append(filename)
+ f.close()
class _GitFileList(list):
- def __init__(self):
- f = os.popen('git-ls-files')
- for line in f.readlines():
- filename = line.strip()
- if not filename.startswith('.'):
- self.append(filename)
- f.close()
+ def __init__(self):
+ f = os.popen('git-ls-files')
+ for line in f.readlines():
+ filename = line.strip()
+ if not filename.startswith('.'):
+ self.append(filename)
+ f.close()
def _extract_bundle(source_file, dest_dir):
- if not os.path.exists(dest_dir):
- os.mkdir(dest_dir)
+ if not os.path.exists(dest_dir):
+ os.mkdir(dest_dir)
- zf = zipfile.ZipFile(source_file)
+ zf = zipfile.ZipFile(source_file)
- for i, name in enumerate(zf.namelist()):
- path = os.path.join(dest_dir, name)
-
- if not os.path.exists(os.path.dirname(path)):
- os.makedirs(os.path.dirname(path))
+ for i, name in enumerate(zf.namelist()):
+ path = os.path.join(dest_dir, name)
+
+ if not os.path.exists(os.path.dirname(path)):
+ os.makedirs(os.path.dirname(path))
- outfile = open(path, 'wb')
- outfile.write(zf.read(name))
- outfile.flush()
- outfile.close()
+ outfile = open(path, 'wb')
+ outfile.write(zf.read(name))
+ outfile.flush()
+ outfile.close()
def _get_source_path():
- return os.getcwd()
+ return os.getcwd()
def _get_activities_path():
- path = os.path.expanduser('~/Activities')
- if not os.path.isdir(path):
- os.mkdir(path)
- return path
+ path = os.path.expanduser('~/Activities')
+ if not os.path.isdir(path):
+ os.mkdir(path)
+ return path
def _get_bundle_dir():
- bundle_name = os.path.basename(_get_source_path())
- return bundle_name + '.activity'
+ bundle_name = os.path.basename(_get_source_path())
+ return bundle_name + '.activity'
def _get_install_dir(prefix):
- return os.path.join(prefix, 'share/activities')
+ return os.path.join(prefix, 'share/activities')
def _get_bundle_path():
- return os.path.join(_get_activities_path(), _get_bundle_dir())
+ return os.path.join(_get_activities_path(), _get_bundle_dir())
def _get_package_name():
- bundle = Bundle(_get_source_path())
- zipname = '%s-%d.xo' % (bundle.get_name(), bundle.get_activity_version())
- return zipname
+ bundle = Bundle(_get_source_path())
+ zipname = '%s-%d.xo' % (bundle.get_name(), bundle.get_activity_version())
+ return zipname
def _delete_backups(arg, dirname, names):
- for name in names:
- if name.endswith('~') or name.endswith('pyc'):
- os.remove(os.path.join(dirname, name))
+ for name in names:
+ if name.endswith('~') or name.endswith('pyc'):
+ os.remove(os.path.join(dirname, name))
def cmd_help():
- print 'Usage: \n\
+ print 'Usage: \n\
setup.py dev - setup for development \n\
setup.py dist - create a bundle package \n\
setup.py install - install the bundle \n\
@@ -98,59 +98,59 @@ setup.py help - print this message \n\
'
def cmd_dev():
- bundle_path = get_bundle_path()
- try:
- os.symlink(_get_source_path(), bundle_path)
- except OSError:
- if os.path.islink(bundle_path):
- print 'ERROR - The bundle has been already setup for development.'
- else:
- print 'ERROR - A bundle with the same name is already installed.'
+ bundle_path = get_bundle_path()
+ try:
+ os.symlink(_get_source_path(), bundle_path)
+ except OSError:
+ if os.path.islink(bundle_path):
+ print 'ERROR - The bundle has been already setup for development.'
+ else:
+ print 'ERROR - A bundle with the same name is already installed.'
def cmd_dist():
- if os.path.isdir('.git'):
- file_list = _GitFileList()
- elif os.path.isdir('.svn'):
- file_list = _SvnFileList()
- else:
- print 'ERROR - The command works only with git or svn repositories.'
-
- zipname = _get_package_name()
- bundle_zip = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)
-
- for filename in file_list:
- arcname = os.path.join(_get_bundle_dir(), filename)
- bundle_zip.write(filename, arcname)
-
- bundle_zip.close()
+ if os.path.isdir('.git'):
+ file_list = _GitFileList()
+ elif os.path.isdir('.svn'):
+ file_list = _SvnFileList()
+ else:
+ print 'ERROR - The command works only with git or svn repositories.'
+
+ zipname = _get_package_name()
+ bundle_zip = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)
+
+ for filename in file_list:
+ arcname = os.path.join(_get_bundle_dir(), filename)
+ bundle_zip.write(filename, arcname)
+
+ bundle_zip.close()
def cmd_install(prefix):
- cmd_dist()
- cmd_uninstall(prefix)
- _extract_bundle(_get_package_name(), _get_install_dir(prefix))
+ cmd_dist()
+ cmd_uninstall(prefix)
+ _extract_bundle(_get_package_name(), _get_install_dir(prefix))
def cmd_uninstall(prefix):
- path = os.path.join(_get_install_dir(prefix), _get_bundle_dir())
- if os.path.isdir(path):
- shutil.rmtree(path)
+ path = os.path.join(_get_install_dir(prefix), _get_bundle_dir())
+ if os.path.isdir(path):
+ shutil.rmtree(path)
def cmd_clean():
- os.path.walk('.', delete_backups, None)
+ os.path.walk('.', delete_backups, None)
def start():
- if len(sys.argv) < 2:
- cmd_help()
- elif sys.argv[1] == 'build':
- pass
- elif sys.argv[1] == 'dev':
- cmd_dev()
- elif sys.argv[1] == 'dist':
- cmd_dist()
- elif sys.argv[1] == 'install' and len(sys.argv) == 3:
- cmd_install(sys.argv[2])
- elif sys.argv[1] == 'uninstall' and len(sys.argv) == 3:
- cmd_uninstall(sys.argv[2])
- elif sys.argv[1] == 'clean':
- cmd_clean()
- else:
- cmd_help()
+ if len(sys.argv) < 2:
+ cmd_help()
+ elif sys.argv[1] == 'build':
+ pass
+ elif sys.argv[1] == 'dev':
+ cmd_dev()
+ elif sys.argv[1] == 'dist':
+ cmd_dist()
+ elif sys.argv[1] == 'install' and len(sys.argv) == 3:
+ cmd_install(sys.argv[2])
+ elif sys.argv[1] == 'uninstall' and len(sys.argv) == 3:
+ cmd_uninstall(sys.argv[2])
+ elif sys.argv[1] == 'clean':
+ cmd_clean()
+ else:
+ cmd_help()
diff --git a/sugar/activity/bundleregistry.py b/sugar/activity/bundleregistry.py
index f9adbca..aa7d70a 100644
--- a/sugar/activity/bundleregistry.py
+++ b/sugar/activity/bundleregistry.py
@@ -6,51 +6,51 @@ from sugar import env
from sugar import util
class _ServiceManager(object):
- def __init__(self):
- self._path = env.get_user_service_dir()
+ def __init__(self):
+ self._path = env.get_user_service_dir()
- def add(self, bundle):
- name = bundle.get_service_name()
+ def add(self, bundle):
+ name = bundle.get_service_name()
- # FIXME evil hack. Probably need to fix Exec spec
- full_exec = env.get_shell_bin_dir() + '/' + bundle.get_exec()
- full_exec += ' ' + bundle.get_path()
+ # FIXME evil hack. Probably need to fix Exec spec
+ full_exec = env.get_shell_bin_dir() + '/' + bundle.get_exec()
+ full_exec += ' ' + bundle.get_path()
- util.write_service(name, full_exec, self._path)
+ util.write_service(name, full_exec, self._path)
class BundleRegistry:
- """Service that tracks the available activity bundles"""
-
- def __init__(self):
- self._bundles = {}
- self._search_path = []
- self._service_manager = _ServiceManager()
-
- def get_bundle(self, service_name):
- """Returns an bundle given his service name"""
- if self._bundles.has_key(service_name):
- return self._bundles[service_name]
- else:
- return None
-
- def add_search_path(self, path):
- """Add a directory to the bundles search path"""
- self._search_path.append(path)
- self._scan_directory(path)
-
- def __iter__(self):
- return self._bundles.values().__iter__()
-
- def _scan_directory(self, path):
- if os.path.isdir(path):
- for f in os.listdir(path):
- bundle_dir = os.path.join(path, f)
- if os.path.isdir(bundle_dir) and \
- bundle_dir.endswith('.activity'):
- self._add_bundle(bundle_dir)
-
- def _add_bundle(self, bundle_path):
- bundle = Bundle(bundle_path)
- if bundle.is_valid():
- self._bundles[bundle.get_service_name()] = bundle
- self._service_manager.add(bundle)
+ """Service that tracks the available activity bundles"""
+
+ def __init__(self):
+ self._bundles = {}
+ self._search_path = []
+ self._service_manager = _ServiceManager()
+
+ def get_bundle(self, service_name):
+ """Returns an bundle given his service name"""
+ if self._bundles.has_key(service_name):
+ return self._bundles[service_name]
+ else:
+ return None
+
+ def add_search_path(self, path):
+ """Add a directory to the bundles search path"""
+ self._search_path.append(path)
+ self._scan_directory(path)
+
+ def __iter__(self):
+ return self._bundles.values().__iter__()
+
+ def _scan_directory(self, path):
+ if os.path.isdir(path):
+ for f in os.listdir(path):
+ bundle_dir = os.path.join(path, f)
+ if os.path.isdir(bundle_dir) and \
+ bundle_dir.endswith('.activity'):
+ self._add_bundle(bundle_dir)
+
+ def _add_bundle(self, bundle_path):
+ bundle = Bundle(bundle_path)
+ if bundle.is_valid():
+ self._bundles[bundle.get_service_name()] = bundle
+ self._service_manager.add(bundle)
diff --git a/sugar/chat/ActivityChat.py b/sugar/chat/ActivityChat.py
index 1892672..ecba9af 100644
--- a/sugar/chat/ActivityChat.py
+++ b/sugar/chat/ActivityChat.py
@@ -20,48 +20,48 @@ import logging
from sugar.chat.GroupChat import GroupChat
class ActivityChat(GroupChat):
- SERVICE_TYPE = "_olpc_activity_chat._udp"
+ SERVICE_TYPE = "_olpc_activity_chat._udp"
- def __init__(self, activity):
- GroupChat.__init__(self)
- self._chat_service = None
+ def __init__(self, activity):
+ GroupChat.__init__(self)
+ self._chat_service = None
- self.connect('destroy', self._destroy_cb)
+ self.connect('destroy', self._destroy_cb)
- self._activity = activity
- self._pservice.register_service_type(ActivityChat.SERVICE_TYPE)
- self._pservice.connect('service-appeared', self._service_appeared_cb)
+ self._activity = activity
+ self._pservice.register_service_type(ActivityChat.SERVICE_TYPE)
+ self._pservice.connect('service-appeared', self._service_appeared_cb)
- # Find an existing activity chat to latch onto
- ps_activity = self._pservice.get_activity(activity.get_id())
- if ps_activity is not None:
- services = ps_activity.get_services_of_type(ActivityChat.SERVICE_TYPE)
- if len(services) > 0:
- self._service_appeared_cb(self._pservice, services[0])
+ # Find an existing activity chat to latch onto
+ ps_activity = self._pservice.get_activity(activity.get_id())
+ if ps_activity is not None:
+ services = ps_activity.get_services_of_type(ActivityChat.SERVICE_TYPE)
+ if len(services) > 0:
+ self._service_appeared_cb(self._pservice, services[0])
- def _service_appeared_cb(self, pservice, service):
- if service.get_activity_id() != self._activity.get_id():
- return
- if service.get_type() != ActivityChat.SERVICE_TYPE:
- return
- if self._chat_service:
- return
+ def _service_appeared_cb(self, pservice, service):
+ if service.get_activity_id() != self._activity.get_id():
+ return
+ if service.get_type() != ActivityChat.SERVICE_TYPE:
+ return
+ if self._chat_service:
+ return
- logging.debug('Activity chat service appeared, setup the stream.')
- # Ok, there's an existing chat service that we copy
- # parameters and such from
- addr = service.get_address()
- port = service.get_port()
- self._chat_service = self._pservice.share_activity(self._activity,
- stype=ActivityChat.SERVICE_TYPE, address=addr, port=port)
- self._setup_stream(self._chat_service)
+ logging.debug('Activity chat service appeared, setup the stream.')
+ # Ok, there's an existing chat service that we copy
+ # parameters and such from
+ addr = service.get_address()
+ port = service.get_port()
+ self._chat_service = self._pservice.share_activity(self._activity,
+ stype=ActivityChat.SERVICE_TYPE, address=addr, port=port)
+ self._setup_stream(self._chat_service)
- def share(self):
- """Only called when we share the activity this chat is tied to."""
- self._chat_service = self._pservice.share_activity(self._activity,
- stype=ActivityChat.SERVICE_TYPE)
- self._setup_stream(self._chat_service)
+ def share(self):
+ """Only called when we share the activity this chat is tied to."""
+ self._chat_service = self._pservice.share_activity(self._activity,
+ stype=ActivityChat.SERVICE_TYPE)
+ self._setup_stream(self._chat_service)
- def _destroy_cb(self, widget):
- if self._chat_service:
- self._pservice.unregister_service(self._chat_service)
+ def _destroy_cb(self, widget):
+ if self._chat_service:
+ self._pservice.unregister_service(self._chat_service)
diff --git a/sugar/chat/Chat.py b/sugar/chat/Chat.py
index eb1b4da..aae6450 100644
--- a/sugar/chat/Chat.py
+++ b/sugar/chat/Chat.py
@@ -37,244 +37,244 @@ import richtext
PANGO_SCALE = 1024 # Where is this defined?
class Chat(gtk.VBox):
- SERVICE_TYPE = "_olpc_chat._tcp"
- SERVICE_PORT = 6100
-
- TEXT_MODE = 0
- SKETCH_MODE = 1
-
- def __init__(self):
- gtk.VBox.__init__(self, False, 6)
-
- self._pservice = PresenceService.get_instance()
-
- self._stream_writer = None
- self.set_border_width(12)
-
- chat_vbox = gtk.VBox()
- chat_vbox.set_spacing(6)
-
- self._chat_sw = gtk.ScrolledWindow()
- self._chat_sw.set_shadow_type(gtk.SHADOW_IN)
- self._chat_sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
- self._chat_view = richtext.RichTextView()
- self._chat_view.connect("link-clicked", self.__link_clicked_cb)
- self._chat_view.set_editable(False)
- self._chat_view.set_cursor_visible(False)
- self._chat_view.set_pixels_above_lines(7)
- self._chat_view.set_left_margin(5)
- self._chat_sw.add(self._chat_view)
- self._chat_view.show()
- chat_vbox.pack_start(self._chat_sw)
- self._chat_sw.show()
-
- self.pack_start(chat_vbox)
- chat_vbox.show()
-
- self._mode = Chat.TEXT_MODE
- self._editor = ChatEditor(self, ChatEditor.TEXT_MODE)
-
- toolbar = ChatToolbar(self._editor)
- self.pack_start(toolbar, False)
- toolbar.show()
-
- self.pack_start(self._editor, False)
- self._editor.show()
-
- self.connect("key-press-event", self.__key_press_event_cb)
-
- def __key_press_event_cb(self, window, event):
- if event.keyval == gtk.keysyms.s and \
- event.state & gtk.gdk.CONTROL_MASK:
- if self.get_mode() == Chat.SKETCH_MODE:
- self.set_mode(Chat.TEXT_MODE)
- elif self.get_mode() == Chat.TEXT_MODE:
- self.set_mode(Chat.SKETCH_MODE)
-
- def get_mode(self):
- return self._mode
-
- def set_mode(self, mode):
- self._mode = mode
- if self._mode == Chat.TEXT_MODE:
- self._editor.set_mode(ChatEditor.TEXT_MODE)
- elif self._mode == Chat.SKETCH_MODE:
- self._editor.set_mode(ChatEditor.SKETCH_MODE)
-
- def __get_browser_shell(self):
- bus = dbus.SessionBus()
- proxy_obj = bus.get_object('com.redhat.Sugar.Browser', '/com/redhat/Sugar/Browser')
- self._browser_shell = dbus.Interface(proxy_obj, 'com.redhat.Sugar.BrowserShell')
-
- def __link_clicked_cb(self, view, address):
- self.__get_browser_shell().open_browser(address)
-
- def _scroll_chat_view_to_bottom(self):
- # Only scroll to bottom if the view is already close to the bottom
- vadj = self._chat_sw.get_vadjustment()
- if vadj.value + vadj.page_size > vadj.upper * 0.8:
- vadj.value = vadj.upper - vadj.page_size
- self._chat_sw.set_vadjustment(vadj)
-
- def _message_inserted(self):
- gobject.idle_add(self._scroll_chat_view_to_bottom)
-
- def _insert_buddy(self, buf, buddy):
- # Stuff in the buddy icon, if we have one for this buddy
- icon = buddy.get_icon_pixbuf()
- if icon:
- rise = int(icon.get_height() / 4) * -1
-
- hash_string = "%s-%s" % (buddy.get_name(), buddy.get_ip4_address())
- sha_hash = sha.new()
- sha_hash.update(hash_string)
- tagname = "buddyicon-%s" % sha_hash.hexdigest()
-
- if not buf.get_tag_table().lookup(tagname):
- buf.create_tag(tagname, rise=(rise * PANGO_SCALE))
-
- aniter = buf.get_end_iter()
- buf.insert_pixbuf(aniter, icon)
- aniter.backward_char()
- enditer = buf.get_end_iter()
- buf.apply_tag_by_name(tagname, aniter, enditer)
-
- # Stick in the buddy's nickname
- if not buf.get_tag_table().lookup("nickname"):
- buf.create_tag("nickname", weight=pango.WEIGHT_BOLD)
- aniter = buf.get_end_iter()
- offset = aniter.get_offset()
- buf.insert(aniter, " " + buddy.get_name() + ": ")
- enditer = buf.get_iter_at_offset(offset)
- buf.apply_tag_by_name("nickname", aniter, enditer)
-
- def _insert_rich_message(self, buddy, msg):
- msg = Emoticons.get_instance().replace(msg)
-
- buf = self._chat_view.get_buffer()
- self._insert_buddy(buf, buddy)
-
- serializer = richtext.RichTextSerializer()
- serializer.deserialize(msg, buf)
- aniter = buf.get_end_iter()
- buf.insert(aniter, "\n")
-
- self._message_inserted()
-
- def _insert_sketch(self, buddy, svgdata):
- """Insert a sketch object into the chat buffer."""
- pbl = gtk.gdk.PixbufLoader("svg")
- pbl.write(svgdata)
- pbl.close()
- pbuf = pbl.get_pixbuf()
-
- buf = self._chat_view.get_buffer()
-
- self._insert_buddy(buf, buddy)
-
- rise = int(pbuf.get_height() / 3) * -1
- sha_hash = sha.new()
- sha_hash.update(svgdata)
- tagname = "sketch-%s" % sha_hash.hexdigest()
- if not buf.get_tag_table().lookup(tagname):
- buf.create_tag(tagname, rise=(rise * PANGO_SCALE))
-
- aniter = buf.get_end_iter()
- buf.insert_pixbuf(aniter, pbuf)
- aniter.backward_char()
- enditer = buf.get_end_iter()
- buf.apply_tag_by_name(tagname, aniter, enditer)
- aniter = buf.get_end_iter()
- buf.insert(aniter, "\n")
-
- self._message_inserted()
-
- def _get_first_richtext_chunk(self, msg):
- """Scan the message for the first richtext-tagged chunk and return it."""
- rt_last = -1
- tag_rt_start = "<richtext>"
- tag_rt_end = "</richtext>"
- rt_first = msg.find(tag_rt_start)
- length = -1
- if rt_first >= 0:
- length = len(msg)
- rt_last = msg.find(tag_rt_end, rt_first)
- if rt_first >= 0 and rt_last >= (rt_first + len(tag_rt_start)) and length > 0:
- return msg[rt_first:rt_last + len(tag_rt_end)]
- return None
-
- def _get_first_sketch_chunk(self, msg):
- """Scan the message for the first SVG-tagged chunk and return it."""
- svg_last = -1
- tag_svg_start = "<svg"
- tag_svg_end = "</svg>"
- desc_start = msg.find("<?xml version='1.0' encoding='UTF-8'?>")
- if desc_start < 0:
- return None
- ignore = msg.find("<!DOCTYPE svg")
- if ignore < 0:
- return None
- svg_first = msg.find(tag_svg_start)
- length = -1
- if svg_first >= 0:
- length = len(msg)
- svg_last = msg.find(tag_svg_end, svg_first)
- if svg_first >= 0 and svg_last >= (svg_first + len(tag_svg_start)) and length > 0:
- return msg[desc_start:svg_last + len(tag_svg_end)]
- return None
-
- def recv_message(self, message):
- """Insert a remote chat message into the chat buffer."""
- [nick, msg] = Chat.deserialize_message(message)
- buddy = self._pservice.get_buddy_by_name(nick)
- if not buddy:
- logging.error('The buddy %s is not present.' % (nick))
- return
-
- # FIXME a better way to compare buddies?
- owner = self._pservice.get_owner()
- if buddy.get_name() == owner.get_name():
- return
-
- chunk = self._get_first_richtext_chunk(msg)
- if chunk:
- self._insert_rich_message(buddy, chunk)
- return
-
- chunk = self._get_first_sketch_chunk(msg)
- if chunk:
- self._insert_sketch(buddy, chunk)
- return
-
- def set_stream_writer(self, stream_writer):
- self._stream_writer = stream_writer
-
- def send_sketch(self, svgdata):
- if not svgdata or not len(svgdata):
- return
- if self._stream_writer:
- self._stream_writer.write(self.serialize_message(svgdata))
- owner = self._pservice.get_owner()
- if owner:
- self._insert_sketch(owner, svgdata)
-
- def send_text_message(self, text):
- """Send a chat message and insert it into the local buffer."""
- if len(text) <= 0:
- return
- if self._stream_writer:
- self._stream_writer.write(self.serialize_message(text))
- else:
- logging.warning("Cannot send message, there is no stream writer")
- owner = self._pservice.get_owner()
- if owner:
- self._insert_rich_message(owner, text)
-
- def serialize_message(self, message):
- owner = self._pservice.get_owner()
- return owner.get_name() + '||' + message
-
- def deserialize_message(message):
- return message.split('||', 1)
-
- deserialize_message = staticmethod(deserialize_message)
+ SERVICE_TYPE = "_olpc_chat._tcp"
+ SERVICE_PORT = 6100
+
+ TEXT_MODE = 0
+ SKETCH_MODE = 1
+
+ def __init__(self):
+ gtk.VBox.__init__(self, False, 6)
+
+ self._pservice = PresenceService.get_instance()
+
+ self._stream_writer = None
+ self.set_border_width(12)
+
+ chat_vbox = gtk.VBox()
+ chat_vbox.set_spacing(6)
+
+ self._chat_sw = gtk.ScrolledWindow()
+ self._chat_sw.set_shadow_type(gtk.SHADOW_IN)
+ self._chat_sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS)
+ self._chat_view = richtext.RichTextView()
+ self._chat_view.connect("link-clicked", self.__link_clicked_cb)
+ self._chat_view.set_editable(False)
+ self._chat_view.set_cursor_visible(False)
+ self._chat_view.set_pixels_above_lines(7)
+ self._chat_view.set_left_margin(5)
+ self._chat_sw.add(self._chat_view)
+ self._chat_view.show()
+ chat_vbox.pack_start(self._chat_sw)
+ self._chat_sw.show()
+
+ self.pack_start(chat_vbox)
+ chat_vbox.show()
+
+ self._mode = Chat.TEXT_MODE
+ self._editor = ChatEditor(self, ChatEditor.TEXT_MODE)
+
+ toolbar = ChatToolbar(self._editor)
+ self.pack_start(toolbar, False)
+ toolbar.show()
+
+ self.pack_start(self._editor, False)
+ self._editor.show()
+
+ self.connect("key-press-event", self.__key_press_event_cb)
+
+ def __key_press_event_cb(self, window, event):
+ if event.keyval == gtk.keysyms.s and \
+ event.state & gtk.gdk.CONTROL_MASK:
+ if self.get_mode() == Chat.SKETCH_MODE:
+ self.set_mode(Chat.TEXT_MODE)
+ elif self.get_mode() == Chat.TEXT_MODE:
+ self.set_mode(Chat.SKETCH_MODE)
+
+ def get_mode(self):
+ return self._mode
+
+ def set_mode(self, mode):
+ self._mode = mode
+ if self._mode == Chat.TEXT_MODE:
+ self._editor.set_mode(ChatEditor.TEXT_MODE)
+ elif self._mode == Chat.SKETCH_MODE:
+ self._editor.set_mode(ChatEditor.SKETCH_MODE)
+
+ def __get_browser_shell(self):
+ bus = dbus.SessionBus()
+ proxy_obj = bus.get_object('com.redhat.Sugar.Browser', '/com/redhat/Sugar/Browser')
+ self._browser_shell = dbus.Interface(proxy_obj, 'com.redhat.Sugar.BrowserShell')
+
+ def __link_clicked_cb(self, view, address):
+ self.__get_browser_shell().open_browser(address)
+
+ def _scroll_chat_view_to_bottom(self):
+ # Only scroll to bottom if the view is already close to the bottom
+ vadj = self._chat_sw.get_vadjustment()
+ if vadj.value + vadj.page_size > vadj.upper * 0.8:
+ vadj.value = vadj.upper - vadj.page_size
+ self._chat_sw.set_vadjustment(vadj)
+
+ def _message_inserted(self):
+ gobject.idle_add(self._scroll_chat_view_to_bottom)
+
+ def _insert_buddy(self, buf, buddy):
+ # Stuff in the buddy icon, if we have one for this buddy
+ icon = buddy.get_icon_pixbuf()
+ if icon:
+ rise = int(icon.get_height() / 4) * -1
+
+ hash_string = "%s-%s" % (buddy.get_name(), buddy.get_ip4_address())
+ sha_hash = sha.new()
+ sha_hash.update(hash_string)
+ tagname = "buddyicon-%s" % sha_hash.hexdigest()
+
+ if not buf.get_tag_table().lookup(tagname):
+ buf.create_tag(tagname, rise=(rise * PANGO_SCALE))
+
+ aniter = buf.get_end_iter()
+ buf.insert_pixbuf(aniter, icon)
+ aniter.backward_char()
+ enditer = buf.get_end_iter()
+ buf.apply_tag_by_name(tagname, aniter, enditer)
+
+ # Stick in the buddy's nickname
+ if not buf.get_tag_table().lookup("nickname"):
+ buf.create_tag("nickname", weight=pango.WEIGHT_BOLD)
+ aniter = buf.get_end_iter()
+ offset = aniter.get_offset()
+ buf.insert(aniter, " " + buddy.get_name() + ": ")
+ enditer = buf.get_iter_at_offset(offset)
+ buf.apply_tag_by_name("nickname", aniter, enditer)
+
+ def _insert_rich_message(self, buddy, msg):
+ msg = Emoticons.get_instance().replace(msg)
+
+ buf = self._chat_view.get_buffer()
+ self._insert_buddy(buf, buddy)
+
+ serializer = richtext.RichTextSerializer()
+ serializer.deserialize(msg, buf)
+ aniter = buf.get_end_iter()
+ buf.insert(aniter, "\n")
+
+ self._message_inserted()
+
+ def _insert_sketch(self, buddy, svgdata):
+ """Insert a sketch object into the chat buffer."""
+ pbl = gtk.gdk.PixbufLoader("svg")
+ pbl.write(svgdata)
+ pbl.close()
+ pbuf = pbl.get_pixbuf()
+
+ buf = self._chat_view.get_buffer()
+
+ self._insert_buddy(buf, buddy)
+
+ rise = int(pbuf.get_height() / 3) * -1
+ sha_hash = sha.new()
+ sha_hash.update(svgdata)
+ tagname = "sketch-%s" % sha_hash.hexdigest()
+ if not buf.get_tag_table().lookup(tagname):
+ buf.create_tag(tagname, rise=(rise * PANGO_SCALE))
+
+ aniter = buf.get_end_iter()
+ buf.insert_pixbuf(aniter, pbuf)
+ aniter.backward_char()
+ enditer = buf.get_end_iter()
+ buf.apply_tag_by_name(tagname, aniter, enditer)
+ aniter = buf.get_end_iter()
+ buf.insert(aniter, "\n")
+
+ self._message_inserted()
+
+ def _get_first_richtext_chunk(self, msg):
+ """Scan the message for the first richtext-tagged chunk and return it."""
+ rt_last = -1
+ tag_rt_start = "<richtext>"
+ tag_rt_end = "</richtext>"
+ rt_first = msg.find(tag_rt_start)
+ length = -1
+ if rt_first >= 0:
+ length = len(msg)
+ rt_last = msg.find(tag_rt_end, rt_first)
+ if rt_first >= 0 and rt_last >= (rt_first + len(tag_rt_start)) and length > 0:
+ return msg[rt_first:rt_last + len(tag_rt_end)]
+ return None
+
+ def _get_first_sketch_chunk(self, msg):
+ """Scan the message for the first SVG-tagged chunk and return it."""
+ svg_last = -1
+ tag_svg_start = "<svg"
+ tag_svg_end = "</svg>"
+ desc_start = msg.find("<?xml version='1.0' encoding='UTF-8'?>")
+ if desc_start < 0:
+ return None
+ ignore = msg.find("<!DOCTYPE svg")
+ if ignore < 0:
+ return None
+ svg_first = msg.find(tag_svg_start)
+ length = -1
+ if svg_first >= 0:
+ length = len(msg)
+ svg_last = msg.find(tag_svg_end, svg_first)
+ if svg_first >= 0 and svg_last >= (svg_first + len(tag_svg_start)) and length > 0:
+ return msg[desc_start:svg_last + len(tag_svg_end)]
+ return None
+
+ def recv_message(self, message):
+ """Insert a remote chat message into the chat buffer."""
+ [nick, msg] = Chat.deserialize_message(message)
+ buddy = self._pservice.get_buddy_by_name(nick)
+ if not buddy:
+ logging.error('The buddy %s is not present.' % (nick))
+ return
+
+ # FIXME a better way to compare buddies?
+ owner = self._pservice.get_owner()
+ if buddy.get_name() == owner.get_name():
+ return
+
+ chunk = self._get_first_richtext_chunk(msg)
+ if chunk:
+ self._insert_rich_message(buddy, chunk)
+ return
+
+ chunk = self._get_first_sketch_chunk(msg)
+ if chunk:
+ self._insert_sketch(buddy, chunk)
+ return
+
+ def set_stream_writer(self, stream_writer):
+ self._stream_writer = stream_writer
+
+ def send_sketch(self, svgdata):
+ if not svgdata or not len(svgdata):
+ return
+ if self._stream_writer:
+ self._stream_writer.write(self.serialize_message(svgdata))
+ owner = self._pservice.get_owner()
+ if owner:
+ self._insert_sketch(owner, svgdata)
+
+ def send_text_message(self, text):
+ """Send a chat message and insert it into the local buffer."""
+ if len(text) <= 0:
+ return
+ if self._stream_writer:
+ self._stream_writer.write(self.serialize_message(text))
+ else:
+ logging.warning("Cannot send message, there is no stream writer")
+ owner = self._pservice.get_owner()
+ if owner:
+ self._insert_rich_message(owner, text)
+
+ def serialize_message(self, message):
+ owner = self._pservice.get_owner()
+ return owner.get_name() + '||' + message
+
+ def deserialize_message(message):
+ return message.split('||', 1)
+
+ deserialize_message = staticmethod(deserialize_message)
diff --git a/sugar/chat/ChatEditor.py b/sugar/chat/ChatEditor.py
index 4ee16ce..ee36688 100644
--- a/sugar/chat/ChatEditor.py
+++ b/sugar/chat/ChatEditor.py
@@ -22,83 +22,83 @@ from sugar.chat.sketchpad.SketchPad import SketchPad
import richtext
class ChatEditor(gtk.HBox):
- TEXT_MODE = 0
- SKETCH_MODE = 1
+ TEXT_MODE = 0
+ SKETCH_MODE = 1
- def __init__(self, chat, mode):
- gtk.HBox.__init__(self, False, 6)
+ def __init__(self, chat, mode):
+ gtk.HBox.__init__(self, False, 6)
- self._chat = chat
+ self._chat = chat
- self._notebook = gtk.Notebook()
- self._notebook.set_show_tabs(False)
- self._notebook.set_show_border(False)
- self._notebook.set_size_request(-1, 70)
-
- chat_view_sw = gtk.ScrolledWindow()
- chat_view_sw.set_shadow_type(gtk.SHADOW_IN)
- chat_view_sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- self._text_view = richtext.RichTextView()
- self._text_view.connect("key-press-event", self.__key_press_event_cb)
- chat_view_sw.add(self._text_view)
- self._text_view.show()
-
- self._notebook.append_page(chat_view_sw)
- chat_view_sw.show()
-
- self._sketchpad = SketchPad()
- self._notebook.append_page(self._sketchpad)
- self._sketchpad.show()
-
- self.pack_start(self._notebook)
- self._notebook.show()
-
- send_button = gtk.Button(_("Send"))
- send_button.set_size_request(60, -1)
- send_button.connect('clicked', self.__send_button_clicked_cb)
- self.pack_start(send_button, False, True)
- send_button.show()
-
- self.set_mode(mode)
+ self._notebook = gtk.Notebook()
+ self._notebook.set_show_tabs(False)
+ self._notebook.set_show_border(False)
+ self._notebook.set_size_request(-1, 70)
+
+ chat_view_sw = gtk.ScrolledWindow()
+ chat_view_sw.set_shadow_type(gtk.SHADOW_IN)
+ chat_view_sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ self._text_view = richtext.RichTextView()
+ self._text_view.connect("key-press-event", self.__key_press_event_cb)
+ chat_view_sw.add(self._text_view)
+ self._text_view.show()
+
+ self._notebook.append_page(chat_view_sw)
+ chat_view_sw.show()
+
+ self._sketchpad = SketchPad()
+ self._notebook.append_page(self._sketchpad)
+ self._sketchpad.show()
+
+ self.pack_start(self._notebook)
+ self._notebook.show()
+
+ send_button = gtk.Button(_("Send"))
+ send_button.set_size_request(60, -1)
+ send_button.connect('clicked', self.__send_button_clicked_cb)
+ self.pack_start(send_button, False, True)
+ send_button.show()
+
+ self.set_mode(mode)
- def set_color(self, color):
- self._sketchpad.set_color(color)
-
- def get_buffer(self):
- return self._text_view.get_buffer()
+ def set_color(self, color):
+ self._sketchpad.set_color(color)
+
+ def get_buffer(self):
+ return self._text_view.get_buffer()
- def set_mode(self, mode):
- self._mode = mode
- if self._mode == ChatEditor.SKETCH_MODE:
- self._notebook.set_current_page(1)
- elif self._mode == ChatEditor.TEXT_MODE:
- self._notebook.set_current_page(0)
+ def set_mode(self, mode):
+ self._mode = mode
+ if self._mode == ChatEditor.SKETCH_MODE:
+ self._notebook.set_current_page(1)
+ elif self._mode == ChatEditor.TEXT_MODE:
+ self._notebook.set_current_page(0)
- def __send_button_clicked_cb(self, button):
- self._send()
+ def __send_button_clicked_cb(self, button):
+ self._send()
- def _send(self):
- if self._mode == ChatEditor.SKETCH_MODE:
- self._send_sketch()
- elif self._mode == ChatEditor.TEXT_MODE:
- self._send_text()
+ def _send(self):
+ if self._mode == ChatEditor.SKETCH_MODE:
+ self._send_sketch()
+ elif self._mode == ChatEditor.TEXT_MODE:
+ self._send_text()
- def _send_sketch(self):
- self._chat.send_sketch(self._sketchpad.to_svg())
- self._sketchpad.clear()
+ def _send_sketch(self):
+ self._chat.send_sketch(self._sketchpad.to_svg())
+ self._sketchpad.clear()
- def _send_text(self):
- buf = self._text_view.get_buffer()
- text = buf.get_text(buf.get_start_iter(), buf.get_end_iter())
- if len(text.strip()) > 0:
- serializer = richtext.RichTextSerializer()
- text = serializer.serialize(buf)
- self._chat.send_text_message(text)
+ def _send_text(self):
+ buf = self._text_view.get_buffer()
+ text = buf.get_text(buf.get_start_iter(), buf.get_end_iter())
+ if len(text.strip()) > 0:
+ serializer = richtext.RichTextSerializer()
+ text = serializer.serialize(buf)
+ self._chat.send_text_message(text)
- buf.set_text("")
- buf.place_cursor(buf.get_start_iter())
-
- def __key_press_event_cb(self, text_view, event):
- if event.keyval == gtk.keysyms.Return:
- self._send()
- return True
+ buf.set_text("")
+ buf.place_cursor(buf.get_start_iter())
+
+ def __key_press_event_cb(self, text_view, event):
+ if event.keyval == gtk.keysyms.Return:
+ self._send()
+ return True
diff --git a/sugar/chat/ChatToolbar.py b/sugar/chat/ChatToolbar.py
index 8e88a68..d633138 100644
--- a/sugar/chat/ChatToolbar.py
+++ b/sugar/chat/ChatToolbar.py
@@ -22,129 +22,129 @@ from sugar.chat.sketchpad.Toolbox import Toolbox
import richtext
class ChatToolbar(gtk.HBox):
- def __init__(self, editor):
- gtk.HBox.__init__(self, False, 24)
-
- self._editor = editor
- self._emt_popup = None
-
- spring = gtk.Label('')
- self.pack_start(spring, True)
- spring.show()
-
- toolbox = richtext.RichTextToolbox(editor.get_buffer())
- self.pack_start(toolbox, False)
- toolbox.show()
-
- item = gtk.Button()
- item.unset_flags(gtk.CAN_FOCUS)
-
- e_hbox = gtk.HBox(False, 6)
-
- e_image = gtk.Image()
- e_image.set_from_icon_name('stock_smiley-1', gtk.ICON_SIZE_SMALL_TOOLBAR)
- e_hbox.pack_start(e_image)
- e_image.show()
-
- arrow = gtk.Arrow(gtk.ARROW_DOWN, gtk.SHADOW_NONE)
- e_hbox.pack_start(arrow)
- arrow.show()
-
- item.set_image(e_hbox)
- item.connect("clicked", self.__emoticons_button_clicked_cb)
- toolbox.pack_start(item, False)
- item.show()
-
-# separator = gtk.SeparatorToolItem()
-# toolbar.insert(separator, -1)
-# separator.show()
-
-# item = gtk.MenuToolButton(None, "Links")
-# item.set_menu(gtk.Menu())
-# item.connect("show-menu", self.__show_link_menu_cb)
-# toolbar.insert(item, -1)
-# item.show()
-
- toolbox = Toolbox()
- toolbox.connect('color-selected', self._color_selected)
- self.pack_start(toolbox, False)
- toolbox.show()
-
- spring = gtk.Label('')
- self.pack_start(spring, True)
- spring.show()
-
- def _color_selected(self, toolbox, color):
- self._editor.set_color(color)
-
- def __link_activate_cb(self, item, link):
- buf = self._editor.get_buffer()
- buf.append_link(link['title'], link['address'])
-
- def __show_link_menu_cb(self, button):
- menu = gtk.Menu()
-
- links = self.__get_browser_shell().get_links()
-
- for link in links:
- item = gtk.MenuItem(link['title'], False)
- item.connect("activate", self.__link_activate_cb, link)
- menu.append(item)
- item.show()
-
- button.set_menu(menu)
-
- def _create_emoticons_popup(self):
- model = gtk.ListStore(gtk.gdk.Pixbuf, str)
-
- for name in Emoticons.get_instance().get_all():
- icon_theme = gtk.icon_theme_get_default()
- try:
- pixbuf = icon_theme.load_icon(name, 16, 0)
- model.append([pixbuf, name])
- except gobject.GError:
- pass
-
- icon_view = gtk.IconView(model)
- icon_view.connect('selection-changed', self.__emoticon_selection_changed_cb)
- icon_view.set_pixbuf_column(0)
- icon_view.set_selection_mode(gtk.SELECTION_SINGLE)
-
- frame = gtk.Frame()
- frame.set_shadow_type(gtk.SHADOW_ETCHED_IN)
- frame.add(icon_view)
- icon_view.show()
-
- window = gtk.Window(gtk.WINDOW_POPUP)
- window.add(frame)
- frame.show()
-
- return window
-
- def __emoticon_selection_changed_cb(self, icon_view):
- items = icon_view.get_selected_items()
- if items:
- model = icon_view.get_model()
- icon_name = model[items[0]][1]
- self._editor.get_buffer().append_icon(icon_name)
- self._emt_popup.hide()
-
- def __emoticons_button_clicked_cb(self, button):
- # FIXME grabs...
- if not self._emt_popup:
- self._emt_popup = self._create_emoticons_popup()
-
- if self._emt_popup.get_property('visible'):
- self._emt_popup.hide()
- else:
- width = 180
- height = 130
-
- self._emt_popup.set_default_size(width, height)
-
- [x, y] = button.window.get_origin()
- x += button.allocation.x
- y += button.allocation.y - height
- self._emt_popup.move(x, y)
-
- self._emt_popup.show()
+ def __init__(self, editor):
+ gtk.HBox.__init__(self, False, 24)
+
+ self._editor = editor
+ self._emt_popup = None
+
+ spring = gtk.Label('')
+ self.pack_start(spring, True)
+ spring.show()
+
+ toolbox = richtext.RichTextToolbox(editor.get_buffer())
+ self.pack_start(toolbox, False)
+ toolbox.show()
+
+ item = gtk.Button()
+ item.unset_flags(gtk.CAN_FOCUS)
+
+ e_hbox = gtk.HBox(False, 6)
+
+ e_image = gtk.Image()
+ e_image.set_from_icon_name('stock_smiley-1', gtk.ICON_SIZE_SMALL_TOOLBAR)
+ e_hbox.pack_start(e_image)
+ e_image.show()
+
+ arrow = gtk.Arrow(gtk.ARROW_DOWN, gtk.SHADOW_NONE)
+ e_hbox.pack_start(arrow)
+ arrow.show()
+
+ item.set_image(e_hbox)
+ item.connect("clicked", self.__emoticons_button_clicked_cb)
+ toolbox.pack_start(item, False)
+ item.show()
+
+# separator = gtk.SeparatorToolItem()
+# toolbar.insert(separator, -1)
+# separator.show()
+
+# item = gtk.MenuToolButton(None, "Links")
+# item.set_menu(gtk.Menu())
+# item.connect("show-menu", self.__show_link_menu_cb)
+# toolbar.insert(item, -1)
+# item.show()
+
+ toolbox = Toolbox()
+ toolbox.connect('color-selected', self._color_selected)
+ self.pack_start(toolbox, False)
+ toolbox.show()
+
+ spring = gtk.Label('')
+ self.pack_start(spring, True)
+ spring.show()
+
+ def _color_selected(self, toolbox, color):
+ self._editor.set_color(color)
+
+ def __link_activate_cb(self, item, link):
+ buf = self._editor.get_buffer()
+ buf.append_link(link['title'], link['address'])
+
+ def __show_link_menu_cb(self, button):
+ menu = gtk.Menu()
+
+ links = self.__get_browser_shell().get_links()
+
+ for link in links:
+ item = gtk.MenuItem(link['title'], False)
+ item.connect("activate", self.__link_activate_cb, link)
+ menu.append(item)
+ item.show()
+
+ button.set_menu(menu)
+
+ def _create_emoticons_popup(self):
+ model = gtk.ListStore(gtk.gdk.Pixbuf, str)
+
+ for name in Emoticons.get_instance().get_all():
+ icon_theme = gtk.icon_theme_get_default()
+ try:
+ pixbuf = icon_theme.load_icon(name, 16, 0)
+ model.append([pixbuf, name])
+ except gobject.GError:
+ pass
+
+ icon_view = gtk.IconView(model)
+ icon_view.connect('selection-changed', self.__emoticon_selection_changed_cb)
+ icon_view.set_pixbuf_column(0)
+ icon_view.set_selection_mode(gtk.SELECTION_SINGLE)
+
+ frame = gtk.Frame()
+ frame.set_shadow_type(gtk.SHADOW_ETCHED_IN)
+ frame.add(icon_view)
+ icon_view.show()
+
+ window = gtk.Window(gtk.WINDOW_POPUP)
+ window.add(frame)
+ frame.show()
+
+ return window
+
+ def __emoticon_selection_changed_cb(self, icon_view):
+ items = icon_view.get_selected_items()
+ if items:
+ model = icon_view.get_model()
+ icon_name = model[items[0]][1]
+ self._editor.get_buffer().append_icon(icon_name)
+ self._emt_popup.hide()
+
+ def __emoticons_button_clicked_cb(self, button):
+ # FIXME grabs...
+ if not self._emt_popup:
+ self._emt_popup = self._create_emoticons_popup()
+
+ if self._emt_popup.get_property('visible'):
+ self._emt_popup.hide()
+ else:
+ width = 180
+ height = 130
+
+ self._emt_popup.set_default_size(width, height)
+
+ [x, y] = button.window.get_origin()
+ x += button.allocation.x
+ y += button.allocation.y - height
+ self._emt_popup.move(x, y)
+
+ self._emt_popup.show()
diff --git a/sugar/chat/Emoticons.py b/sugar/chat/Emoticons.py
index 3f0e09e..33e53eb 100644
--- a/sugar/chat/Emoticons.py
+++ b/sugar/chat/Emoticons.py
@@ -15,70 +15,70 @@
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
-emoticons_table = [ \
-[ 'stock_smiley-10', [ ':P', ':p' ] ], \
-[ 'stock_smiley-19', None ], \
-[ 'stock_smiley-2', None ], \
-[ 'stock_smiley-11', None ], \
-[ 'stock_smiley-1', [ ':)' ] ], \
-[ 'stock_smiley-3', None ], \
-[ 'stock_smiley-12', None ], \
-[ 'stock_smiley-20', None ], \
-[ 'stock_smiley-4', [ ':(' ] ], \
-[ 'stock_smiley-13', None ], \
-[ 'stock_smiley-21', None ], \
-[ 'stock_smiley-5', None ], \
-[ 'stock_smiley-14', None ], \
-[ 'stock_smiley-22', None ], \
-[ 'stock_smiley-6', None ], \
-[ 'stock_smiley-15', None ], \
-[ 'stock_smiley-23', None ], \
-[ 'stock_smiley-7', None ], \
-[ 'stock_smiley-16', None ], \
-[ 'stock_smiley-24', None ], \
-[ 'stock_smiley-8', None ], \
-[ 'stock_smiley-17', None ], \
-[ 'stock_smiley-25', None ], \
-[ 'stock_smiley-9', None ], \
-[ 'stock_smiley-18', None ], \
-[ 'stock_smiley-26', None ], \
+emoticons_table = [ \
+[ 'stock_smiley-10', [ ':P', ':p' ] ], \
+[ 'stock_smiley-19', None ], \
+[ 'stock_smiley-2', None ], \
+[ 'stock_smiley-11', None ], \
+[ 'stock_smiley-1', [ ':)' ] ], \
+[ 'stock_smiley-3', None ], \
+[ 'stock_smiley-12', None ], \
+[ 'stock_smiley-20', None ], \
+[ 'stock_smiley-4', [ ':(' ] ], \
+[ 'stock_smiley-13', None ], \
+[ 'stock_smiley-21', None ], \
+[ 'stock_smiley-5', None ], \
+[ 'stock_smiley-14', None ], \
+[ 'stock_smiley-22', None ], \
+[ 'stock_smiley-6', None ], \
+[ 'stock_smiley-15', None ], \
+[ 'stock_smiley-23', None ], \
+[ 'stock_smiley-7', None ], \
+[ 'stock_smiley-16', None ], \
+[ 'stock_smiley-24', None ], \
+[ 'stock_smiley-8', None ], \
+[ 'stock_smiley-17', None ], \
+[ 'stock_smiley-25', None ], \
+[ 'stock_smiley-9', None ], \
+[ 'stock_smiley-18', None ], \
+[ 'stock_smiley-26', None ], \
]
class Emoticons:
- instance = None
+ instance = None
- def get_instance():
- if not Emoticons.instance:
- Emoticons.instance = Emoticons()
- return Emoticons.instance
+ def get_instance():
+ if not Emoticons.instance:
+ Emoticons.instance = Emoticons()
+ return Emoticons.instance
- get_instance = staticmethod(get_instance)
+ get_instance = staticmethod(get_instance)
- def __init__(self):
- self._table = {}
+ def __init__(self):
+ self._table = {}
- for emoticon in emoticons_table:
- [ name, text_emts ] = emoticon
- self.add(name, text_emts)
-
- def add(self, icon_name, text=None):
- self._table[icon_name] = text
-
- def get_all(self):
- return self._table.keys()
-
- """Replace emoticons text with the icon name.
-
- Parse the provided text to find emoticons (in
- textual form) and replace them with their xml
- representation in the form:
- <icon name="$EMOTICON_ICON_NAME"/>
- """
- def replace(self, text):
- for icon_name in self._table.keys():
- text_emts = self._table[icon_name]
- if text_emts:
- for emoticon_text in text_emts:
- xml = '<icon name="' + icon_name + '"/>'
- text = text.replace(emoticon_text, xml)
- return text
+ for emoticon in emoticons_table:
+ [ name, text_emts ] = emoticon
+ self.add(name, text_emts)
+
+ def add(self, icon_name, text=None):
+ self._table[icon_name] = text
+
+ def get_all(self):
+ return self._table.keys()
+
+ """Replace emoticons text with the icon name.
+
+ Parse the provided text to find emoticons (in
+ textual form) and replace them with their xml
+ representation in the form:
+ <icon name="$EMOTICON_ICON_NAME"/>
+ """
+ def replace(self, text):
+ for icon_name in self._table.keys():
+ text_emts = self._table[icon_name]
+ if text_emts:
+ for emoticon_text in text_emts:
+ xml = '<icon name="' + icon_name + '"/>'
+ text = text.replace(emoticon_text, xml)
+ return text
diff --git a/sugar/chat/GroupChat.py b/sugar/chat/GroupChat.py
index d7580da..a1c6b65 100644
--- a/sugar/chat/GroupChat.py
+++ b/sugar/chat/GroupChat.py
@@ -23,15 +23,15 @@ from sugar.presence.PresenceService import PresenceService
import sugar.env
class GroupChat(Chat):
- def __init__(self):
- Chat.__init__(self)
- self._group_stream = None
+ def __init__(self):
+ Chat.__init__(self)
+ self._group_stream = None
- def _setup_stream(self, service):
- self._group_stream = Stream.new_from_service(service)
- self._group_stream.set_data_listener(self._group_recv_message)
- self._stream_writer = self._group_stream.new_writer()
+ def _setup_stream(self, service):
+ self._group_stream = Stream.new_from_service(service)
+ self._group_stream.set_data_listener(self._group_recv_message)
+ self._stream_writer = self._group_stream.new_writer()
- def _group_recv_message(self, address, msg):
- logging.debug('Group chat received from %s message %s' % (address, msg))
- self.recv_message(msg)
+ def _group_recv_message(self, address, msg):
+ logging.debug('Group chat received from %s message %s' % (address, msg))
+ self.recv_message(msg)
diff --git a/sugar/chat/richtext.py b/sugar/chat/richtext.py
index 7a6f179..ebd8b1c 100644
--- a/sugar/chat/richtext.py
+++ b/sugar/chat/richtext.py
@@ -21,431 +21,431 @@ import pango
import xml.sax
class RichTextView(gtk.TextView):
-
- __gsignals__ = {
- 'link-clicked': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_STRING]))
- }
-
- def __init__(self):
- gtk.TextView.__init__(self, RichTextBuffer())
- self.connect("motion-notify-event", self.__motion_notify_cb)
- self.connect("button-press-event", self.__button_press_cb)
- self.__hover_link = False
-
- def _set_hover_link(self, hover_link):
- if hover_link != self.__hover_link:
- self.__hover_link = hover_link
- display = self.get_toplevel().get_display()
- child_window = self.get_window(gtk.TEXT_WINDOW_TEXT)
-
- if hover_link:
- cursor = gtk.gdk.Cursor(display, gtk.gdk.HAND2)
- else:
- cursor = gtk.gdk.Cursor(display, gtk.gdk.XTERM)
-
- child_window.set_cursor(cursor)
- gtk.gdk.flush()
-
- def __iter_is_link(self, it):
- item = self.get_buffer().get_tag_table().lookup("link")
- if item:
- return it.has_tag(item)
- return False
-
- def __get_event_iter(self, event):
- return self.get_iter_at_location(int(event.x), int(event.y))
-
- def __motion_notify_cb(self, widget, event):
- if event.is_hint:
- event.window.get_pointer();
-
- it = self.__get_event_iter(event)
- if it:
- hover_link = self.__iter_is_link(it)
- else:
- hover_link = False
-
- self._set_hover_link(hover_link)
-
- def __button_press_cb(self, widget, event):
- it = self.__get_event_iter(event)
- if it and self.__iter_is_link(it):
- buf = self.get_buffer()
- address_tag = buf.get_tag_table().lookup("object-id")
-
- address_end = it.copy()
- address_end.backward_to_tag_toggle(address_tag)
-
- address_start = address_end.copy()
- address_start.backward_to_tag_toggle(address_tag)
-
- address = buf.get_text(address_start, address_end)
- self.emit("link-clicked", address)
+
+ __gsignals__ = {
+ 'link-clicked': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_STRING]))
+ }
+
+ def __init__(self):
+ gtk.TextView.__init__(self, RichTextBuffer())
+ self.connect("motion-notify-event", self.__motion_notify_cb)
+ self.connect("button-press-event", self.__button_press_cb)
+ self.__hover_link = False
+
+ def _set_hover_link(self, hover_link):
+ if hover_link != self.__hover_link:
+ self.__hover_link = hover_link
+ display = self.get_toplevel().get_display()
+ child_window = self.get_window(gtk.TEXT_WINDOW_TEXT)
+
+ if hover_link:
+ cursor = gtk.gdk.Cursor(display, gtk.gdk.HAND2)
+ else:
+ cursor = gtk.gdk.Cursor(display, gtk.gdk.XTERM)
+
+ child_window.set_cursor(cursor)
+ gtk.gdk.flush()
+
+ def __iter_is_link(self, it):
+ item = self.get_buffer().get_tag_table().lookup("link")
+ if item:
+ return it.has_tag(item)
+ return False
+
+ def __get_event_iter(self, event):
+ return self.get_iter_at_location(int(event.x), int(event.y))
+
+ def __motion_notify_cb(self, widget, event):
+ if event.is_hint:
+ event.window.get_pointer();
+
+ it = self.__get_event_iter(event)
+ if it:
+ hover_link = self.__iter_is_link(it)
+ else:
+ hover_link = False
+
+ self._set_hover_link(hover_link)
+
+ def __button_press_cb(self, widget, event):
+ it = self.__get_event_iter(event)
+ if it and self.__iter_is_link(it):
+ buf = self.get_buffer()
+ address_tag = buf.get_tag_table().lookup("object-id")
+
+ address_end = it.copy()
+ address_end.backward_to_tag_toggle(address_tag)
+
+ address_start = address_end.copy()
+ address_start.backward_to_tag_toggle(address_tag)
+
+ address = buf.get_text(address_start, address_end)
+ self.emit("link-clicked", address)
class RichTextBuffer(gtk.TextBuffer):
- def __init__(self):
- gtk.TextBuffer.__init__(self)
-
- self.connect_after("insert-text", self.__insert_text_cb)
-
- self.__create_tags()
- self.active_tags = []
-
- def append_link(self, title, address):
- it = self.get_iter_at_mark(self.get_insert())
- self.insert_with_tags_by_name(it, address, "link", "object-id")
- self.insert_with_tags_by_name(it, title, "link")
-
- def append_icon(self, name, it = None):
- if not it:
- it = self.get_iter_at_mark(self.get_insert())
-
- self.insert_with_tags_by_name(it, name, "icon", "object-id")
- icon_theme = gtk.icon_theme_get_default()
- try:
- pixbuf = icon_theme.load_icon(name, 16, 0)
- self.insert_pixbuf(it, pixbuf)
- except gobject.GError:
- pass
-
- def apply_tag(self, tag_name):
- self.active_tags.append(tag_name)
-
- bounds = self.get_selection_bounds()
- if bounds:
- [start, end] = bounds
- self.apply_tag_by_name(tag_name, start, end)
-
- def unapply_tag(self, tag_name):
- self.active_tags.remove(tag_name)
-
- bounds = self.get_selection_bounds()
- if bounds:
- [start, end] = bounds
- self.remove_tag_by_name(tag_name, start, end)
-
- def __create_tags(self):
- tag = self.create_tag("icon")
-
- tag = self.create_tag("link")
- tag.set_property("underline", pango.UNDERLINE_SINGLE)
- tag.set_property("foreground", "#0000FF")
-
- tag = self.create_tag("object-id")
- tag.set_property("invisible", True)
-
- tag = self.create_tag("bold")
- tag.set_property("weight", pango.WEIGHT_BOLD)
-
- tag = self.create_tag("italic")
- tag.set_property("style", pango.STYLE_ITALIC)
-
- tag = self.create_tag("font-size-xx-small")
- tag.set_property("scale", pango.SCALE_XX_SMALL)
-
- tag = self.create_tag("font-size-x-small")
- tag.set_property("scale", pango.SCALE_X_SMALL)
-
- tag = self.create_tag("font-size-small")
- tag.set_property("scale", pango.SCALE_SMALL)
-
- tag = self.create_tag("font-size-large")
- tag.set_property("scale", pango.SCALE_LARGE)
-
- tag = self.create_tag("font-size-x-large")
- tag.set_property("scale", pango.SCALE_X_LARGE)
-
- tag = self.create_tag("font-size-xx-large")
- tag.set_property("scale", pango.SCALE_XX_LARGE)
-
- def __insert_text_cb(self, widget, pos, text, length):
- for tag in self.active_tags:
- pos_end = pos.copy()
- pos_end.backward_chars(length)
- self.apply_tag_by_name(tag, pos, pos_end)
-
+ def __init__(self):
+ gtk.TextBuffer.__init__(self)
+
+ self.connect_after("insert-text", self.__insert_text_cb)
+
+ self.__create_tags()
+ self.active_tags = []
+
+ def append_link(self, title, address):
+ it = self.get_iter_at_mark(self.get_insert())
+ self.insert_with_tags_by_name(it, address, "link", "object-id")
+ self.insert_with_tags_by_name(it, title, "link")
+
+ def append_icon(self, name, it = None):
+ if not it:
+ it = self.get_iter_at_mark(self.get_insert())
+
+ self.insert_with_tags_by_name(it, name, "icon", "object-id")
+ icon_theme = gtk.icon_theme_get_default()
+ try:
+ pixbuf = icon_theme.load_icon(name, 16, 0)
+ self.insert_pixbuf(it, pixbuf)
+ except gobject.GError:
+ pass
+
+ def apply_tag(self, tag_name):
+ self.active_tags.append(tag_name)
+
+ bounds = self.get_selection_bounds()
+ if bounds:
+ [start, end] = bounds
+ self.apply_tag_by_name(tag_name, start, end)
+
+ def unapply_tag(self, tag_name):
+ self.active_tags.remove(tag_name)
+
+ bounds = self.get_selection_bounds()
+ if bounds:
+ [start, end] = bounds
+ self.remove_tag_by_name(tag_name, start, end)
+
+ def __create_tags(self):
+ tag = self.create_tag("icon")
+
+ tag = self.create_tag("link")
+ tag.set_property("underline", pango.UNDERLINE_SINGLE)
+ tag.set_property("foreground", "#0000FF")
+
+ tag = self.create_tag("object-id")
+ tag.set_property("invisible", True)
+
+ tag = self.create_tag("bold")
+ tag.set_property("weight", pango.WEIGHT_BOLD)
+
+ tag = self.create_tag("italic")
+ tag.set_property("style", pango.STYLE_ITALIC)
+
+ tag = self.create_tag("font-size-xx-small")
+ tag.set_property("scale", pango.SCALE_XX_SMALL)
+
+ tag = self.create_tag("font-size-x-small")
+ tag.set_property("scale", pango.SCALE_X_SMALL)
+
+ tag = self.create_tag("font-size-small")
+ tag.set_property("scale", pango.SCALE_SMALL)
+
+ tag = self.create_tag("font-size-large")
+ tag.set_property("scale", pango.SCALE_LARGE)
+
+ tag = self.create_tag("font-size-x-large")
+ tag.set_property("scale", pango.SCALE_X_LARGE)
+
+ tag = self.create_tag("font-size-xx-large")
+ tag.set_property("scale", pango.SCALE_XX_LARGE)
+
+ def __insert_text_cb(self, widget, pos, text, length):
+ for tag in self.active_tags:
+ pos_end = pos.copy()
+ pos_end.backward_chars(length)
+ self.apply_tag_by_name(tag, pos, pos_end)
+
class RichTextToolbox(gtk.HBox):
- def __init__(self, buf):
- gtk.HBox.__init__(self, False, 6)
-
- self.buf = buf
-
- self._font_size = "normal"
- self._font_scales = [ "xx-small", "x-small", "small", \
- "normal", \
- "large", "x-large", "xx-large" ]
-
- image = gtk.Image()
- image.set_from_stock(gtk.STOCK_BOLD, gtk.ICON_SIZE_SMALL_TOOLBAR)
-
- item = gtk.ToggleButton()
- item.set_image(image)
- item.connect("toggled", self.__toggle_style_cb, "bold")
- item.unset_flags(gtk.CAN_FOCUS)
- self.pack_start(item, False)
- item.show()
-
- image.show()
-
- image = gtk.Image()
- image.set_from_stock(gtk.STOCK_ITALIC, gtk.ICON_SIZE_SMALL_TOOLBAR)
-
- item = gtk.ToggleButton()
- item.set_image(image)
- item.unset_flags(gtk.CAN_FOCUS)
- item.connect("toggled", self.__toggle_style_cb, "italic")
- self.pack_start(item, False)
- item.show()
-
- image = gtk.Image()
- image.set_from_stock(gtk.STOCK_GO_UP, gtk.ICON_SIZE_SMALL_TOOLBAR)
-
- self._font_size_up = gtk.Button()
- self._font_size_up.set_image(image)
- self._font_size_up.unset_flags(gtk.CAN_FOCUS)
- self._font_size_up.connect("clicked", self.__font_size_up_cb)
- self.pack_start(self._font_size_up, False)
- self._font_size_up.show()
-
- image.show()
-
- image = gtk.Image()
- image.set_from_stock(gtk.STOCK_GO_DOWN, gtk.ICON_SIZE_SMALL_TOOLBAR)
-
- self._font_size_down = gtk.Button()
- self._font_size_down.set_image(image)
- self._font_size_down.unset_flags(gtk.CAN_FOCUS)
- self._font_size_down.connect("clicked", self.__font_size_down_cb)
- self.pack_start(self._font_size_down, False)
- self._font_size_down.show()
-
- image.show()
-
- def _get_font_size_index(self):
- return self._font_scales.index(self._font_size);
-
- def __toggle_style_cb(self, toggle, tag_name):
- if toggle.get_active():
- self.buf.apply_tag(tag_name)
- else:
- self.buf.unapply_tag(tag_name)
-
- def _set_font_size(self, font_size):
- if self._font_size != "normal":
- self.buf.unapply_tag("font-size-" + self._font_size)
- if font_size != "normal":
- self.buf.apply_tag("font-size-" + font_size)
-
- self._font_size = font_size
-
- can_up = self._get_font_size_index() < len(self._font_scales) - 1
- can_down = self._get_font_size_index() > 0
- self._font_size_up.set_sensitive(can_up)
- self._font_size_down.set_sensitive(can_down)
-
- def __font_size_up_cb(self, button):
- index = self._get_font_size_index()
- if index + 1 < len(self._font_scales):
- self._set_font_size(self._font_scales[index + 1])
-
- def __font_size_down_cb(self, button):
- index = self._get_font_size_index()
- if index > 0:
- self._set_font_size(self._font_scales[index - 1])
-
+ def __init__(self, buf):
+ gtk.HBox.__init__(self, False, 6)
+
+ self.buf = buf
+
+ self._font_size = "normal"
+ self._font_scales = [ "xx-small", "x-small", "small", \
+ "normal", \
+ "large", "x-large", "xx-large" ]
+
+ image = gtk.Image()
+ image.set_from_stock(gtk.STOCK_BOLD, gtk.ICON_SIZE_SMALL_TOOLBAR)
+
+ item = gtk.ToggleButton()
+ item.set_image(image)
+ item.connect("toggled", self.__toggle_style_cb, "bold")
+ item.unset_flags(gtk.CAN_FOCUS)
+ self.pack_start(item, False)
+ item.show()
+
+ image.show()
+
+ image = gtk.Image()
+ image.set_from_stock(gtk.STOCK_ITALIC, gtk.ICON_SIZE_SMALL_TOOLBAR)
+
+ item = gtk.ToggleButton()
+ item.set_image(image)
+ item.unset_flags(gtk.CAN_FOCUS)
+ item.connect("toggled", self.__toggle_style_cb, "italic")
+ self.pack_start(item, False)
+ item.show()
+
+ image = gtk.Image()
+ image.set_from_stock(gtk.STOCK_GO_UP, gtk.ICON_SIZE_SMALL_TOOLBAR)
+
+ self._font_size_up = gtk.Button()
+ self._font_size_up.set_image(image)
+ self._font_size_up.unset_flags(gtk.CAN_FOCUS)
+ self._font_size_up.connect("clicked", self.__font_size_up_cb)
+ self.pack_start(self._font_size_up, False)
+ self._font_size_up.show()
+
+ image.show()
+
+ image = gtk.Image()
+ image.set_from_stock(gtk.STOCK_GO_DOWN, gtk.ICON_SIZE_SMALL_TOOLBAR)
+
+ self._font_size_down = gtk.Button()
+ self._font_size_down.set_image(image)
+ self._font_size_down.unset_flags(gtk.CAN_FOCUS)
+ self._font_size_down.connect("clicked", self.__font_size_down_cb)
+ self.pack_start(self._font_size_down, False)
+ self._font_size_down.show()
+
+ image.show()
+
+ def _get_font_size_index(self):
+ return self._font_scales.index(self._font_size);
+
+ def __toggle_style_cb(self, toggle, tag_name):
+ if toggle.get_active():
+ self.buf.apply_tag(tag_name)
+ else:
+ self.buf.unapply_tag(tag_name)
+
+ def _set_font_size(self, font_size):
+ if self._font_size != "normal":
+ self.buf.unapply_tag("font-size-" + self._font_size)
+ if font_size != "normal":
+ self.buf.apply_tag("font-size-" + font_size)
+
+ self._font_size = font_size
+
+ can_up = self._get_font_size_index() < len(self._font_scales) - 1
+ can_down = self._get_font_size_index() > 0
+ self._font_size_up.set_sensitive(can_up)
+ self._font_size_down.set_sensitive(can_down)
+
+ def __font_size_up_cb(self, button):
+ index = self._get_font_size_index()
+ if index + 1 < len(self._font_scales):
+ self._set_font_size(self._font_scales[index + 1])
+
+ def __font_size_down_cb(self, button):
+ index = self._get_font_size_index()
+ if index > 0:
+ self._set_font_size(self._font_scales[index - 1])
+
class RichTextHandler(xml.sax.handler.ContentHandler):
- def __init__(self, serializer, buf):
- xml.sax.handler.ContentHandler.__init__(self)
- self.buf = buf
- self.serializer = serializer
- self.tags = []
- self._in_richtext = False
- self._done = False
-
- def startElement(self, name, attrs):
- # Look for, and only start parsing after 'richtext'
- if not self._in_richtext and name == "richtext":
- self._in_richtext = True
- if not self._in_richtext:
- return
-
- if name != "richtext":
- tag = self.serializer.deserialize_element(name, attrs)
- self.tags.append(tag)
- if name == "link":
- self.href = attrs['href']
- elif name == "icon":
- self.buf.append_icon(attrs['name'], self.buf.get_end_iter())
+ def __init__(self, serializer, buf):
+ xml.sax.handler.ContentHandler.__init__(self)
+ self.buf = buf
+ self.serializer = serializer
+ self.tags = []
+ self._in_richtext = False
+ self._done = False
+
+ def startElement(self, name, attrs):
+ # Look for, and only start parsing after 'richtext'
+ if not self._in_richtext and name == "richtext":
+ self._in_richtext = True
+ if not self._in_richtext:
+ return
+
+ if name != "richtext":
+ tag = self.serializer.deserialize_element(name, attrs)
+ self.tags.append(tag)
+ if name == "link":
+ self.href = attrs['href']
+ elif name == "icon":
+ self.buf.append_icon(attrs['name'], self.buf.get_end_iter())
- def characters(self, data):
- start_it = it = self.buf.get_end_iter()
- mark = self.buf.create_mark(None, start_it, True)
- self.buf.insert(it, data)
- start_it = self.buf.get_iter_at_mark(mark)
-
- for tag in self.tags:
- self.buf.apply_tag_by_name(tag, start_it, it)
- if tag == "link":
- self.buf.insert_with_tags_by_name(start_it, self.href,
- "link", "object-id")
-
- def endElement(self, name):
- if not self._done and self._in_richtext:
- if name != "richtext":
- self.tags.pop()
- if name == "richtext":
- self._done = True
- self._in_richtext = False
+ def characters(self, data):
+ start_it = it = self.buf.get_end_iter()
+ mark = self.buf.create_mark(None, start_it, True)
+ self.buf.insert(it, data)
+ start_it = self.buf.get_iter_at_mark(mark)
+
+ for tag in self.tags:
+ self.buf.apply_tag_by_name(tag, start_it, it)
+ if tag == "link":
+ self.buf.insert_with_tags_by_name(start_it, self.href,
+ "link", "object-id")
+
+ def endElement(self, name):
+ if not self._done and self._in_richtext:
+ if name != "richtext":
+ self.tags.pop()
+ if name == "richtext":
+ self._done = True
+ self._in_richtext = False
class RichTextSerializer:
- def __init__(self):
- self._open_tags = []
-
- def deserialize_element(self, el_name, attributes):
- if el_name == "bold":
- return "bold"
- elif el_name == "italic":
- return "italic"
- elif el_name == "font":
- return "font-size-" + attributes["size"]
- elif el_name == "link":
- return "link"
- elif el_name == "icon":
- return "icon"
- else:
- return None
-
- def _parse_object_id(self, it):
- object_id_tag = self.buf.get_tag_table().lookup("object-id")
- end = it.copy()
- end.forward_to_tag_toggle(object_id_tag)
- return self.buf.get_text(it, end)
-
- def serialize_tag_start(self, tag, it):
- name = tag.get_property("name")
- if name == "bold":
- return "<bold>"
- elif name == "italic":
- return "<italic>"
- elif name == "link":
- address = self._parse_object_id(it)
- return "<link " + "href=\"" + address + "\">"
- elif name == "icon":
- name = self._parse_object_id(it)
- return "<icon " + "name=\"" + name + "\"/>"
- elif name == "object-id":
- return ""
- elif name.startswith("font-size-"):
- tag_name = name.replace("font-size-", "", 1)
- return "<font size=\"" + tag_name + "\">"
- else:
- return "<unknown>"
-
- def serialize_tag_end(self, tag):
- name = tag.get_property("name")
- if name == "bold":
- return "</bold>"
- elif name == "italic":
- return "</italic>"
- elif name == "link":
- return "</link>"
- elif name == "icon":
- return ""
- elif name == "object-id":
- return ""
- elif name.startswith("font-size-"):
- return "</font>"
- else:
- return "</unknown>"
-
- def serialize(self, buf):
- self.buf = buf
-
- res = "<richtext>"
-
- next_it = buf.get_start_iter()
- while not next_it.is_end():
- it = next_it.copy()
- if not next_it.forward_to_tag_toggle(None):
- next_it = buf.get_end_iter()
-
- tags_to_reopen = []
-
- for tag in it.get_toggled_tags(False):
- while 1:
- open_tag = self._open_tags.pop()
- res += self.serialize_tag_end(tag)
- if open_tag == tag:
- break
- tags_to_reopen.append(open_tag)
-
- for tag in tags_to_reopen:
- self._open_tags.append(tag)
- res += self.serialize_tag_start(tag, it)
-
- for tag in it.get_toggled_tags(True):
- self._open_tags.append(tag)
- res += self.serialize_tag_start(tag, it)
-
- res += buf.get_text(it, next_it, False)
-
- if next_it.is_end():
- self._open_tags.reverse()
- for tag in self._open_tags:
- res += self.serialize_tag_end(tag)
-
- res += "</richtext>"
-
- return res
-
- def deserialize(self, xml_string, buf):
- parser = xml.sax.make_parser()
- handler = RichTextHandler(self, buf)
- parser.setContentHandler(handler)
- parser.feed(xml_string)
- parser.close()
+ def __init__(self):
+ self._open_tags = []
+
+ def deserialize_element(self, el_name, attributes):
+ if el_name == "bold":
+ return "bold"
+ elif el_name == "italic":
+ return "italic"
+ elif el_name == "font":
+ return "font-size-" + attributes["size"]
+ elif el_name == "link":
+ return "link"
+ elif el_name == "icon":
+ return "icon"
+ else:
+ return None
+
+ def _parse_object_id(self, it):
+ object_id_tag = self.buf.get_tag_table().lookup("object-id")
+ end = it.copy()
+ end.forward_to_tag_toggle(object_id_tag)
+ return self.buf.get_text(it, end)
+
+ def serialize_tag_start(self, tag, it):
+ name = tag.get_property("name")
+ if name == "bold":
+ return "<bold>"
+ elif name == "italic":
+ return "<italic>"
+ elif name == "link":
+ address = self._parse_object_id(it)
+ return "<link " + "href=\"" + address + "\">"
+ elif name == "icon":
+ name = self._parse_object_id(it)
+ return "<icon " + "name=\"" + name + "\"/>"
+ elif name == "object-id":
+ return ""
+ elif name.startswith("font-size-"):
+ tag_name = name.replace("font-size-", "", 1)
+ return "<font size=\"" + tag_name + "\">"
+ else:
+ return "<unknown>"
+
+ def serialize_tag_end(self, tag):
+ name = tag.get_property("name")
+ if name == "bold":
+ return "</bold>"
+ elif name == "italic":
+ return "</italic>"
+ elif name == "link":
+ return "</link>"
+ elif name == "icon":
+ return ""
+ elif name == "object-id":
+ return ""
+ elif name.startswith("font-size-"):
+ return "</font>"
+ else:
+ return "</unknown>"
+
+ def serialize(self, buf):
+ self.buf = buf
+
+ res = "<richtext>"
+
+ next_it = buf.get_start_iter()
+ while not next_it.is_end():
+ it = next_it.copy()
+ if not next_it.forward_to_tag_toggle(None):
+ next_it = buf.get_end_iter()
+
+ tags_to_reopen = []
+
+ for tag in it.get_toggled_tags(False):
+ while 1:
+ open_tag = self._open_tags.pop()
+ res += self.serialize_tag_end(tag)
+ if open_tag == tag:
+ break
+ tags_to_reopen.append(open_tag)
+
+ for tag in tags_to_reopen:
+ self._open_tags.append(tag)
+ res += self.serialize_tag_start(tag, it)
+
+ for tag in it.get_toggled_tags(True):
+ self._open_tags.append(tag)
+ res += self.serialize_tag_start(tag, it)
+
+ res += buf.get_text(it, next_it, False)
+
+ if next_it.is_end():
+ self._open_tags.reverse()
+ for tag in self._open_tags:
+ res += self.serialize_tag_end(tag)
+
+ res += "</richtext>"
+
+ return res
+
+ def deserialize(self, xml_string, buf):
+ parser = xml.sax.make_parser()
+ handler = RichTextHandler(self, buf)
+ parser.setContentHandler(handler)
+ parser.feed(xml_string)
+ parser.close()
def test_quit(w, rb):
- print RichTextSerializer().serialize(rb)
- gtk.main_quit()
-
+ print RichTextSerializer().serialize(rb)
+ gtk.main_quit()
+
def link_clicked(v, address):
- print "Link clicked " + address
+ print "Link clicked " + address
if __name__ == "__main__":
- window = gtk.Window()
- window.set_default_size(400, 300)
-
- vbox = gtk.VBox()
-
- view = RichTextView()
- view.connect("link-clicked", link_clicked)
- vbox.pack_start(view)
- view.show()
-
- rich_buf = view.get_buffer()
-
- test_xml = "<richtext>"
-
- test_xml += "<bold><italic>Test</italic>one</bold>\n"
- test_xml += "<bold><italic>Test two</italic></bold>"
- test_xml += "<font size=\"xx-small\">Test three</font>"
- test_xml += "<link href=\"http://www.gnome.org\">Test link</link>"
- test_xml += "<icon name=\"stock_help-chat\"/>"
- test_xml += "</richtext>"
-
- RichTextSerializer().deserialize(test_xml, rich_buf)
-
- toolbar = RichTextToolbar(rich_buf)
- vbox.pack_start(toolbar, False)
- toolbar.show()
-
- window.add(vbox)
- vbox.show()
-
- window.show()
-
- window.connect("destroy", test_quit, rich_buf)
-
- gtk.main()
+ window = gtk.Window()
+ window.set_default_size(400, 300)
+
+ vbox = gtk.VBox()
+
+ view = RichTextView()
+ view.connect("link-clicked", link_clicked)
+ vbox.pack_start(view)
+ view.show()
+
+ rich_buf = view.get_buffer()
+
+ test_xml = "<richtext>"
+
+ test_xml += "<bold><italic>Test</italic>one</bold>\n"
+ test_xml += "<bold><italic>Test two</italic></bold>"
+ test_xml += "<font size=\"xx-small\">Test three</font>"
+ test_xml += "<link href=\"http://www.gnome.org\">Test link</link>"
+ test_xml += "<icon name=\"stock_help-chat\"/>"
+ test_xml += "</richtext>"
+
+ RichTextSerializer().deserialize(test_xml, rich_buf)
+
+ toolbar = RichTextToolbar(rich_buf)
+ vbox.pack_start(toolbar, False)
+ toolbar.show()
+
+ window.add(vbox)
+ vbox.show()
+
+ window.show()
+
+ window.connect("destroy", test_quit, rich_buf)
+
+ gtk.main()
diff --git a/sugar/chat/sketchpad/Sketch.py b/sugar/chat/sketchpad/Sketch.py
index 0ddfb3c..ac0a865 100644
--- a/sugar/chat/sketchpad/Sketch.py
+++ b/sugar/chat/sketchpad/Sketch.py
@@ -18,37 +18,37 @@
from SVGdraw import path
class Sketch:
- def __init__(self, rgb):
- self._points = []
- self._rgb = (float(rgb[0]), float(rgb[1]), float(rgb[2]))
-
- def add_point(self, x, y):
- self._points.append((x, y))
+ def __init__(self, rgb):
+ self._points = []
+ self._rgb = (float(rgb[0]), float(rgb[1]), float(rgb[2]))
+
+ def add_point(self, x, y):
+ self._points.append((x, y))
- def get_points(self):
- return self._points
-
- def draw(self, ctx):
- start = True
- for (x, y) in self._points:
- if start:
- ctx.move_to(x, y)
- start = False
- else:
- ctx.line_to(x, y)
- ctx.set_source_rgb(self._rgb[0], self._rgb[1], self._rgb[2])
- ctx.stroke()
-
- def draw_to_svg(self):
- i = 0
- for (x, y) in self._points:
- coords = str(x) + ' ' + str(y) + ' '
- if i == 0:
- path_data = 'M ' + coords
- elif i == 1:
- path_data += 'L ' + coords
- else:
- path_data += coords
- i += 1
- color = "#%02X%02X%02X" % (255 * self._rgb[0], 255 * self._rgb[1], 255 * self._rgb[2])
- return path(path_data, fill = 'none', stroke = color)
+ def get_points(self):
+ return self._points
+
+ def draw(self, ctx):
+ start = True
+ for (x, y) in self._points:
+ if start:
+ ctx.move_to(x, y)
+ start = False
+ else:
+ ctx.line_to(x, y)
+ ctx.set_source_rgb(self._rgb[0], self._rgb[1], self._rgb[2])
+ ctx.stroke()
+
+ def draw_to_svg(self):
+ i = 0
+ for (x, y) in self._points:
+ coords = str(x) + ' ' + str(y) + ' '
+ if i == 0:
+ path_data = 'M ' + coords
+ elif i == 1:
+ path_data += 'L ' + coords
+ else:
+ path_data += coords
+ i += 1
+ color = "#%02X%02X%02X" % (255 * self._rgb[0], 255 * self._rgb[1], 255 * self._rgb[2])
+ return path(path_data, fill = 'none', stroke = color)
diff --git a/sugar/chat/sketchpad/SketchPad.py b/sugar/chat/sketchpad/SketchPad.py
index 33327f0..e15e435 100644
--- a/sugar/chat/sketchpad/SketchPad.py
+++ b/sugar/chat/sketchpad/SketchPad.py
@@ -23,101 +23,101 @@ from SVGdraw import drawing
from SVGdraw import svg
class SketchPad(gtk.DrawingArea):
- __gsignals__ = {
- 'new-user-sketch':(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT]))
- }
+ __gsignals__ = {
+ 'new-user-sketch':(gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT]))
+ }
- def __init__(self, bgcolor=(0.6, 1, 0.4)):
- gtk.DrawingArea.__init__(self)
+ def __init__(self, bgcolor=(0.6, 1, 0.4)):
+ gtk.DrawingArea.__init__(self)
- self._active_sketch = None
- self._rgb = (0.0, 0.0, 0.0)
- self._bgcolor = bgcolor
- self._sketches = []
+ self._active_sketch = None
+ self._rgb = (0.0, 0.0, 0.0)
+ self._bgcolor = bgcolor
+ self._sketches = []
- self.add_events(gtk.gdk.BUTTON_PRESS_MASK |
- gtk.gdk.BUTTON_RELEASE_MASK |
- gtk.gdk.BUTTON1_MOTION_MASK)
- self.connect("button-press-event", self._button_press_cb)
- self.connect("button-release-event", self._button_release_cb)
- self.connect("motion-notify-event", self._motion_notify_cb)
- self.connect('expose_event', self.expose)
-
- def clear(self):
- self._sketches = []
- self.window.invalidate_rect(None, False)
+ self.add_events(gtk.gdk.BUTTON_PRESS_MASK |
+ gtk.gdk.BUTTON_RELEASE_MASK |
+ gtk.gdk.BUTTON1_MOTION_MASK)
+ self.connect("button-press-event", self._button_press_cb)
+ self.connect("button-release-event", self._button_release_cb)
+ self.connect("motion-notify-event", self._motion_notify_cb)
+ self.connect('expose_event', self.expose)
+
+ def clear(self):
+ self._sketches = []
+ self.window.invalidate_rect(None, False)
- def expose(self, widget, event):
- """Draw the background of the sketchpad."""
- rect = self.get_allocation()
- ctx = widget.window.cairo_create()
-
- ctx.set_source_rgb(self._bgcolor[0], self._bgcolor[1], self._bgcolor[2])
- ctx.rectangle(0, 0, rect.width, rect.height)
- ctx.fill_preserve()
-
- ctx.set_source_rgb(0, 0.3, 0.2)
- ctx.stroke()
-
- for sketch in self._sketches:
- sketch.draw(ctx)
-
- return False
+ def expose(self, widget, event):
+ """Draw the background of the sketchpad."""
+ rect = self.get_allocation()
+ ctx = widget.window.cairo_create()
+
+ ctx.set_source_rgb(self._bgcolor[0], self._bgcolor[1], self._bgcolor[2])
+ ctx.rectangle(0, 0, rect.width, rect.height)
+ ctx.fill_preserve()
+
+ ctx.set_source_rgb(0, 0.3, 0.2)
+ ctx.stroke()
+
+ for sketch in self._sketches:
+ sketch.draw(ctx)
+
+ return False
- def set_color(self, color):
- """Sets the current drawing color of the sketchpad.
- color agument should be 3-item tuple of rgb values between 0 and 1."""
- self._rgb = color
+ def set_color(self, color):
+ """Sets the current drawing color of the sketchpad.
+ color agument should be 3-item tuple of rgb values between 0 and 1."""
+ self._rgb = color
- def add_sketch(self, sketch):
- """Add a sketch to the the pad. Mostly for subclasses and clients."""
- self._sketches.append(sketch)
- self.window.invalidate_rect(None, False)
+ def add_sketch(self, sketch):
+ """Add a sketch to the the pad. Mostly for subclasses and clients."""
+ self._sketches.append(sketch)
+ self.window.invalidate_rect(None, False)
- def add_point(self, event):
- if not self._active_sketch:
- return
- self._active_sketch.add_point(event.x, event.y)
- self.window.invalidate_rect(None, False)
-
- def _button_press_cb(self, widget, event):
- self._active_sketch = Sketch(self._rgb)
- self._sketches.append(self._active_sketch)
- self.add_point(event)
-
- def _button_release_cb(self, widget, event):
- self.add_point(event)
- self.emit('new-user-sketch', self._active_sketch)
- self._active_sketch = None
-
- def _motion_notify_cb(self, widget, event):
- self.add_point(event)
-
- def to_svg(self):
- """Return a string containing an SVG representation of this sketch."""
- d = drawing()
- s = svg()
- for sketch in self._sketches:
- s.addElement(sketch.draw_to_svg())
- d.setSVG(s)
- return d.toXml()
+ def add_point(self, event):
+ if not self._active_sketch:
+ return
+ self._active_sketch.add_point(event.x, event.y)
+ self.window.invalidate_rect(None, False)
+
+ def _button_press_cb(self, widget, event):
+ self._active_sketch = Sketch(self._rgb)
+ self._sketches.append(self._active_sketch)
+ self.add_point(event)
+
+ def _button_release_cb(self, widget, event):
+ self.add_point(event)
+ self.emit('new-user-sketch', self._active_sketch)
+ self._active_sketch = None
+
+ def _motion_notify_cb(self, widget, event):
+ self.add_point(event)
+
+ def to_svg(self):
+ """Return a string containing an SVG representation of this sketch."""
+ d = drawing()
+ s = svg()
+ for sketch in self._sketches:
+ s.addElement(sketch.draw_to_svg())
+ d.setSVG(s)
+ return d.toXml()
def test_quit(w, skpad):
- print skpad.to_svg()
- gtk.main_quit()
+ print skpad.to_svg()
+ gtk.main_quit()
if __name__ == "__main__":
- window = gtk.Window()
- window.set_default_size(400, 300)
- window.connect("destroy", lambda w: gtk.main_quit())
+ window = gtk.Window()
+ window.set_default_size(400, 300)
+ window.connect("destroy", lambda w: gtk.main_quit())
- sketchpad = SketchPad()
- window.add(sketchpad)
- sketchpad.show()
-
- window.show()
-
- window.connect("destroy", test_quit, sketchpad)
+ sketchpad = SketchPad()
+ window.add(sketchpad)
+ sketchpad.show()
+
+ window.show()
+
+ window.connect("destroy", test_quit, sketchpad)
- gtk.main()
+ gtk.main()
diff --git a/sugar/chat/sketchpad/Toolbox.py b/sugar/chat/sketchpad/Toolbox.py
index 0ae4e29..b142f98 100644
--- a/sugar/chat/sketchpad/Toolbox.py
+++ b/sugar/chat/sketchpad/Toolbox.py
@@ -19,59 +19,59 @@ import gtk
import gobject
class ColorButton(gtk.RadioButton):
- def __init__(self, group, rgb):
- gtk.RadioButton.__init__(self, group)
-
- self._rgb = rgb
-
- self.set_mode(False)
- self.set_relief(gtk.RELIEF_NONE)
-
- drawing_area = gtk.DrawingArea()
- drawing_area.set_size_request(24, 24)
- drawing_area.connect_after('expose_event', self.expose)
- self.add(drawing_area)
- drawing_area.show()
+ def __init__(self, group, rgb):
+ gtk.RadioButton.__init__(self, group)
+
+ self._rgb = rgb
+
+ self.set_mode(False)
+ self.set_relief(gtk.RELIEF_NONE)
+
+ drawing_area = gtk.DrawingArea()
+ drawing_area.set_size_request(24, 24)
+ drawing_area.connect_after('expose_event', self.expose)
+ self.add(drawing_area)
+ drawing_area.show()
- def color(self):
- return self._rgb
+ def color(self):
+ return self._rgb
- def expose(self, widget, event):
- rect = widget.get_allocation()
- ctx = widget.window.cairo_create()
+ def expose(self, widget, event):
+ rect = widget.get_allocation()
+ ctx = widget.window.cairo_create()
- ctx.set_source_rgb(self._rgb[0], self._rgb[1] , self._rgb[2])
- ctx.rectangle(4, 4, rect.width - 8, rect.height - 8)
- ctx.fill()
-
- return False
+ ctx.set_source_rgb(self._rgb[0], self._rgb[1] , self._rgb[2])
+ ctx.rectangle(4, 4, rect.width - 8, rect.height - 8)
+ ctx.fill()
+
+ return False
class Toolbox(gtk.HBox):
- __gsignals__ = {
- 'color-selected': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT]))
- }
+ __gsignals__ = {
+ 'color-selected': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT]))
+ }
- def __init__(self):
- gtk.HBox.__init__(self, False, 6)
-
- self._colors_group = None
-
- self._add_color([0, 0, 0])
- self._add_color([1, 0, 0])
- self._add_color([0, 1, 0])
- self._add_color([0, 0, 1])
-
- def _add_color(self, rgb):
- color = ColorButton(self._colors_group, rgb)
- color.unset_flags(gtk.CAN_FOCUS)
- color.connect('clicked', self.__color_clicked_cb, rgb)
- self.pack_start(color, False)
+ def __init__(self):
+ gtk.HBox.__init__(self, False, 6)
+
+ self._colors_group = None
+
+ self._add_color([0, 0, 0])
+ self._add_color([1, 0, 0])
+ self._add_color([0, 1, 0])
+ self._add_color([0, 0, 1])
+
+ def _add_color(self, rgb):
+ color = ColorButton(self._colors_group, rgb)
+ color.unset_flags(gtk.CAN_FOCUS)
+ color.connect('clicked', self.__color_clicked_cb, rgb)
+ self.pack_start(color, False)
- if self._colors_group == None:
- self._colors_group = color
+ if self._colors_group == None:
+ self._colors_group = color
- color.show()
+ color.show()
- def __color_clicked_cb(self, button, rgb):
- self.emit("color-selected", button.color())
+ def __color_clicked_cb(self, button, rgb):
+ self.emit("color-selected", button.color())
diff --git a/sugar/clipboard/ClipboardService.py b/sugar/clipboard/ClipboardService.py
index 7c9dd1f..254d6b2 100644
--- a/sugar/clipboard/ClipboardService.py
+++ b/sugar/clipboard/ClipboardService.py
@@ -7,69 +7,69 @@ DBUS_PATH = "/org/laptop/Clipboard"
class ClipboardService(gobject.GObject):
- __gsignals__ = {
- 'object-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([str, str, str])),
- 'object-deleted': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([str])),
- 'object-state-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([str, int])),
- }
-
- def __init__(self):
- gobject.GObject.__init__(self)
-
- self._dbus_service = None
- bus = dbus.SessionBus()
- bus.add_signal_receiver(self._name_owner_changed_cb,
- signal_name="NameOwnerChanged",
- dbus_interface="org.freedesktop.DBus")
- # Try to register to ClipboardService, if we fail, we'll try later.
- try:
- self._connect_clipboard_signals()
- except dbus.DBusException, exception:
- pass
-
- def _connect_clipboard_signals(self):
- bus = dbus.SessionBus()
- proxy_obj = bus.get_object(DBUS_SERVICE, DBUS_PATH)
- self._dbus_service = dbus.Interface(proxy_obj, DBUS_SERVICE)
- self._dbus_service.connect_to_signal('object_added',
- self._object_added_cb)
- self._dbus_service.connect_to_signal('object_deleted',
- self._object_deleted_cb)
- self._dbus_service.connect_to_signal('object_state_changed',
- self._object_state_changed_cb)
+ __gsignals__ = {
+ 'object-added': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([str, str, str])),
+ 'object-deleted': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([str])),
+ 'object-state-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([str, int])),
+ }
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+
+ self._dbus_service = None
+ bus = dbus.SessionBus()
+ bus.add_signal_receiver(self._name_owner_changed_cb,
+ signal_name="NameOwnerChanged",
+ dbus_interface="org.freedesktop.DBus")
+ # Try to register to ClipboardService, if we fail, we'll try later.
+ try:
+ self._connect_clipboard_signals()
+ except dbus.DBusException, exception:
+ pass
+
+ def _connect_clipboard_signals(self):
+ bus = dbus.SessionBus()
+ proxy_obj = bus.get_object(DBUS_SERVICE, DBUS_PATH)
+ self._dbus_service = dbus.Interface(proxy_obj, DBUS_SERVICE)
+ self._dbus_service.connect_to_signal('object_added',
+ self._object_added_cb)
+ self._dbus_service.connect_to_signal('object_deleted',
+ self._object_deleted_cb)
+ self._dbus_service.connect_to_signal('object_state_changed',
+ self._object_state_changed_cb)
- def _name_owner_changed_cb(self, name, old, new):
- if name != DBUS_SERVICE:
- return
-
- if (not old and not len(old)) and (new and len(new)):
- # ClipboardService started up
- self._connect_clipboard_signals()
-
- def _object_added_cb(self, name, mimeType, fileName):
- self.emit('object-added', name, mimeType, fileName)
+ def _name_owner_changed_cb(self, name, old, new):
+ if name != DBUS_SERVICE:
+ return
+
+ if (not old and not len(old)) and (new and len(new)):
+ # ClipboardService started up
+ self._connect_clipboard_signals()
+
+ def _object_added_cb(self, name, mimeType, fileName):
+ self.emit('object-added', name, mimeType, fileName)
- def _object_deleted_cb(self, fileName):
- self.emit('object-deleted', fileName)
+ def _object_deleted_cb(self, fileName):
+ self.emit('object-deleted', fileName)
- def _object_state_changed_cb(self, fileName, percent):
- self.emit('object-state-changed', fileName, percent)
-
- def add_object(self, name, mimeType, fileName):
- self._dbus_service.add_object(name, mimeType, fileName)
+ def _object_state_changed_cb(self, fileName, percent):
+ self.emit('object-state-changed', fileName, percent)
+
+ def add_object(self, name, mimeType, fileName):
+ self._dbus_service.add_object(name, mimeType, fileName)
- def delete_object(self, fileName):
- self._dbus_service.delete_object(fileName)
-
- def set_object_state(self, fileName, percent):
- self._dbus_service.set_object_state(fileName, percent)
+ def delete_object(self, fileName):
+ self._dbus_service.delete_object(fileName)
+
+ def set_object_state(self, fileName, percent):
+ self._dbus_service.set_object_state(fileName, percent)
_clipboard_service = None
def get_instance():
- global _clipboard_service
- if not _clipboard_service:
- _clipboard_service = ClipboardService()
- return _clipboard_service
+ global _clipboard_service
+ if not _clipboard_service:
+ _clipboard_service = ClipboardService()
+ return _clipboard_service
diff --git a/sugar/emulator.py b/sugar/emulator.py
index 638029e..b37dae6 100644
--- a/sugar/emulator.py
+++ b/sugar/emulator.py
@@ -24,108 +24,108 @@ import gobject
from sugar import env
def get_display_number():
- """Find a free display number trying to connect to 6000+ ports"""
- retries = 20
- display_number = 1
- display_is_free = False
-
- while not display_is_free and retries > 0:
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- try:
- s.connect(('127.0.0.1', 6000 + display_number))
- s.close()
-
- display_number += 1
- retries -= 1
- except:
- display_is_free = True
-
- if display_is_free:
- return display_number
- else:
- logging.error('Cannot find a free display.')
- sys.exit(0)
+ """Find a free display number trying to connect to 6000+ ports"""
+ retries = 20
+ display_number = 1
+ display_is_free = False
+
+ while not display_is_free and retries > 0:
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ try:
+ s.connect(('127.0.0.1', 6000 + display_number))
+ s.close()
+
+ display_number += 1
+ retries -= 1
+ except:
+ display_is_free = True
+
+ if display_is_free:
+ return display_number
+ else:
+ logging.error('Cannot find a free display.')
+ sys.exit(0)
class Process:
- """Object representing one of the session processes"""
-
- def __init__(self, command):
- self._command = command
-
- def get_name(self):
- return self._command
-
- def start(self, standard_output=False):
- args = self._command.split()
- flags = gobject.SPAWN_SEARCH_PATH
- result = gobject.spawn_async(args, flags=flags,
- standard_output=standard_output)
- self.pid = result[0]
- self._stdout = result[2]
+ """Object representing one of the session processes"""
+
+ def __init__(self, command):
+ self._command = command
+
+ def get_name(self):
+ return self._command
+
+ def start(self, standard_output=False):
+ args = self._command.split()
+ flags = gobject.SPAWN_SEARCH_PATH
+ result = gobject.spawn_async(args, flags=flags,
+ standard_output=standard_output)
+ self.pid = result[0]
+ self._stdout = result[2]
class MatchboxProcess(Process):
- def __init__(self):
- kbd_config = os.path.join(env.get_data_dir(), 'kbdconfig')
- options = '-kbdconfig %s ' % kbd_config
+ def __init__(self):
+ kbd_config = os.path.join(env.get_data_dir(), 'kbdconfig')
+ options = '-kbdconfig %s ' % kbd_config
- options += '-use_titlebar no '
- options += '-theme olpc '
+ options += '-use_titlebar no '
+ options += '-theme olpc '
- command = 'matchbox-window-manager %s ' % options
- Process.__init__(self, command)
-
- def get_name(self):
- return 'Matchbox'
+ command = 'matchbox-window-manager %s ' % options
+ Process.__init__(self, command)
+
+ def get_name(self):
+ return 'Matchbox'
class XephyrProcess(Process):
- def __init__(self, fullscreen):
- self._display = get_display_number()
- cmd = 'Xephyr :%d -ac ' % (self._display)
- if fullscreen:
- cmd += '-fullscreen '
- else:
- cmd += '-screen 800x600 '
- Process.__init__(self, cmd)
-
- def get_name(self):
- return 'Xephyr'
-
- def start(self):
- Process.start(self)
- os.environ['DISPLAY'] = ":%d" % (self._display)
- os.environ['SUGAR_XEPHYR_PID'] = '%d' % self.pid
+ def __init__(self, fullscreen):
+ self._display = get_display_number()
+ cmd = 'Xephyr :%d -ac ' % (self._display)
+ if fullscreen:
+ cmd += '-fullscreen '
+ else:
+ cmd += '-screen 800x600 '
+ Process.__init__(self, cmd)
+
+ def get_name(self):
+ return 'Xephyr'
+
+ def start(self):
+ Process.start(self)
+ os.environ['DISPLAY'] = ":%d" % (self._display)
+ os.environ['SUGAR_XEPHYR_PID'] = '%d' % self.pid
class XnestProcess(Process):
- def __init__(self):
- self._display = get_display_number()
- cmd = 'Xnest :%d -ac -geometry 800x600' % (self._display)
- Process.__init__(self, cmd)
-
- def get_name(self):
- return 'Xnest'
-
- def start(self):
- Process.start(self)
- os.environ['DISPLAY'] = ":%d" % (self._display)
+ def __init__(self):
+ self._display = get_display_number()
+ cmd = 'Xnest :%d -ac -geometry 800x600' % (self._display)
+ Process.__init__(self, cmd)
+
+ def get_name(self):
+ return 'Xnest'
+
+ def start(self):
+ Process.start(self)
+ os.environ['DISPLAY'] = ":%d" % (self._display)
class Emulator(object):
- """The OLPC emulator"""
- def __init__(self, fullscreen):
- self._fullscreen = fullscreen
-
- def start(self):
- try:
- process = XephyrProcess(self._fullscreen)
- process.start()
- except:
- try:
- process = XnestProcess()
- process.start()
- except:
- print 'Cannot run the emulator. You need to install \
- Xephyr or Xnest.'
- sys.exit(0)
-
- process = MatchboxProcess()
- process.start()
+ """The OLPC emulator"""
+ def __init__(self, fullscreen):
+ self._fullscreen = fullscreen
+
+ def start(self):
+ try:
+ process = XephyrProcess(self._fullscreen)
+ process.start()
+ except:
+ try:
+ process = XnestProcess()
+ process.start()
+ except:
+ print 'Cannot run the emulator. You need to install \
+ Xephyr or Xnest.'
+ sys.exit(0)
+
+ process = MatchboxProcess()
+ process.start()
diff --git a/sugar/env.py b/sugar/env.py
index 7c63731..391c7cd 100644
--- a/sugar/env.py
+++ b/sugar/env.py
@@ -20,43 +20,43 @@ import sys
import pwd
try:
- from sugar.__uninstalled__ import *
+ from sugar.__uninstalled__ import *
except ImportError:
- from sugar.__installed__ import *
+ from sugar.__installed__ import *
def get_profile_path():
- if os.environ.has_key('SUGAR_PROFILE'):
- profile_id = os.environ['SUGAR_PROFILE']
- else:
- profile_id = 'default'
+ if os.environ.has_key('SUGAR_PROFILE'):
+ profile_id = os.environ['SUGAR_PROFILE']
+ else:
+ profile_id = 'default'
- path = os.path.join(os.path.expanduser('~/.sugar'), profile_id)
- if not os.path.isdir(path):
- try:
- os.makedirs(path)
- except OSError, exc:
- print "Could not create user directory."
+ path = os.path.join(os.path.expanduser('~/.sugar'), profile_id)
+ if not os.path.isdir(path):
+ try:
+ os.makedirs(path)
+ except OSError, exc:
+ print "Could not create user directory."
- return path
+ return path
def get_data_dir():
- return sugar_data_dir
+ return sugar_data_dir
def get_services_dir():
- return sugar_services_dir
+ return sugar_services_dir
def get_shell_bin_dir():
- return sugar_shell_bin_dir
+ return sugar_shell_bin_dir
# http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
def get_data_dirs():
- if os.environ.has_key('XDG_DATA_DIRS'):
- return os.environ['XDG_DATA_DIRS'].split(':')
- else:
- return [ '/usr/local/share/', '/usr/share/' ]
+ if os.environ.has_key('XDG_DATA_DIRS'):
+ return os.environ['XDG_DATA_DIRS'].split(':')
+ else:
+ return [ '/usr/local/share/', '/usr/share/' ]
def get_user_service_dir():
- service_dir = os.path.expanduser('~/.local/share/dbus-1/services')
- if not os.path.isdir(service_dir):
- os.makedirs(service_dir)
- return service_dir
+ service_dir = os.path.expanduser('~/.local/share/dbus-1/services')
+ if not os.path.isdir(service_dir):
+ os.makedirs(service_dir)
+ return service_dir
diff --git a/sugar/graphics/ClipboardBubble.py b/sugar/graphics/ClipboardBubble.py
index b94fc26..1947fd5 100644
--- a/sugar/graphics/ClipboardBubble.py
+++ b/sugar/graphics/ClipboardBubble.py
@@ -24,108 +24,108 @@ import gtk
import hippo
class ClipboardBubble(hippo.CanvasBox, hippo.CanvasItem):
- __gtype_name__ = 'ClipboardBubble'
-
- __gproperties__ = {
- 'fill-color': (object, None, None,
- gobject.PARAM_READWRITE),
- 'stroke-color': (object, None, None,
- gobject.PARAM_READWRITE),
- 'progress-color': (object, None, None,
- gobject.PARAM_READWRITE),
- 'percent' : (object, None, None,
- gobject.PARAM_READWRITE),
- }
-
- def __init__(self, **kwargs):
- self._stroke_color = 0xFFFFFFFF
- self._fill_color = 0xFFFFFFFF
- self._progress_color = 0x000000FF
- self._percent = 0
- self._radius = 8
-
- hippo.CanvasBox.__init__(self, **kwargs)
-
- def do_set_property(self, pspec, value):
- if pspec.name == 'fill-color':
- self._fill_color = value
- self.emit_paint_needed(0, 0, -1, -1)
- elif pspec.name == 'stroke-color':
- self._stroke_color = value
- self.emit_paint_needed(0, 0, -1, -1)
- elif pspec.name == 'progress-color':
- self._progress_color = value
- self.emit_paint_needed(0, 0, -1, -1)
- elif pspec.name == 'percent':
- self._percent = value
- self.emit_paint_needed(0, 0, -1, -1)
-
- def do_get_property(self, pspec):
- if pspec.name == 'fill-color':
- return self._fill_color
- elif pspec.name == 'stroke-color':
- return self._stroke_color
- elif pspec.name == 'progress-color':
- return self._progress_color
- elif pspec.name == 'percent':
- return self._percent
-
- def _int_to_rgb(self, int_color):
- red = (int_color >> 24) & 0x000000FF
- green = (int_color >> 16) & 0x000000FF
- blue = (int_color >> 8) & 0x000000FF
- alpha = int_color & 0x000000FF
- return (red / 255.0, green / 255.0, blue / 255.0)
-
- def do_paint_below_children(self, cr, damaged_box):
- [width, height] = self.get_allocation()
-
- line_width = 3.0
- x = line_width
- y = line_width
- width -= line_width * 2
- height -= line_width * 2
-
- self._paint_ellipse(cr, x, y, width, height, self._fill_color)
-
- color = self._int_to_rgb(self._stroke_color)
- cr.set_source_rgb(*color)
- cr.set_line_width(line_width)
- cr.stroke();
-
- self._paint_progress_bar(cr, x, y, width, height, line_width)
-
- def _paint_progress_bar(self, cr, x, y, width, height, line_width):
- prog_x = x + line_width
- prog_y = y + line_width
- prog_width = (width - (line_width * 2)) * (self._percent / 100.0)
- prog_height = (height - (line_width * 2))
-
- self._paint_ellipse(cr, prog_x, prog_y, width, height, self._progress_color)
-
- def _paint_ellipse(self, cr, x, y, width, height, fill_color):
- cr.move_to(x + self._radius, y)
- cr.arc(x + width - self._radius,
- y + self._radius,
- self._radius,
- math.pi * 1.5,
- math.pi * 2)
- cr.arc(x + width - self._radius,
- x + height - self._radius,
- self._radius,
- 0,
- math.pi * 0.5)
- cr.arc(x + self._radius,
- y + height - self._radius,
- self._radius,
- math.pi * 0.5,
- math.pi)
- cr.arc(x + self._radius,
- y + self._radius,
- self._radius,
- math.pi,
- math.pi * 1.5);
-
- color = self._int_to_rgb(fill_color)
- cr.set_source_rgb(*color)
- cr.fill_preserve();
+ __gtype_name__ = 'ClipboardBubble'
+
+ __gproperties__ = {
+ 'fill-color': (object, None, None,
+ gobject.PARAM_READWRITE),
+ 'stroke-color': (object, None, None,
+ gobject.PARAM_READWRITE),
+ 'progress-color': (object, None, None,
+ gobject.PARAM_READWRITE),
+ 'percent' : (object, None, None,
+ gobject.PARAM_READWRITE),
+ }
+
+ def __init__(self, **kwargs):
+ self._stroke_color = 0xFFFFFFFF
+ self._fill_color = 0xFFFFFFFF
+ self._progress_color = 0x000000FF
+ self._percent = 0
+ self._radius = 8
+
+ hippo.CanvasBox.__init__(self, **kwargs)
+
+ def do_set_property(self, pspec, value):
+ if pspec.name == 'fill-color':
+ self._fill_color = value
+ self.emit_paint_needed(0, 0, -1, -1)
+ elif pspec.name == 'stroke-color':
+ self._stroke_color = value
+ self.emit_paint_needed(0, 0, -1, -1)
+ elif pspec.name == 'progress-color':
+ self._progress_color = value
+ self.emit_paint_needed(0, 0, -1, -1)
+ elif pspec.name == 'percent':
+ self._percent = value
+ self.emit_paint_needed(0, 0, -1, -1)
+
+ def do_get_property(self, pspec):
+ if pspec.name == 'fill-color':
+ return self._fill_color
+ elif pspec.name == 'stroke-color':
+ return self._stroke_color
+ elif pspec.name == 'progress-color':
+ return self._progress_color
+ elif pspec.name == 'percent':
+ return self._percent
+
+ def _int_to_rgb(self, int_color):
+ red = (int_color >> 24) & 0x000000FF
+ green = (int_color >> 16) & 0x000000FF
+ blue = (int_color >> 8) & 0x000000FF
+ alpha = int_color & 0x000000FF
+ return (red / 255.0, green / 255.0, blue / 255.0)
+
+ def do_paint_below_children(self, cr, damaged_box):
+ [width, height] = self.get_allocation()
+
+ line_width = 3.0
+ x = line_width
+ y = line_width
+ width -= line_width * 2
+ height -= line_width * 2
+
+ self._paint_ellipse(cr, x, y, width, height, self._fill_color)
+
+ color = self._int_to_rgb(self._stroke_color)
+ cr.set_source_rgb(*color)
+ cr.set_line_width(line_width)
+ cr.stroke();
+
+ self._paint_progress_bar(cr, x, y, width, height, line_width)
+
+ def _paint_progress_bar(self, cr, x, y, width, height, line_width):
+ prog_x = x + line_width
+ prog_y = y + line_width
+ prog_width = (width - (line_width * 2)) * (self._percent / 100.0)
+ prog_height = (height - (line_width * 2))
+
+ self._paint_ellipse(cr, prog_x, prog_y, width, height, self._progress_color)
+
+ def _paint_ellipse(self, cr, x, y, width, height, fill_color):
+ cr.move_to(x + self._radius, y)
+ cr.arc(x + width - self._radius,
+ y + self._radius,
+ self._radius,
+ math.pi * 1.5,
+ math.pi * 2)
+ cr.arc(x + width - self._radius,
+ x + height - self._radius,
+ self._radius,
+ 0,
+ math.pi * 0.5)
+ cr.arc(x + self._radius,
+ y + height - self._radius,
+ self._radius,
+ math.pi * 0.5,
+ math.pi)
+ cr.arc(x + self._radius,
+ y + self._radius,
+ self._radius,
+ math.pi,
+ math.pi * 1.5);
+
+ color = self._int_to_rgb(fill_color)
+ cr.set_source_rgb(*color)
+ cr.fill_preserve();
diff --git a/sugar/graphics/bubble.py b/sugar/graphics/bubble.py
index f5903a0..5bfe87a 100644
--- a/sugar/graphics/bubble.py
+++ b/sugar/graphics/bubble.py
@@ -22,56 +22,56 @@ import gtk
import hippo
class Bubble(hippo.CanvasBox, hippo.CanvasItem):
- __gtype_name__ = 'SugarBubble'
+ __gtype_name__ = 'SugarBubble'
- __gproperties__ = {
- 'color' : (object, None, None,
- gobject.PARAM_READWRITE),
- }
+ __gproperties__ = {
+ 'color' : (object, None, None,
+ gobject.PARAM_READWRITE),
+ }
- def __init__(self, **kwargs):
- self._color = None
- self._radius = 8
+ def __init__(self, **kwargs):
+ self._color = None
+ self._radius = 8
- hippo.CanvasBox.__init__(self, **kwargs)
+ hippo.CanvasBox.__init__(self, **kwargs)
- def do_set_property(self, pspec, value):
- if pspec.name == 'color':
- self._color = value
- self.emit_paint_needed(0, 0, -1, -1)
+ def do_set_property(self, pspec, value):
+ if pspec.name == 'color':
+ self._color = value
+ self.emit_paint_needed(0, 0, -1, -1)
- def do_get_property(self, pspec):
- if pspec.name == 'color':
- return self._color
+ def do_get_property(self, pspec):
+ if pspec.name == 'color':
+ return self._color
- def _string_to_rgb(self, color_string):
- col = gtk.gdk.color_parse(color_string)
- return (col.red / 65535.0, col.green / 65535.0, col.blue / 65535.0)
+ def _string_to_rgb(self, color_string):
+ col = gtk.gdk.color_parse(color_string)
+ return (col.red / 65535.0, col.green / 65535.0, col.blue / 65535.0)
- def do_paint_below_children(self, cr, damaged_box):
- [width, height] = self.get_allocation()
+ def do_paint_below_children(self, cr, damaged_box):
+ [width, height] = self.get_allocation()
- line_width = 3.0
- x = line_width
- y = line_width
- width -= line_width * 2
- height -= line_width * 2
+ line_width = 3.0
+ x = line_width
+ y = line_width
+ width -= line_width * 2
+ height -= line_width * 2
- cr.move_to(x + self._radius, y);
- cr.arc(x + width - self._radius, y + self._radius,
- self._radius, math.pi * 1.5, math.pi * 2);
- cr.arc(x + width - self._radius, x + height - self._radius,
- self._radius, 0, math.pi * 0.5);
- cr.arc(x + self._radius, y + height - self._radius,
- self._radius, math.pi * 0.5, math.pi);
- cr.arc(x + self._radius, y + self._radius, self._radius,
- math.pi, math.pi * 1.5);
+ cr.move_to(x + self._radius, y);
+ cr.arc(x + width - self._radius, y + self._radius,
+ self._radius, math.pi * 1.5, math.pi * 2);
+ cr.arc(x + width - self._radius, x + height - self._radius,
+ self._radius, 0, math.pi * 0.5);
+ cr.arc(x + self._radius, y + height - self._radius,
+ self._radius, math.pi * 0.5, math.pi);
+ cr.arc(x + self._radius, y + self._radius, self._radius,
+ math.pi, math.pi * 1.5);
- color = self._string_to_rgb(self._color.get_fill_color())
- cr.set_source_rgb(*color)
- cr.fill_preserve();
+ color = self._string_to_rgb(self._color.get_fill_color())
+ cr.set_source_rgb(*color)
+ cr.fill_preserve();
- color = self._string_to_rgb(self._color.get_stroke_color())
- cr.set_source_rgb(*color)
- cr.set_line_width(line_width)
- cr.stroke();
+ color = self._string_to_rgb(self._color.get_stroke_color())
+ cr.set_source_rgb(*color)
+ cr.set_line_width(line_width)
+ cr.stroke();
diff --git a/sugar/graphics/canvasicon.py b/sugar/graphics/canvasicon.py
index da3d8ca..06aff7b 100644
--- a/sugar/graphics/canvasicon.py
+++ b/sugar/graphics/canvasicon.py
@@ -26,133 +26,133 @@ import cairo
from sugar.graphics.iconcolor import IconColor
class _IconCache:
- def __init__(self):
- self._icons = {}
- self._theme = gtk.icon_theme_get_default()
+ def __init__(self):
+ self._icons = {}
+ self._theme = gtk.icon_theme_get_default()
- def _read_icon(self, filename, color):
- icon_file = open(filename, 'r')
+ def _read_icon(self, filename, color):
+ icon_file = open(filename, 'r')
- if color == None:
- return rsvg.Handle(file=filename)
- else:
- data = icon_file.read()
- icon_file.close()
+ if color == None:
+ return rsvg.Handle(file=filename)
+ else:
+ data = icon_file.read()
+ icon_file.close()
- fill = color.get_fill_color()
- stroke = color.get_stroke_color()
-
- entity = '<!ENTITY fill_color "%s">' % fill
- data = re.sub('<!ENTITY fill_color .*>', entity, data)
+ fill = color.get_fill_color()
+ stroke = color.get_stroke_color()
+
+ entity = '<!ENTITY fill_color "%s">' % fill
+ data = re.sub('<!ENTITY fill_color .*>', entity, data)
- entity = '<!ENTITY stroke_color "%s">' % stroke
- data = re.sub('<!ENTITY stroke_color .*>', entity, data)
+ entity = '<!ENTITY stroke_color "%s">' % stroke
+ data = re.sub('<!ENTITY stroke_color .*>', entity, data)
- return rsvg.Handle(data=data)
+ return rsvg.Handle(data=data)
- def get_handle(self, name, color, size):
- info = self._theme.lookup_icon(name, int(size), 0)
+ def get_handle(self, name, color, size):
+ info = self._theme.lookup_icon(name, int(size), 0)
- if color:
- key = (info.get_filename(), color.to_string())
- else:
- key = info.get_filename()
+ if color:
+ key = (info.get_filename(), color.to_string())
+ else:
+ key = info.get_filename()
- if self._icons.has_key(key):
- icon = self._icons[key]
- else:
- icon = self._read_icon(info.get_filename(), color)
- self._icons[key] = icon
- return icon
+ if self._icons.has_key(key):
+ icon = self._icons[key]
+ else:
+ icon = self._read_icon(info.get_filename(), color)
+ self._icons[key] = icon
+ return icon
class CanvasIcon(hippo.CanvasBox, hippo.CanvasItem):
- __gtype_name__ = 'CanvasIcon'
-
- __gproperties__ = {
- 'icon-name': (str, None, None, None,
- gobject.PARAM_READWRITE),
- 'color' : (object, None, None,
- gobject.PARAM_READWRITE),
- 'size' : (int, None, None,
- 0, 1024, 24,
- gobject.PARAM_READWRITE)
- }
-
- _cache = _IconCache()
-
- def __init__(self, **kwargs):
- self._size = 24
- self._color = None
- self._icon_name = None
-
- hippo.CanvasBox.__init__(self, **kwargs)
-
- self._buffer = None
-
- self.connect('button-press-event', self._button_press_event_cb)
-
- def do_set_property(self, pspec, value):
- if pspec.name == 'icon-name':
- self._icon_name = value
- self._buffer = None
- self.emit_paint_needed(0, 0, -1, -1)
- elif pspec.name == 'color':
- self._buffer = None
- self._color = value
- self.emit_paint_needed(0, 0, -1, -1)
- elif pspec.name == 'size':
- self._buffer = None
- self._size = value
- self.emit_request_changed()
-
- def do_get_property(self, pspec):
- if pspec.name == 'size':
- return self._size
- elif pspec.name == 'icon-name':
- return self._icon_name
- elif pspec.name == 'color':
- return self._color
-
- def _get_buffer(self, cr, handle, size):
- if self._buffer == None:
- target = cr.get_target()
- surface = target.create_similar(cairo.CONTENT_COLOR_ALPHA,
- int(size) + 1, int(size) + 1)
-
- dimensions = handle.get_dimension_data()
- scale = float(size) / float(dimensions[0])
-
- ctx = cairo.Context(surface)
- ctx.scale(scale, scale)
- handle.render_cairo(ctx)
- del ctx
-
- self._buffer = surface
- self._buffer_scale = scale
-
- return self._buffer
-
- def do_paint_below_children(self, cr, damaged_box):
- icon_name = self._icon_name
- if icon_name == None:
- icon_name = 'stock-missing'
-
- handle = CanvasIcon._cache.get_handle(
- icon_name, self._color, self._size)
- buf = self._get_buffer(cr, handle, self._size)
-
- [width, height] = self.get_allocation()
- x = (width - self._size) / 2
- y = (height - self._size) / 2
-
- cr.set_source_surface(buf, x, y)
- cr.paint()
-
- def do_get_width_request(self):
- return self._size
-
- def do_get_height_request(self, for_width):
- return self._size
-
- def _button_press_event_cb(self, item, event):
- item.emit_activated()
+ __gtype_name__ = 'CanvasIcon'
+
+ __gproperties__ = {
+ 'icon-name': (str, None, None, None,
+ gobject.PARAM_READWRITE),
+ 'color' : (object, None, None,
+ gobject.PARAM_READWRITE),
+ 'size' : (int, None, None,
+ 0, 1024, 24,
+ gobject.PARAM_READWRITE)
+ }
+
+ _cache = _IconCache()
+
+ def __init__(self, **kwargs):
+ self._size = 24
+ self._color = None
+ self._icon_name = None
+
+ hippo.CanvasBox.__init__(self, **kwargs)
+
+ self._buffer = None
+
+ self.connect('button-press-event', self._button_press_event_cb)
+
+ def do_set_property(self, pspec, value):
+ if pspec.name == 'icon-name':
+ self._icon_name = value
+ self._buffer = None
+ self.emit_paint_needed(0, 0, -1, -1)
+ elif pspec.name == 'color':
+ self._buffer = None
+ self._color = value
+ self.emit_paint_needed(0, 0, -1, -1)
+ elif pspec.name == 'size':
+ self._buffer = None
+ self._size = value
+ self.emit_request_changed()
+
+ def do_get_property(self, pspec):
+ if pspec.name == 'size':
+ return self._size
+ elif pspec.name == 'icon-name':
+ return self._icon_name
+ elif pspec.name == 'color':
+ return self._color
+
+ def _get_buffer(self, cr, handle, size):
+ if self._buffer == None:
+ target = cr.get_target()
+ surface = target.create_similar(cairo.CONTENT_COLOR_ALPHA,
+ int(size) + 1, int(size) + 1)
+
+ dimensions = handle.get_dimension_data()
+ scale = float(size) / float(dimensions[0])
+
+ ctx = cairo.Context(surface)
+ ctx.scale(scale, scale)
+ handle.render_cairo(ctx)
+ del ctx
+
+ self._buffer = surface
+ self._buffer_scale = scale
+
+ return self._buffer
+
+ def do_paint_below_children(self, cr, damaged_box):
+ icon_name = self._icon_name
+ if icon_name == None:
+ icon_name = 'stock-missing'
+
+ handle = CanvasIcon._cache.get_handle(
+ icon_name, self._color, self._size)
+ buf = self._get_buffer(cr, handle, self._size)
+
+ [width, height] = self.get_allocation()
+ x = (width - self._size) / 2
+ y = (height - self._size) / 2
+
+ cr.set_source_surface(buf, x, y)
+ cr.paint()
+
+ def do_get_width_request(self):
+ return self._size
+
+ def do_get_height_request(self, for_width):
+ return self._size
+
+ def _button_press_event_cb(self, item, event):
+ item.emit_activated()
diff --git a/sugar/graphics/grid.py b/sugar/graphics/grid.py
index 350b4ec..cfbdf67 100644
--- a/sugar/graphics/grid.py
+++ b/sugar/graphics/grid.py
@@ -21,19 +21,19 @@ COLS = 16
ROWS = 12
class Grid(object):
- def __init__(self):
- self._factor = gtk.gdk.screen_width() / COLS
+ def __init__(self):
+ self._factor = gtk.gdk.screen_width() / COLS
- def point(self, grid_x, grid_y):
- return [grid_x * self._factor, grid_y * self._factor]
+ def point(self, grid_x, grid_y):
+ return [grid_x * self._factor, grid_y * self._factor]
- def rectangle(self, grid_x, grid_y, grid_w, grid_h):
- return [grid_x * self._factor, grid_y * self._factor,
- grid_w * self._factor, grid_h * self._factor]
+ def rectangle(self, grid_x, grid_y, grid_w, grid_h):
+ return [grid_x * self._factor, grid_y * self._factor,
+ grid_w * self._factor, grid_h * self._factor]
- def dimension(self, grid_dimension):
- return grid_dimension * self._factor
+ def dimension(self, grid_dimension):
+ return grid_dimension * self._factor
- def fit_point(self, x, y):
- return [int(x / self._factor), int(y / self._factor)]
-
+ def fit_point(self, x, y):
+ return [int(x / self._factor), int(y / self._factor)]
+
diff --git a/sugar/graphics/iconcolor.py b/sugar/graphics/iconcolor.py
index d736d54..71dfe18 100644
--- a/sugar/graphics/iconcolor.py
+++ b/sugar/graphics/iconcolor.py
@@ -20,32 +20,32 @@ import random
from sugar.graphics.colors import colors
def _parse_string(color_string):
- if color_string == 'white':
- return ['#ffffff', '#414141']
+ if color_string == 'white':
+ return ['#ffffff', '#414141']
- splitted = color_string.split(',')
- if len(splitted) == 2:
- return [splitted[0], splitted[1]]
- else:
- return None
+ splitted = color_string.split(',')
+ if len(splitted) == 2:
+ return [splitted[0], splitted[1]]
+ else:
+ return None
def is_valid(color_string):
- return (_parse_string(color_string) != None)
+ return (_parse_string(color_string) != None)
class IconColor:
- def __init__(self, color_string=None):
- if color_string == None or not is_valid(color_string):
- n = int(random.random() * (len(colors) - 1))
- [self._stroke, self._fill] = colors[n]
- else:
- [self._stroke, self._fill] = _parse_string(color_string)
+ def __init__(self, color_string=None):
+ if color_string == None or not is_valid(color_string):
+ n = int(random.random() * (len(colors) - 1))
+ [self._stroke, self._fill] = colors[n]
+ else:
+ [self._stroke, self._fill] = _parse_string(color_string)
- def get_stroke_color(self):
- return self._stroke
+ def get_stroke_color(self):
+ return self._stroke
- def get_fill_color(self):
- return self._fill
+ def get_fill_color(self):
+ return self._fill
- def to_string(self):
- return '%s,%s' % (self._stroke, self._fill)
+ def to_string(self):
+ return '%s,%s' % (self._stroke, self._fill)
diff --git a/sugar/graphics/menu.py b/sugar/graphics/menu.py
index 508dbb0..5b68d61 100644
--- a/sugar/graphics/menu.py
+++ b/sugar/graphics/menu.py
@@ -23,85 +23,85 @@ from sugar.graphics.canvasicon import CanvasIcon
from sugar.graphics import style
class Menu(gtk.Window):
- __gsignals__ = {
- 'action': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([int])),
- }
+ __gsignals__ = {
+ 'action': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([int])),
+ }
- def __init__(self, title=None, content_box=None):
- gtk.Window.__init__(self, gtk.WINDOW_POPUP)
+ def __init__(self, title=None, content_box=None):
+ gtk.Window.__init__(self, gtk.WINDOW_POPUP)
- canvas = hippo.Canvas()
- self.add(canvas)
- canvas.show()
+ canvas = hippo.Canvas()
+ self.add(canvas)
+ canvas.show()
- self._root = hippo.CanvasBox()
- style.apply_stylesheet(self._root, 'menu')
- canvas.set_root(self._root)
+ self._root = hippo.CanvasBox()
+ style.apply_stylesheet(self._root, 'menu')
+ canvas.set_root(self._root)
- if title:
- self._title_item = hippo.CanvasText(text=title)
- style.apply_stylesheet(self._title_item, 'menu.Title')
- self._root.append(self._title_item)
- else:
- self._title_item = None
+ if title:
+ self._title_item = hippo.CanvasText(text=title)
+ style.apply_stylesheet(self._title_item, 'menu.Title')
+ self._root.append(self._title_item)
+ else:
+ self._title_item = None
- if content_box:
- separator = self._create_separator()
- self._root.append(separator)
- self._root.append(content_box)
+ if content_box:
+ separator = self._create_separator()
+ self._root.append(separator)
+ self._root.append(content_box)
- self._action_box = None
- self._item_box = None
+ self._action_box = None
+ self._item_box = None
- def _create_separator(self):
- separator = hippo.CanvasBox()
- style.apply_stylesheet(separator, 'menu.Separator')
- return separator
+ def _create_separator(self):
+ separator = hippo.CanvasBox()
+ style.apply_stylesheet(separator, 'menu.Separator')
+ return separator
- def _create_item_box(self):
- if self._title_item:
- separator = self._create_separator()
- self._root.append(separator)
+ def _create_item_box(self):
+ if self._title_item:
+ separator = self._create_separator()
+ self._root.append(separator)
- self._item_box = hippo.CanvasBox(
- orientation=hippo.ORIENTATION_VERTICAL)
- self._root.append(self._item_box)
+ self._item_box = hippo.CanvasBox(
+ orientation=hippo.ORIENTATION_VERTICAL)
+ self._root.append(self._item_box)
- def _create_action_box(self):
- separator = self._create_separator()
- self._root.append(separator)
+ def _create_action_box(self):
+ separator = self._create_separator()
+ self._root.append(separator)
- self._action_box = hippo.CanvasBox(
- orientation=hippo.ORIENTATION_HORIZONTAL)
- self._root.append(self._action_box)
+ self._action_box = hippo.CanvasBox(
+ orientation=hippo.ORIENTATION_HORIZONTAL)
+ self._root.append(self._action_box)
- def add_item(self, label, action_id):
- if not self._item_box:
- self._create_item_box()
+ def add_item(self, label, action_id):
+ if not self._item_box:
+ self._create_item_box()
- text = hippo.CanvasText(text=label)
- style.apply_stylesheet(text, 'menu.Item')
+ text = hippo.CanvasText(text=label)
+ style.apply_stylesheet(text, 'menu.Item')
- # FIXME need a way to make hippo items activable in python
- text.connect('button-press-event', self._item_clicked_cb, action_id)
- #text.connect('activated', self._action_clicked_cb, action_id)
+ # FIXME need a way to make hippo items activable in python
+ text.connect('button-press-event', self._item_clicked_cb, action_id)
+ #text.connect('activated', self._action_clicked_cb, action_id)
- self._item_box.append(text)
+ self._item_box.append(text)
- def add_action(self, icon, action_id):
- if not self._action_box:
- self._create_action_box()
+ def add_action(self, icon, action_id):
+ if not self._action_box:
+ self._create_action_box()
- style.apply_stylesheet(icon, 'menu.ActionIcon')
- icon.connect('activated', self._action_clicked_cb, action_id)
- self._action_box.append(icon)
+ style.apply_stylesheet(icon, 'menu.ActionIcon')
+ icon.connect('activated', self._action_clicked_cb, action_id)
+ self._action_box.append(icon)
- def remove_action(self, icon):
- self._action_box.remove(icon)
+ def remove_action(self, icon):
+ self._action_box.remove(icon)
- def _item_clicked_cb(self, icon, event, action):
- self.emit('action', action)
+ def _item_clicked_cb(self, icon, event, action):
+ self.emit('action', action)
- def _action_clicked_cb(self, icon, action):
- self.emit('action', action)
+ def _action_clicked_cb(self, icon, action):
+ self.emit('action', action)
diff --git a/sugar/graphics/menuicon.py b/sugar/graphics/menuicon.py
index 8c0041e..62d1275 100644
--- a/sugar/graphics/menuicon.py
+++ b/sugar/graphics/menuicon.py
@@ -23,58 +23,58 @@ from sugar.graphics.canvasicon import CanvasIcon
from sugar.graphics.timeline import Timeline
class MenuIcon(CanvasIcon):
- def __init__(self, menu_shell, **kwargs):
- CanvasIcon.__init__(self, **kwargs)
+ def __init__(self, menu_shell, **kwargs):
+ CanvasIcon.__init__(self, **kwargs)
- self._menu_shell = menu_shell
- self._menu = None
- self._hover_menu = False
+ self._menu_shell = menu_shell
+ self._menu = None
+ self._hover_menu = False
- self._timeline = Timeline(self)
- self._timeline.add_tag('popup', 6, 6)
- self._timeline.add_tag('before_popdown', 7, 7)
- self._timeline.add_tag('popdown', 8, 8)
+ self._timeline = Timeline(self)
+ self._timeline.add_tag('popup', 6, 6)
+ self._timeline.add_tag('before_popdown', 7, 7)
+ self._timeline.add_tag('popdown', 8, 8)
- self.connect('motion-notify-event', self._motion_notify_event_cb)
+ self.connect('motion-notify-event', self._motion_notify_event_cb)
- def do_popup(self, current, n_frames):
- if self._menu:
- return
+ def do_popup(self, current, n_frames):
+ if self._menu:
+ return
- self._menu = self.create_menu()
+ self._menu = self.create_menu()
- self._menu.connect('enter-notify-event',
- self._menu_enter_notify_event_cb)
- self._menu.connect('leave-notify-event',
- self._menu_leave_notify_event_cb)
+ self._menu.connect('enter-notify-event',
+ self._menu_enter_notify_event_cb)
+ self._menu.connect('leave-notify-event',
+ self._menu_leave_notify_event_cb)
- [x, y] = self._menu_shell.get_position(self._menu, self)
+ [x, y] = self._menu_shell.get_position(self._menu, self)
- self._menu.move(x, y)
- self._menu.show()
+ self._menu.move(x, y)
+ self._menu.show()
- self._menu_shell.set_active(self)
+ self._menu_shell.set_active(self)
- def do_popdown(self, current, frame):
- if self._menu:
- self._menu.destroy()
- self._menu = None
- self._menu_shell.set_active(None)
+ def do_popdown(self, current, frame):
+ if self._menu:
+ self._menu.destroy()
+ self._menu = None
+ self._menu_shell.set_active(None)
- def popdown(self):
- self._timeline.play('popdown', 'popdown')
+ def popdown(self):
+ self._timeline.play('popdown', 'popdown')
- def _motion_notify_event_cb(self, item, event):
- if event.detail == hippo.MOTION_DETAIL_ENTER:
- self._timeline.play(None, 'popup')
- elif event.detail == hippo.MOTION_DETAIL_LEAVE:
- if not self._hover_menu:
- self._timeline.play('before_popdown', 'popdown')
+ def _motion_notify_event_cb(self, item, event):
+ if event.detail == hippo.MOTION_DETAIL_ENTER:
+ self._timeline.play(None, 'popup')
+ elif event.detail == hippo.MOTION_DETAIL_LEAVE:
+ if not self._hover_menu:
+ self._timeline.play('before_popdown', 'popdown')
- def _menu_enter_notify_event_cb(self, widget, event):
- self._hover_menu = True
- self._timeline.play('popup', 'popup')
+ def _menu_enter_notify_event_cb(self, widget, event):
+ self._hover_menu = True
+ self._timeline.play('popup', 'popup')
- def _menu_leave_notify_event_cb(self, widget, event):
- self._hover_menu = False
- self._timeline.play('popdown', 'popdown')
+ def _menu_leave_notify_event_cb(self, widget, event):
+ self._hover_menu = False
+ self._timeline.play('popdown', 'popdown')
diff --git a/sugar/graphics/menushell.py b/sugar/graphics/menushell.py
index 48183e1..61b98b0 100644
--- a/sugar/graphics/menushell.py
+++ b/sugar/graphics/menushell.py
@@ -19,83 +19,83 @@ import gobject
import gtk
class MenuShell(gobject.GObject):
- __gsignals__ = {
- 'activated': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([])),
- 'deactivated': (gobject.SIGNAL_RUN_FIRST,
- gobject.TYPE_NONE, ([])),
- }
-
- AUTO = 0
- LEFT = 1
- RIGHT = 2
- TOP = 3
- BOTTOM = 4
-
- def __init__(self, parent_canvas):
- gobject.GObject.__init__(self)
-
- self._parent_canvas = parent_canvas
- self._menu_controller = None
- self._position = MenuShell.AUTO
-
- def set_position(self, position):
- self._position = position
-
- def is_active(self):
- return (self._menu_controller != None)
-
- def set_active(self, controller):
- if controller == None:
- self.emit('deactivated')
- else:
- self.emit('activated')
-
- if self._menu_controller:
- self._menu_controller.popdown()
- self._menu_controller = controller
-
- def _get_item_rect(self, item):
- [x, y] = item.get_context().translate_to_widget(item)
-
- [origin_x, origin_y] = self._parent_canvas.window.get_origin()
- x += origin_x
- y += origin_y
-
- [w, h] = item.get_allocation()
-
- return [x, y, w, h]
-
- def get_position(self, menu, item):
- [item_x, item_y, item_w, item_h] = self._get_item_rect(item)
- [menu_w, menu_h] = menu.size_request()
-
- left_x = item_x - menu_w
- left_y = item_y
- right_x = item_x + item_w
- right_y = item_y
- top_x = item_x
- top_y = item_y - menu_h
- bottom_x = item_x
- bottom_y = item_y + item_h
-
- if self._position == MenuShell.LEFT:
- [x, y] = [left_x, left_y]
- elif self._position == MenuShell.RIGHT:
- [x, y] = [right_x, right_y]
- elif self._position == MenuShell.TOP:
- [x, y] = [top_x, top_y]
- elif self._position == MenuShell.BOTTOM:
- [x, y] = [bottom_x, bottom_y]
- elif self._position == MenuShell.AUTO:
- [x, y] = [right_x, right_y]
- if x + menu_w > gtk.gdk.screen_width():
- [x, y] = [left_x, left_y]
-
- x = min(x, gtk.gdk.screen_width() - menu_w)
- x = max(0, x)
-
- y = min(y, gtk.gdk.screen_height() - menu_h)
- y = max(0, y)
-
- return [x, y]
+ __gsignals__ = {
+ 'activated': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([])),
+ 'deactivated': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE, ([])),
+ }
+
+ AUTO = 0
+ LEFT = 1
+ RIGHT = 2
+ TOP = 3
+ BOTTOM = 4
+
+ def __init__(self, parent_canvas):
+ gobject.GObject.__init__(self)
+
+ self._parent_canvas = parent_canvas
+ self._menu_controller = None
+ self._position = MenuShell.AUTO
+
+ def set_position(self, position):
+ self._position = position
+
+ def is_active(self):
+ return (self._menu_controller != None)
+
+ def set_active(self, controller):
+ if controller == None:
+ self.emit('deactivated')
+ else:
+ self.emit('activated')
+
+ if self._menu_controller:
+ self._menu_controller.popdown()
+ self._menu_controller = controller
+
+ def _get_item_rect(self, item):
+ [x, y] = item.get_context().translate_to_widget(item)
+
+ [origin_x, origin_y] = self._parent_canvas.window.get_origin()
+ x += origin_x
+ y += origin_y
+
+ [w, h] = item.get_allocation()
+
+ return [x, y, w, h]
+
+ def get_position(self, menu, item):
+ [item_x, item_y, item_w, item_h] = self._get_item_rect(item)
+ [menu_w, menu_h] = menu.size_request()
+
+ left_x = item_x - menu_w
+ left_y = item_y
+ right_x = item_x + item_w
+ right_y = item_y
+ top_x = item_x
+ top_y = item_y - menu_h
+ bottom_x = item_x
+ bottom_y = item_y + item_h
+
+ if self._position == MenuShell.LEFT:
+ [x, y] = [left_x, left_y]
+ elif self._position == MenuShell.RIGHT:
+ [x, y] = [right_x, right_y]
+ elif self._position == MenuShell.TOP:
+ [x, y] = [top_x, top_y]
+ elif self._position == MenuShell.BOTTOM:
+ [x, y] = [bottom_x, bottom_y]
+ elif self._position == MenuShell.AUTO:
+ [x, y] = [right_x, right_y]
+ if x + menu_w > gtk.gdk.screen_width():
+ [x, y] = [left_x, left_y]
+
+ x = min(x, gtk.gdk.screen_width() - menu_w)
+ x = max(0, x)
+
+ y = min(y, gtk.gdk.screen_height() - menu_h)
+ y = max(0, y)
+
+ return [x, y]
diff --git a/sugar/graphics/snowflakebox.py b/sugar/graphics/snowflakebox.py
index 2af11cd..30f5b05 100644
--- a/sugar/graphics/snowflakebox.py
+++ b/sugar/graphics/snowflakebox.py
@@ -25,72 +25,72 @@ _CHILDREN_FACTOR = 1
_FLAKE_DISTANCE = 6
class SnowflakeBox(hippo.CanvasBox, hippo.CanvasItem):
- __gtype_name__ = 'SugarSnowflakeBox'
- def __init__(self, **kwargs):
- hippo.CanvasBox.__init__(self, **kwargs)
- self._root = None
+ __gtype_name__ = 'SugarSnowflakeBox'
+ def __init__(self, **kwargs):
+ hippo.CanvasBox.__init__(self, **kwargs)
+ self._root = None
- def set_root(self, icon):
- self._root = icon
+ def set_root(self, icon):
+ self._root = icon
- def _get_center(self):
- [width, height] = self.get_allocation()
- return [width / 2, height / 2]
+ def _get_center(self):
+ [width, height] = self.get_allocation()
+ return [width / 2, height / 2]
- def _get_radius(self):
- return _BASE_RADIUS + _CHILDREN_FACTOR * self._get_n_children()
+ def _get_radius(self):
+ return _BASE_RADIUS + _CHILDREN_FACTOR * self._get_n_children()
- def _layout_root(self):
- [width, height] = self._root.get_allocation()
- [cx, cy] = self._get_center()
+ def _layout_root(self):
+ [width, height] = self._root.get_allocation()
+ [cx, cy] = self._get_center()
- x = cx - (width / 2)
- y = cy - (height / 2)
+ x = cx - (width / 2)
+ y = cy - (height / 2)
- self.move(self._root, int(x), int(y))
+ self.move(self._root, int(x), int(y))
- def _get_n_children(self):
- return len(self.get_children()) - 1
+ def _get_n_children(self):
+ return len(self.get_children()) - 1
- def _layout_child(self, child, index):
- r = self._get_radius()
- if (self._get_n_children() > 10):
- r += _FLAKE_DISTANCE * (index % 3)
+ def _layout_child(self, child, index):
+ r = self._get_radius()
+ if (self._get_n_children() > 10):
+ r += _FLAKE_DISTANCE * (index % 3)
- angle = 2 * math.pi * index / self._get_n_children()
+ angle = 2 * math.pi * index / self._get_n_children()
- [width, height] = child.get_allocation()
- [cx, cy] = self._get_center()
+ [width, height] = child.get_allocation()
+ [cx, cy] = self._get_center()
- x = cx + math.cos(angle) * r - (width / 2)
- y = cy + math.sin(angle) * r - (height / 2)
+ x = cx + math.cos(angle) * r - (width / 2)
+ y = cy + math.sin(angle) * r - (height / 2)
- self.move(child, int(x), int(y))
+ self.move(child, int(x), int(y))
- def do_get_width_request(self):
- hippo.CanvasBox.do_get_width_request(self)
+ def do_get_width_request(self):
+ hippo.CanvasBox.do_get_width_request(self)
- max_child_size = 0
- for child in self.get_children():
- width = child.get_width_request()
- height = child.get_height_request(width)
- max_child_size = max (max_child_size, width)
- max_child_size = max (max_child_size, height)
+ max_child_size = 0
+ for child in self.get_children():
+ width = child.get_width_request()
+ height = child.get_height_request(width)
+ max_child_size = max (max_child_size, width)
+ max_child_size = max (max_child_size, height)
- return self._get_radius() * 2 + \
- max_child_size + _FLAKE_DISTANCE * 2
+ return self._get_radius() * 2 + \
+ max_child_size + _FLAKE_DISTANCE * 2
- def do_get_height_request(self, width):
- hippo.CanvasBox.do_get_height_request(self, width)
- return width
+ def do_get_height_request(self, width):
+ hippo.CanvasBox.do_get_height_request(self, width)
+ return width
- def do_allocate(self, width, height):
- hippo.CanvasBox.do_allocate(self, width, height)
+ def do_allocate(self, width, height):
+ hippo.CanvasBox.do_allocate(self, width, height)
- self._layout_root()
+ self._layout_root()
- index = 0
- for child in self.get_children():
- if child != self._root:
- self._layout_child(child, index)
- index += 1
+ index = 0
+ for child in self.get_children():
+ if child != self._root:
+ self._layout_child(child, index)
+ index += 1
diff --git a/sugar/graphics/spreadbox.py b/sugar/graphics/spreadbox.py
index 7d4047d..59dfe9c 100644
--- a/sugar/graphics/spreadbox.py
+++ b/sugar/graphics/spreadbox.py
@@ -25,108 +25,108 @@ _DISTANCE_THRESHOLD = 10.0
_FORCE_CONSTANT = 0.1
class SpreadBox(hippo.CanvasBox, hippo.CanvasItem):
- __gtype_name__ = 'SugarSpreadBox'
+ __gtype_name__ = 'SugarSpreadBox'
- def __init__(self, **kwargs):
- hippo.CanvasBox.__init__(self, **kwargs)
+ def __init__(self, **kwargs):
+ hippo.CanvasBox.__init__(self, **kwargs)
- self._items_to_position = []
- self._stable = False
+ self._items_to_position = []
+ self._stable = False
- def add_item(self, item):
- self._items_to_position.append(item)
- self.append(item, hippo.PACK_FIXED)
+ def add_item(self, item):
+ self._items_to_position.append(item)
+ self.append(item, hippo.PACK_FIXED)
- def remove_item(self, item):
- if self._items_to_position.count(item) > 0:
- self._items_to_position.remove(item)
- self.remove(item)
+ def remove_item(self, item):
+ if self._items_to_position.count(item) > 0:
+ self._items_to_position.remove(item)
+ self.remove(item)
- def _get_item_radius(self, item):
- [width, height] = item.get_request()
- return math.sqrt(width ** 2 + height ** 2) / 2
+ def _get_item_radius(self, item):
+ [width, height] = item.get_request()
+ return math.sqrt(width ** 2 + height ** 2) / 2
- def _get_item_center(self, item):
- [width, height] = item.get_request()
- [x, y] = self.get_position(item)
+ def _get_item_center(self, item):
+ [width, height] = item.get_request()
+ [x, y] = self.get_position(item)
- c_x = int(x + float(width) / 2.0)
- c_y = int(y + float(height) / 2.0)
+ c_x = int(x + float(width) / 2.0)
+ c_y = int(y + float(height) / 2.0)
- return [c_x, c_y]
+ return [c_x, c_y]
- def _get_repulsion(self, icon1, icon2):
- [c1_x, c1_y] = self._get_item_center(icon1)
- [c2_x, c2_y] = self._get_item_center(icon2)
+ def _get_repulsion(self, icon1, icon2):
+ [c1_x, c1_y] = self._get_item_center(icon1)
+ [c2_x, c2_y] = self._get_item_center(icon2)
- a = c2_x - c1_x
- b = c2_y - c1_y
+ a = c2_x - c1_x
+ b = c2_y - c1_y
- r1 = self._get_item_radius(icon1)
- r2 = self._get_item_radius(icon2)
- distance = math.sqrt(a ** 2 + b ** 2) - r1 - r2
+ r1 = self._get_item_radius(icon1)
+ r2 = self._get_item_radius(icon2)
+ distance = math.sqrt(a ** 2 + b ** 2) - r1 - r2
- if distance < _DISTANCE_THRESHOLD:
- f_x = int(math.ceil(-_FORCE_CONSTANT * float(a)))
- f_y = int(math.ceil(-_FORCE_CONSTANT * float(b)))
- else:
- f_x = 0
- f_y = 0
+ if distance < _DISTANCE_THRESHOLD:
+ f_x = int(math.ceil(-_FORCE_CONSTANT * float(a)))
+ f_y = int(math.ceil(-_FORCE_CONSTANT * float(b)))
+ else:
+ f_x = 0
+ f_y = 0
- return [f_x, f_y]
+ return [f_x, f_y]
- def _clamp_position(self, icon, x, y):
- x = max(0, x)
- y = max(0, y)
+ def _clamp_position(self, icon, x, y):
+ x = max(0, x)
+ y = max(0, y)
- [item_w, item_h] = icon.get_request()
- [box_w, box_h] = self.get_allocation()
+ [item_w, item_h] = icon.get_request()
+ [box_w, box_h] = self.get_allocation()
- x = min(box_w - item_w, x)
- y = min(box_h - item_h, y)
+ x = min(box_w - item_w, x)
+ y = min(box_h - item_h, y)
- return [x, y]
+ return [x, y]
- def _spread_icons(self):
- self._stable = True
+ def _spread_icons(self):
+ self._stable = True
- for icon1 in self.get_children():
- vx = 0
- vy = 0
+ for icon1 in self.get_children():
+ vx = 0
+ vy = 0
- for icon2 in self.get_children():
- if icon1 != icon2:
- [f_x, f_y] = self._get_repulsion(icon1, icon2)
- if f_x != 0 or f_y != 0:
- self._stable = False
- vx += f_x
- vy += f_y
+ for icon2 in self.get_children():
+ if icon1 != icon2:
+ [f_x, f_y] = self._get_repulsion(icon1, icon2)
+ if f_x != 0 or f_y != 0:
+ self._stable = False
+ vx += f_x
+ vy += f_y
- if vx != 0 or vy != 0:
- [x, y] = self.get_position(icon1)
- new_x = x + vx
- new_y = y + vy
+ if vx != 0 or vy != 0:
+ [x, y] = self.get_position(icon1)
+ new_x = x + vx
+ new_y = y + vy
- [new_x, new_y] = self._clamp_position(icon1, new_x, new_y)
+ [new_x, new_y] = self._clamp_position(icon1, new_x, new_y)
- self.move(icon1, new_x, new_y)
+ self.move(icon1, new_x, new_y)
- def do_allocate(self, width, height):
- hippo.CanvasBox.do_allocate(self, width, height)
+ def do_allocate(self, width, height):
+ hippo.CanvasBox.do_allocate(self, width, height)
- for item in self._items_to_position:
- [item_w, item_h] = item.get_request()
+ for item in self._items_to_position:
+ [item_w, item_h] = item.get_request()
- x = int(random.random() * width - item_w)
- y = int(random.random() * height - item_h)
+ x = int(random.random() * width - item_w)
+ y = int(random.random() * height - item_h)
- [x, y] = self._clamp_position(item, x, y)
- self.move(item, x, y)
+ [x, y] = self._clamp_position(item, x, y)
+ self.move(item, x, y)
- self._items_to_position = []
+ self._items_to_position = []
- tries = 20
- self._spread_icons()
- while not self._stable and tries > 0:
- self._spread_icons()
- tries -= 1
+ tries = 20
+ self._spread_icons()
+ while not self._stable and tries > 0:
+ self._spread_icons()
+ tries -= 1
diff --git a/sugar/graphics/style.py b/sugar/graphics/style.py
index f0ab3e8..6c4bff3 100644
--- a/sugar/graphics/style.py
+++ b/sugar/graphics/style.py
@@ -31,21 +31,21 @@ large_icon_size = standard_icon_size * 2.0
xlarge_icon_size = standard_icon_size * 3.0
def load_stylesheet(module):
- for objname in dir(module):
- if not objname.startswith('_'):
- obj = getattr(module, objname)
- if isinstance(obj, dict):
- register_stylesheet(objname.replace('_', '.'), obj)
+ for objname in dir(module):
+ if not objname.startswith('_'):
+ obj = getattr(module, objname)
+ if isinstance(obj, dict):
+ register_stylesheet(objname.replace('_', '.'), obj)
def register_stylesheet(name, style):
- _styles[name] = style
+ _styles[name] = style
def apply_stylesheet(item, stylesheet_name):
- if _styles.has_key(stylesheet_name):
- style_sheet = _styles[stylesheet_name]
- for name in style_sheet.keys():
- item.set_property(name, style_sheet[name])
+ if _styles.has_key(stylesheet_name):
+ style_sheet = _styles[stylesheet_name]
+ for name in style_sheet.keys():
+ item.set_property(name, style_sheet[name])
def get_font_description(style, relative_size):
- base_size = 18 * _screen_factor
- return '%s %dpx' % (style, int(base_size * relative_size))
+ base_size = 18 * _screen_factor
+ return '%s %dpx' % (style, int(base_size * relative_size))
diff --git a/sugar/graphics/stylesheet.py b/sugar/graphics/stylesheet.py
index d349733..ae9b4c8 100644
--- a/sugar/graphics/stylesheet.py
+++ b/sugar/graphics/stylesheet.py
@@ -1,31 +1,31 @@
from sugar.graphics import style
menu = {
- 'background_color' : 0x000000FF,
- 'spacing' : style.space_unit,
- 'padding' : style.space_unit
+ 'background_color' : 0x000000FF,
+ 'spacing' : style.space_unit,
+ 'padding' : style.space_unit
}
menu_Title = {
- 'color' : 0xFFFFFFFF,
- 'font' : style.get_font_description('Bold', 1.2)
+ 'color' : 0xFFFFFFFF,
+ 'font' : style.get_font_description('Bold', 1.2)
}
menu_Separator = {
- 'background_color' : 0xFFFFFFFF,
- 'box_height' : style.separator_thickness
+ 'background_color' : 0xFFFFFFFF,
+ 'box_height' : style.separator_thickness
}
menu_ActionIcon = {
- 'size' : style.standard_icon_size
+ 'size' : style.standard_icon_size
}
menu_Item = {
- 'color' : 0xFFFFFFFF,
- 'font' : style.get_font_description('Plain', 1.1)
+ 'color' : 0xFFFFFFFF,
+ 'font' : style.get_font_description('Plain', 1.1)
}
menu_Text = {
- 'color' : 0xFFFFFFFF,
- 'font' : style.get_font_description('Plain', 1.2)
+ 'color' : 0xFFFFFFFF,
+ 'font' : style.get_font_description('Plain', 1.2)
}
diff --git a/sugar/graphics/timeline.py b/sugar/graphics/timeline.py
index 5c40ca5..3944771 100644
--- a/sugar/graphics/timeline.py
+++ b/sugar/graphics/timeline.py
@@ -18,100 +18,100 @@
import gobject
class _Tag:
- def __init__(self, name, start_frame, end_frame):
- self.name = name
- self.start_frame = start_frame
- self.end_frame = end_frame
+ def __init__(self, name, start_frame, end_frame):
+ self.name = name
+ self.start_frame = start_frame
+ self.end_frame = end_frame
class TimelineObserver:
- def __init__(self, observer):
- self._observer = observer
+ def __init__(self, observer):
+ self._observer = observer
- def next_frame(self, tag, current_frame, n_frames):
- try:
- method = getattr(self._observer, 'do_' + tag)
- except AttributeError:
- method = None
+ def next_frame(self, tag, current_frame, n_frames):
+ try:
+ method = getattr(self._observer, 'do_' + tag)
+ except AttributeError:
+ method = None
- if method:
- method(current_frame, n_frames)
+ if method:
+ method(current_frame, n_frames)
class Timeline:
- def __init__(self, observer):
- self._fps = 12
- self._tags = []
- self._name_to_tag = {}
- self._current_frame = 0
- self._timeout_sid = 0
- self._observer = TimelineObserver(observer)
-
- def add_tag(self, name, start_frame, end_frame):
- tag = _Tag(name, start_frame, end_frame)
- self._tags.append(tag)
- self._name_to_tag[name] = tag
-
- def remove_tag(self, name):
- tag = self._tags[name]
- self._tags.remove(tag)
- del self._tags[name]
-
- def _next_frame(self, tag, frame):
- n_frames = tag.start_frame - tag.end_frame
- self._observer.next_frame(tag.name, frame, n_frames)
-
- def goto(self, tag_name, end_frame=False):
- self.pause()
-
- tag = self._name_to_tag[tag_name]
- if end_frame:
- self._current_frame = tag.end_frame
- else:
- self._current_frame = tag.start_frame
-
- self._next_frame(tag, self._current_frame)
-
- def on_tag(self, name):
- tag = self._name_to_tag[name]
- return (tag.start_frame <= self._current_frame and \
- tag.end_frame >= self._current_frame)
-
- def _get_tags_for_frame(self, frame):
- result = []
- for tag in self._tags:
- if tag.start_frame <= frame and tag.end_frame >= frame:
- result.append(tag)
- return result
-
- def _timeout_cb(self, end_frame):
- for tag in self._get_tags_for_frame(self._current_frame):
- cur_frame = self._current_frame - tag.start_frame
- self._next_frame(tag, cur_frame)
-
- if self._current_frame < end_frame:
- self._current_frame += 1
- return True
- else:
- return False
-
- def play(self, start_tag=None, stop_tag=None):
- self.pause()
-
- if start_tag == None:
- start = 0
- else:
- start = self._name_to_tag[start_tag].start_frame
-
- if stop_tag == None:
- end = self._tags[len(self._tags) - 1].end_frame
- else:
- end = self._name_to_tag[stop_tag].end_frame
-
- self._current_frame = start
-
- interval = 1000 / self._fps
- self._timeout_sid = gobject.timeout_add(
- interval, self._timeout_cb, end)
-
- def pause(self):
- if self._timeout_sid > 0:
- gobject.source_remove(self._timeout_sid)
+ def __init__(self, observer):
+ self._fps = 12
+ self._tags = []
+ self._name_to_tag = {}
+ self._current_frame = 0
+ self._timeout_sid = 0
+ self._observer = TimelineObserver(observer)
+
+ def add_tag(self, name, start_frame, end_frame):
+ tag = _Tag(name, start_frame, end_frame)
+ self._tags.append(tag)
+ self._name_to_tag[name] = tag
+
+ def remove_tag(self, name):
+ tag = self._tags[name]
+ self._tags.remove(tag)
+ del self._tags[name]
+
+ def _next_frame(self, tag, frame):
+ n_frames = tag.start_frame - tag.end_frame
+ self._observer.next_frame(tag.name, frame, n_frames)
+
+ def goto(self, tag_name, end_frame=False):
+ self.pause()
+
+ tag = self._name_to_tag[tag_name]
+ if end_frame:
+ self._current_frame = tag.end_frame
+ else:
+ self._current_frame = tag.start_frame
+
+ self._next_frame(tag, self._current_frame)
+
+ def on_tag(self, name):
+ tag = self._name_to_tag[name]
+ return (tag.start_frame <= self._current_frame and \
+ tag.end_frame >= self._current_frame)
+
+ def _get_tags_for_frame(self, frame):
+ result = []
+ for tag in self._tags:
+ if tag.start_frame <= frame and tag.end_frame >= frame:
+ result.append(tag)
+ return result
+
+ def _timeout_cb(self, end_frame):
+ for tag in self._get_tags_for_frame(self._current_frame):
+ cur_frame = self._current_frame - tag.start_frame
+ self._next_frame(tag, cur_frame)
+
+ if self._current_frame < end_frame:
+ self._current_frame += 1
+ return True
+ else:
+ return False
+
+ def play(self, start_tag=None, stop_tag=None):
+ self.pause()
+
+ if start_tag == None:
+ start = 0
+ else:
+ start = self._name_to_tag[start_tag].start_frame
+
+ if stop_tag == None:
+ end = self._tags[len(self._tags) - 1].end_frame
+ else:
+ end = self._name_to_tag[stop_tag].end_frame
+
+ self._current_frame = start
+
+ interval = 1000 / self._fps
+ self._timeout_sid = gobject.timeout_add(
+ interval, self._timeout_cb, end)
+
+ def pause(self):
+ if self._timeout_sid > 0:
+ gobject.source_remove(self._timeout_sid)
diff --git a/sugar/logger.py b/sugar/logger.py
index b4b2e0c..5eb8039 100644
--- a/sugar/logger.py
+++ b/sugar/logger.py
@@ -29,82 +29,82 @@ STDOUT_LEVEL = 1000
STDERR_LEVEL = 2000
class LogWriter:
- def __init__(self, module_id):
- self._module_id = module_id
-
- logs_dir = _get_logs_dir()
- log_path = os.path.join(logs_dir, module_id + '.log')
- self._log_file = open(log_path, 'w')
-
- def write_record(self, record):
- self.write(record.levelno, record.msg)
-
- def write(self, level, msg):
- if level == logging.ERROR:
- level_txt = 'ERROR'
- elif level == logging.WARNING:
- level_txt = 'WARNING'
- elif level == logging.DEBUG:
- level_txt = 'DEBUG'
- elif level == logging.INFO:
- level_txt = 'INFO'
- elif level == STDERR_LEVEL:
- level_txt = 'STDERR'
- elif level == STDOUT_LEVEL:
- level_txt = 'STDOUT'
-
- fmt = "%s - %s\n" % (level_txt, msg)
- fmt = fmt.encode("utf8")
- self._log_file.write(fmt)
- self._log_file.flush()
+ def __init__(self, module_id):
+ self._module_id = module_id
+
+ logs_dir = _get_logs_dir()
+ log_path = os.path.join(logs_dir, module_id + '.log')
+ self._log_file = open(log_path, 'w')
+
+ def write_record(self, record):
+ self.write(record.levelno, record.msg)
+
+ def write(self, level, msg):
+ if level == logging.ERROR:
+ level_txt = 'ERROR'
+ elif level == logging.WARNING:
+ level_txt = 'WARNING'
+ elif level == logging.DEBUG:
+ level_txt = 'DEBUG'
+ elif level == logging.INFO:
+ level_txt = 'INFO'
+ elif level == STDERR_LEVEL:
+ level_txt = 'STDERR'
+ elif level == STDOUT_LEVEL:
+ level_txt = 'STDOUT'
+
+ fmt = "%s - %s\n" % (level_txt, msg)
+ fmt = fmt.encode("utf8")
+ self._log_file.write(fmt)
+ self._log_file.flush()
class Handler(logging.Handler):
- def __init__(self, writer):
- logging.Handler.__init__(self)
+ def __init__(self, writer):
+ logging.Handler.__init__(self)
- self._writer = writer
+ self._writer = writer
- def emit(self, record):
- self._writer.write_record(record)
+ def emit(self, record):
+ self._writer.write_record(record)
class StdoutCatcher:
- def write(self, txt):
- _log_writer.write(STDOUT_LEVEL, txt)
- sys.__stdout__.write(txt)
+ def write(self, txt):
+ _log_writer.write(STDOUT_LEVEL, txt)
+ sys.__stdout__.write(txt)
class StderrCatcher:
- def write(self, txt):
- _log_writer.write(STDERR_LEVEL, txt)
- sys.__stderr__.write(txt)
+ def write(self, txt):
+ _log_writer.write(STDERR_LEVEL, txt)
+ sys.__stderr__.write(txt)
def __exception_handler(typ, exc, tb):
- trace = StringIO()
- traceback.print_exception(typ, exc, tb, None, trace)
- print >> sys.stderr, trace.getvalue()
+ trace = StringIO()
+ traceback.print_exception(typ, exc, tb, None, trace)
+ print >> sys.stderr, trace.getvalue()
- _log_writer.write(logging.ERROR, trace.getvalue())
+ _log_writer.write(logging.ERROR, trace.getvalue())
def _get_logs_dir():
- logs_dir = os.path.join(env.get_profile_path(), 'logs')
- if not os.path.isdir(logs_dir):
- os.makedirs(logs_dir)
- return logs_dir
+ logs_dir = os.path.join(env.get_profile_path(), 'logs')
+ if not os.path.isdir(logs_dir):
+ os.makedirs(logs_dir)
+ return logs_dir
def start(module_id):
- log_writer = LogWriter(module_id)
+ log_writer = LogWriter(module_id)
- root_logger = logging.getLogger('')
- root_logger.setLevel(logging.DEBUG)
- root_logger.addHandler(Handler(log_writer))
+ root_logger = logging.getLogger('')
+ root_logger.setLevel(logging.DEBUG)
+ root_logger.addHandler(Handler(log_writer))
- sys.stdout = StdoutCatcher()
- sys.stderr = StderrCatcher()
+ sys.stdout = StdoutCatcher()
+ sys.stderr = StderrCatcher()
- global _log_writer
- _log_writer = log_writer
- sys.excepthook = __exception_handler
+ global _log_writer
+ _log_writer = log_writer
+ sys.excepthook = __exception_handler
def cleanup():
- logs_dir = _get_logs_dir()
- for f in os.listdir(logs_dir):
- os.remove(os.path.join(logs_dir, f))
+ logs_dir = _get_logs_dir()
+ for f in os.listdir(logs_dir):
+ os.remove(os.path.join(logs_dir, f))
diff --git a/sugar/p2p/MostlyReliablePipe.py b/sugar/p2p/MostlyReliablePipe.py
index 4218181..604eada 100644
--- a/sugar/p2p/MostlyReliablePipe.py
+++ b/sugar/p2p/MostlyReliablePipe.py
@@ -32,952 +32,952 @@ import gobject
def _stringify_sha(sha_hash):
- print_sha = ""
- for char in sha_hash:
- print_sha = print_sha + binascii.b2a_hex(char)
- return print_sha
+ print_sha = ""
+ for char in sha_hash:
+ print_sha = print_sha + binascii.b2a_hex(char)
+ return print_sha
def _sha_data(data):
- sha_hash = sha.new()
- sha_hash.update(data)
- return sha_hash.digest()
+ sha_hash = sha.new()
+ sha_hash.update(data)
+ return sha_hash.digest()
_UDP_DATAGRAM_SIZE = 512
class SegmentBase(object):
- _MAGIC = 0xbaea4304
-
- # 4: magic (0xbaea4304)
- # 1: type
- # 2: segment number
- # 2: total segments
- # 2: message sequence number
- #20: total data sha1
- _HEADER_TEMPLATE = "! IbHHH20s"
- _HEADER_LEN = struct.calcsize(_HEADER_TEMPLATE)
- _MTU = _UDP_DATAGRAM_SIZE - _HEADER_LEN
-
- # Message segment packet types
- _SEGMENT_TYPE_DATA = 0
- _SEGMENT_TYPE_RETRANSMIT = 1
- _SEGMENT_TYPE_ACK = 2
-
- def magic():
- return SegmentBase._MAGIC
- magic = staticmethod(magic)
-
- def header_template():
- return SegmentBase._HEADER_TEMPLATE
- header_template = staticmethod(header_template)
-
- def type_data():
- return SegmentBase._SEGMENT_TYPE_DATA
- type_data = staticmethod(type_data)
-
- def type_retransmit():
- return SegmentBase._SEGMENT_TYPE_RETRANSMIT
- type_retransmit = staticmethod(type_retransmit)
-
- def type_ack():
- return SegmentBase._SEGMENT_TYPE_ACK
- type_ack = staticmethod(type_ack)
-
- def header_len():
- """Return the header size of SegmentBase packets."""
- return SegmentBase._HEADER_LEN
- header_len = staticmethod(header_len)
-
- def mtu():
- """Return the SegmentBase packet MTU."""
- return SegmentBase._MTU
- mtu = staticmethod(mtu)
-
- def __init__(self, segno, total_segs, msg_seq_num, master_sha):
- self._type = None
- self._transmits = 0
- self._last_transmit = 0
- self._data = None
- self._data_len = 0
- self.userdata = None
- self._stime = time.time()
- self._addr = None
-
- # Sanity checks on the message attributes
- if not segno or not isinstance(segno, int):
- raise ValueError("Segment number must be in integer.")
- if segno < 1 or segno > 65535:
- raise ValueError("Segment number must be between 1 and 65535 inclusive.")
- if not total_segs or not isinstance(total_segs, int):
- raise ValueError("Message segment total must be an integer.")
- if total_segs < 1 or total_segs > 65535:
- raise ValueError("Message must have between 1 and 65535 segments inclusive.")
- if segno > total_segs:
- raise ValueError("Segment number cannot be larger than message segment total.")
- if not msg_seq_num or not isinstance(msg_seq_num, int):
- raise ValueError("Message sequnce number must be an integer.")
- if msg_seq_num < 1 or msg_seq_num > 65535:
- raise ValueError("Message sequence number must be between 1 and 65535 inclusive.")
- if not master_sha or not isinstance(master_sha, str) or len(master_sha) != 20:
- raise ValueError("Message SHA1 checksum invalid.")
-
- self._segno = segno
- self._total_segs = total_segs
- self._msg_seq_num = msg_seq_num
- self._master_sha = master_sha
-
- def _validate_address(addr):
- if not addr or not isinstance(addr, tuple):
- raise ValueError("Address must be a tuple.")
- if len(addr) != 2 or not isinstance(addr[0], str) or not isinstance(addr[1], int):
- raise ValueError("Address format was invalid.")
- if addr[1] < 1 or addr[1] > 65535:
- raise ValueError("Address port was invalid.")
- _validate_address = staticmethod(_validate_address)
-
- def new_from_data(addr, data):
- """Static constructor for creation from a packed data stream."""
- SegmentBase._validate_address(addr)
-
- # Verify minimum length
- if not data:
- raise ValueError("Segment data is invalid.")
- data_len = len(data)
- if data_len < SegmentBase.header_len() + 1:
- raise ValueError("Segment is less then minimum required length")
- if data_len > _UDP_DATAGRAM_SIZE:
- raise ValueError("Segment data is larger than allowed.")
- stream = StringIO.StringIO(data)
-
- # Determine and verify the length of included data
- stream.seek(0, 2)
- data_len = stream.tell() - SegmentBase._HEADER_LEN
- stream.seek(0)
-
- if data_len < 1:
- raise ValueError("Segment must have some data.")
- if data_len > SegmentBase._MTU:
- raise ValueError("Data length must not be larger than the MTU (%s)." % SegmentBase._MTU)
-
- # Read the first header attributes
- (magic, seg_type, segno, total_segs, msg_seq_num, master_sha) = struct.unpack(SegmentBase._HEADER_TEMPLATE,
- stream.read(SegmentBase._HEADER_LEN))
-
- # Sanity checks on the message attributes
- if magic != SegmentBase._MAGIC:
- raise ValueError("Segment does not have the correct magic.")
-
- # if the segment is the only one in the message, validate the data
- if segno == 1 and total_segs == 1:
- data_sha = _sha_data(stream.read(data_len))
- if data_sha != master_sha:
- raise ValueError("Single segment message SHA checksums didn't match.")
- stream.seek(SegmentBase._HEADER_LEN)
-
- if seg_type == SegmentBase._SEGMENT_TYPE_DATA:
- segment = DataSegment(segno, total_segs, msg_seq_num, master_sha)
- elif seg_type == SegmentBase._SEGMENT_TYPE_RETRANSMIT:
- segment = RetransmitSegment(segno, total_segs, msg_seq_num, master_sha)
- elif seg_type == SegmentBase._SEGMENT_TYPE_ACK:
- segment = AckSegment(segno, total_segs, msg_seq_num, master_sha)
- else:
- raise ValueError("Segment has invalid type.")
-
- # Segment specific data interpretation
- segment._addr = addr
- segment._unpack_data(stream, data_len)
-
- return segment
- new_from_data = staticmethod(new_from_data)
-
- def stime(self):
- return self._stime
-
- def address(self):
- return self._addr
-
- def segment_number(self):
- return self._segno
-
- def total_segments(self):
- return self._total_segs
-
- def message_sequence_number(self):
- return self._msg_seq_num
-
- def data(self):
- return self._data
-
- def master_sha(self):
- return self._master_sha
-
- def segment_type(self):
- return self._type
-
- def packetize(self):
- """Return a correctly formatted message that can be immediately sent."""
- header = struct.pack(self._HEADER_TEMPLATE, self._MAGIC, self._type,
- self._segno, self._total_segs, self._msg_seq_num, self._master_sha)
- return header + self._data
-
- def transmits(self):
- return self._transmits
-
- def inc_transmits(self):
- self._transmits = self._transmits + 1
- self._last_transmit = time.time()
-
- def last_transmit(self):
- return self._last_transmit
+ _MAGIC = 0xbaea4304
+
+ # 4: magic (0xbaea4304)
+ # 1: type
+ # 2: segment number
+ # 2: total segments
+ # 2: message sequence number
+ #20: total data sha1
+ _HEADER_TEMPLATE = "! IbHHH20s"
+ _HEADER_LEN = struct.calcsize(_HEADER_TEMPLATE)
+ _MTU = _UDP_DATAGRAM_SIZE - _HEADER_LEN
+
+ # Message segment packet types
+ _SEGMENT_TYPE_DATA = 0
+ _SEGMENT_TYPE_RETRANSMIT = 1
+ _SEGMENT_TYPE_ACK = 2
+
+ def magic():
+ return SegmentBase._MAGIC
+ magic = staticmethod(magic)
+
+ def header_template():
+ return SegmentBase._HEADER_TEMPLATE
+ header_template = staticmethod(header_template)
+
+ def type_data():
+ return SegmentBase._SEGMENT_TYPE_DATA
+ type_data = staticmethod(type_data)
+
+ def type_retransmit():
+ return SegmentBase._SEGMENT_TYPE_RETRANSMIT
+ type_retransmit = staticmethod(type_retransmit)
+
+ def type_ack():
+ return SegmentBase._SEGMENT_TYPE_ACK
+ type_ack = staticmethod(type_ack)
+
+ def header_len():
+ """Return the header size of SegmentBase packets."""
+ return SegmentBase._HEADER_LEN
+ header_len = staticmethod(header_len)
+
+ def mtu():
+ """Return the SegmentBase packet MTU."""
+ return SegmentBase._MTU
+ mtu = staticmethod(mtu)
+
+ def __init__(self, segno, total_segs, msg_seq_num, master_sha):
+ self._type = None
+ self._transmits = 0
+ self._last_transmit = 0
+ self._data = None
+ self._data_len = 0
+ self.userdata = None
+ self._stime = time.time()
+ self._addr = None
+
+ # Sanity checks on the message attributes
+ if not segno or not isinstance(segno, int):
+ raise ValueError("Segment number must be in integer.")
+ if segno < 1 or segno > 65535:
+ raise ValueError("Segment number must be between 1 and 65535 inclusive.")
+ if not total_segs or not isinstance(total_segs, int):
+ raise ValueError("Message segment total must be an integer.")
+ if total_segs < 1 or total_segs > 65535:
+ raise ValueError("Message must have between 1 and 65535 segments inclusive.")
+ if segno > total_segs:
+ raise ValueError("Segment number cannot be larger than message segment total.")
+ if not msg_seq_num or not isinstance(msg_seq_num, int):
+ raise ValueError("Message sequnce number must be an integer.")
+ if msg_seq_num < 1 or msg_seq_num > 65535:
+ raise ValueError("Message sequence number must be between 1 and 65535 inclusive.")
+ if not master_sha or not isinstance(master_sha, str) or len(master_sha) != 20:
+ raise ValueError("Message SHA1 checksum invalid.")
+
+ self._segno = segno
+ self._total_segs = total_segs
+ self._msg_seq_num = msg_seq_num
+ self._master_sha = master_sha
+
+ def _validate_address(addr):
+ if not addr or not isinstance(addr, tuple):
+ raise ValueError("Address must be a tuple.")
+ if len(addr) != 2 or not isinstance(addr[0], str) or not isinstance(addr[1], int):
+ raise ValueError("Address format was invalid.")
+ if addr[1] < 1 or addr[1] > 65535:
+ raise ValueError("Address port was invalid.")
+ _validate_address = staticmethod(_validate_address)
+
+ def new_from_data(addr, data):
+ """Static constructor for creation from a packed data stream."""
+ SegmentBase._validate_address(addr)
+
+ # Verify minimum length
+ if not data:
+ raise ValueError("Segment data is invalid.")
+ data_len = len(data)
+ if data_len < SegmentBase.header_len() + 1:
+ raise ValueError("Segment is less then minimum required length")
+ if data_len > _UDP_DATAGRAM_SIZE:
+ raise ValueError("Segment data is larger than allowed.")
+ stream = StringIO.StringIO(data)
+
+ # Determine and verify the length of included data
+ stream.seek(0, 2)
+ data_len = stream.tell() - SegmentBase._HEADER_LEN
+ stream.seek(0)
+
+ if data_len < 1:
+ raise ValueError("Segment must have some data.")
+ if data_len > SegmentBase._MTU:
+ raise ValueError("Data length must not be larger than the MTU (%s)." % SegmentBase._MTU)
+
+ # Read the first header attributes
+ (magic, seg_type, segno, total_segs, msg_seq_num, master_sha) = struct.unpack(SegmentBase._HEADER_TEMPLATE,
+ stream.read(SegmentBase._HEADER_LEN))
+
+ # Sanity checks on the message attributes
+ if magic != SegmentBase._MAGIC:
+ raise ValueError("Segment does not have the correct magic.")
+
+ # if the segment is the only one in the message, validate the data
+ if segno == 1 and total_segs == 1:
+ data_sha = _sha_data(stream.read(data_len))
+ if data_sha != master_sha:
+ raise ValueError("Single segment message SHA checksums didn't match.")
+ stream.seek(SegmentBase._HEADER_LEN)
+
+ if seg_type == SegmentBase._SEGMENT_TYPE_DATA:
+ segment = DataSegment(segno, total_segs, msg_seq_num, master_sha)
+ elif seg_type == SegmentBase._SEGMENT_TYPE_RETRANSMIT:
+ segment = RetransmitSegment(segno, total_segs, msg_seq_num, master_sha)
+ elif seg_type == SegmentBase._SEGMENT_TYPE_ACK:
+ segment = AckSegment(segno, total_segs, msg_seq_num, master_sha)
+ else:
+ raise ValueError("Segment has invalid type.")
+
+ # Segment specific data interpretation
+ segment._addr = addr
+ segment._unpack_data(stream, data_len)
+
+ return segment
+ new_from_data = staticmethod(new_from_data)
+
+ def stime(self):
+ return self._stime
+
+ def address(self):
+ return self._addr
+
+ def segment_number(self):
+ return self._segno
+
+ def total_segments(self):
+ return self._total_segs
+
+ def message_sequence_number(self):
+ return self._msg_seq_num
+
+ def data(self):
+ return self._data
+
+ def master_sha(self):
+ return self._master_sha
+
+ def segment_type(self):
+ return self._type
+
+ def packetize(self):
+ """Return a correctly formatted message that can be immediately sent."""
+ header = struct.pack(self._HEADER_TEMPLATE, self._MAGIC, self._type,
+ self._segno, self._total_segs, self._msg_seq_num, self._master_sha)
+ return header + self._data
+
+ def transmits(self):
+ return self._transmits
+
+ def inc_transmits(self):
+ self._transmits = self._transmits + 1
+ self._last_transmit = time.time()
+
+ def last_transmit(self):
+ return self._last_transmit
class DataSegment(SegmentBase):
- """A message segment that encapsulates random data."""
-
- def __init__(self, segno, total_segs, msg_seq_num, master_sha):
- SegmentBase.__init__(self, segno, total_segs, msg_seq_num, master_sha)
- self._type = SegmentBase._SEGMENT_TYPE_DATA
-
- def _get_template_for_len(length):
- return "! %ds" % length
- _get_template_for_len = staticmethod(_get_template_for_len)
-
- def _unpack_data(self, stream, data_len):
- """Unpack the data stream, called by constructor."""
- self._data_len = data_len
- template = DataSegment._get_template_for_len(self._data_len)
- self._data = struct.unpack(template, stream.read(self._data_len))[0]
-
- def new_from_parts(segno, total_segs, msg_seq_num, master_sha, data):
- """Construct a new message segment from individual attributes."""
- if not data:
- raise ValueError("Must have valid data.")
- segment = DataSegment(segno, total_segs, msg_seq_num, master_sha)
- segment._data_len = len(data)
- template = DataSegment._get_template_for_len(segment._data_len)
- segment._data = struct.pack(template, data)
- return segment
- new_from_parts = staticmethod(new_from_parts)
+ """A message segment that encapsulates random data."""
+
+ def __init__(self, segno, total_segs, msg_seq_num, master_sha):
+ SegmentBase.__init__(self, segno, total_segs, msg_seq_num, master_sha)
+ self._type = SegmentBase._SEGMENT_TYPE_DATA
+
+ def _get_template_for_len(length):
+ return "! %ds" % length
+ _get_template_for_len = staticmethod(_get_template_for_len)
+
+ def _unpack_data(self, stream, data_len):
+ """Unpack the data stream, called by constructor."""
+ self._data_len = data_len
+ template = DataSegment._get_template_for_len(self._data_len)
+ self._data = struct.unpack(template, stream.read(self._data_len))[0]
+
+ def new_from_parts(segno, total_segs, msg_seq_num, master_sha, data):
+ """Construct a new message segment from individual attributes."""
+ if not data:
+ raise ValueError("Must have valid data.")
+ segment = DataSegment(segno, total_segs, msg_seq_num, master_sha)
+ segment._data_len = len(data)
+ template = DataSegment._get_template_for_len(segment._data_len)
+ segment._data = struct.pack(template, data)
+ return segment
+ new_from_parts = staticmethod(new_from_parts)
class RetransmitSegment(SegmentBase):
- """A message segment that encapsulates a retransmission request."""
-
- # Retransmission data format:
- # 2: message sequence number
- # 20: total data sha1
- # 2: segment number
- _RT_DATA_TEMPLATE = "! H20sH"
- _RT_DATA_LEN = struct.calcsize(_RT_DATA_TEMPLATE)
-
- def data_template():
- return RetransmitSegment._RT_DATA_TEMPLATE
- data_template = staticmethod(data_template)
-
- def __init__(self, segno, total_segs, msg_seq_num, master_sha):
- """Should not be called directly."""
- if segno != 1 or total_segs != 1:
- raise ValueError("Retransmission request messages must have only one segment.")
-
- SegmentBase.__init__(self, segno, total_segs, msg_seq_num, master_sha)
- self._type = SegmentBase._SEGMENT_TYPE_RETRANSMIT
-
- def _verify_data(rt_msg_seq_num, rt_master_sha, rt_segment_number):
- # Sanity checks on the message attributes
- if not rt_segment_number or not isinstance(rt_segment_number, int):
- raise ValueError("RT Segment number must be in integer.")
- if rt_segment_number < 1 or rt_segment_number > 65535:
- raise ValueError("RT Segment number must be between 1 and 65535 inclusive.")
- if not rt_msg_seq_num or not isinstance(rt_msg_seq_num, int):
- raise ValueError("RT Message sequnce number must be an integer.")
- if rt_msg_seq_num < 1 or rt_msg_seq_num > 65535:
- raise ValueError("RT Message sequence number must be between 1 and 65535 inclusive.")
- if not rt_master_sha or not isinstance(rt_master_sha, str) or len(rt_master_sha) != 20:
- raise ValueError("RT Message SHA1 checksum invalid.")
- _verify_data = staticmethod(_verify_data)
-
- def _make_rtms_data(rt_msg_seq_num, rt_master_sha, rt_segment_number):
- """Pack retransmission request payload."""
- data = struct.pack(RetransmitSegment._RT_DATA_TEMPLATE, rt_msg_seq_num,
- rt_master_sha, rt_segment_number)
- return (data, _sha_data(data))
- _make_rtms_data = staticmethod(_make_rtms_data)
-
- def new_from_parts(addr, msg_seq_num, rt_msg_seq_num, rt_master_sha, rt_segment_number):
- """Static constructor for creation from individual attributes."""
-
- RetransmitSegment._verify_data(rt_msg_seq_num, rt_master_sha, rt_segment_number)
- (data, data_sha) = RetransmitSegment._make_rtms_data(rt_msg_seq_num,
- rt_master_sha, rt_segment_number)
- segment = RetransmitSegment(1, 1, msg_seq_num, data_sha)
- segment._data_len = RetransmitSegment._RT_DATA_LEN
- segment._data = data
- SegmentBase._validate_address(addr)
- segment._addr = addr
-
- segment._rt_msg_seq_num = rt_msg_seq_num
- segment._rt_master_sha = rt_master_sha
- segment._rt_segment_number = rt_segment_number
- return segment
- new_from_parts = staticmethod(new_from_parts)
-
- def _unpack_data(self, stream, data_len):
- if data_len != self._RT_DATA_LEN:
- raise ValueError("Retransmission request data had invalid length.")
- data = stream.read(data_len)
- (rt_msg_seq_num, rt_master_sha, rt_seg_no) = struct.unpack(self._RT_DATA_TEMPLATE, data)
- RetransmitSegment._verify_data(rt_msg_seq_num, rt_master_sha, rt_seg_no)
-
- self._data = data
- self._data_len = data_len
- self._rt_msg_seq_num = rt_msg_seq_num
- self._rt_master_sha = rt_master_sha
- self._rt_segment_number = rt_seg_no
-
- def rt_msg_seq_num(self):
- return self._rt_msg_seq_num
-
- def rt_master_sha(self):
- return self._rt_master_sha
-
- def rt_segment_number(self):
- return self._rt_segment_number
+ """A message segment that encapsulates a retransmission request."""
+
+ # Retransmission data format:
+ # 2: message sequence number
+ # 20: total data sha1
+ # 2: segment number
+ _RT_DATA_TEMPLATE = "! H20sH"
+ _RT_DATA_LEN = struct.calcsize(_RT_DATA_TEMPLATE)
+
+ def data_template():
+ return RetransmitSegment._RT_DATA_TEMPLATE
+ data_template = staticmethod(data_template)
+
+ def __init__(self, segno, total_segs, msg_seq_num, master_sha):
+ """Should not be called directly."""
+ if segno != 1 or total_segs != 1:
+ raise ValueError("Retransmission request messages must have only one segment.")
+
+ SegmentBase.__init__(self, segno, total_segs, msg_seq_num, master_sha)
+ self._type = SegmentBase._SEGMENT_TYPE_RETRANSMIT
+
+ def _verify_data(rt_msg_seq_num, rt_master_sha, rt_segment_number):
+ # Sanity checks on the message attributes
+ if not rt_segment_number or not isinstance(rt_segment_number, int):
+ raise ValueError("RT Segment number must be in integer.")
+ if rt_segment_number < 1 or rt_segment_number > 65535:
+ raise ValueError("RT Segment number must be between 1 and 65535 inclusive.")
+ if not rt_msg_seq_num or not isinstance(rt_msg_seq_num, int):
+ raise ValueError("RT Message sequnce number must be an integer.")
+ if rt_msg_seq_num < 1 or rt_msg_seq_num > 65535:
+ raise ValueError("RT Message sequence number must be between 1 and 65535 inclusive.")
+ if not rt_master_sha or not isinstance(rt_master_sha, str) or len(rt_master_sha) != 20:
+ raise ValueError("RT Message SHA1 checksum invalid.")
+ _verify_data = staticmethod(_verify_data)
+
+ def _make_rtms_data(rt_msg_seq_num, rt_master_sha, rt_segment_number):
+ """Pack retransmission request payload."""
+ data = struct.pack(RetransmitSegment._RT_DATA_TEMPLATE, rt_msg_seq_num,
+ rt_master_sha, rt_segment_number)
+ return (data, _sha_data(data))
+ _make_rtms_data = staticmethod(_make_rtms_data)
+
+ def new_from_parts(addr, msg_seq_num, rt_msg_seq_num, rt_master_sha, rt_segment_number):
+ """Static constructor for creation from individual attributes."""
+
+ RetransmitSegment._verify_data(rt_msg_seq_num, rt_master_sha, rt_segment_number)
+ (data, data_sha) = RetransmitSegment._make_rtms_data(rt_msg_seq_num,
+ rt_master_sha, rt_segment_number)
+ segment = RetransmitSegment(1, 1, msg_seq_num, data_sha)
+ segment._data_len = RetransmitSegment._RT_DATA_LEN
+ segment._data = data
+ SegmentBase._validate_address(addr)
+ segment._addr = addr
+
+ segment._rt_msg_seq_num = rt_msg_seq_num
+ segment._rt_master_sha = rt_master_sha
+ segment._rt_segment_number = rt_segment_number
+ return segment
+ new_from_parts = staticmethod(new_from_parts)
+
+ def _unpack_data(self, stream, data_len):
+ if data_len != self._RT_DATA_LEN:
+ raise ValueError("Retransmission request data had invalid length.")
+ data = stream.read(data_len)
+ (rt_msg_seq_num, rt_master_sha, rt_seg_no) = struct.unpack(self._RT_DATA_TEMPLATE, data)
+ RetransmitSegment._verify_data(rt_msg_seq_num, rt_master_sha, rt_seg_no)
+
+ self._data = data
+ self._data_len = data_len
+ self._rt_msg_seq_num = rt_msg_seq_num
+ self._rt_master_sha = rt_master_sha
+ self._rt_segment_number = rt_seg_no
+
+ def rt_msg_seq_num(self):
+ return self._rt_msg_seq_num
+
+ def rt_master_sha(self):
+ return self._rt_master_sha
+
+ def rt_segment_number(self):
+ return self._rt_segment_number
class AckSegment(SegmentBase):
- """A message segment that encapsulates a message acknowledgement."""
-
- # Ack data format:
- # 2: acked message sequence number
- # 20: acked message total data sha1
- # 4: acked message source IP address
- _ACK_DATA_TEMPLATE = "! H20s4s"
- _ACK_DATA_LEN = struct.calcsize(_ACK_DATA_TEMPLATE)
-
- def data_template():
- return AckSegment._ACK_DATA_TEMPLATE
- data_template = staticmethod(data_template)
-
- def __init__(self, segno, total_segs, msg_seq_num, master_sha):
- """Should not be called directly."""
- if segno != 1 or total_segs != 1:
- raise ValueError("Acknowledgement messages must have only one segment.")
-
- SegmentBase.__init__(self, segno, total_segs, msg_seq_num, master_sha)
- self._type = SegmentBase._SEGMENT_TYPE_ACK
-
- def _verify_data(ack_msg_seq_num, ack_master_sha, ack_addr):
- # Sanity checks on the message attributes
- if not ack_msg_seq_num or not isinstance(ack_msg_seq_num, int):
- raise ValueError("Ack message sequnce number must be an integer.")
- if ack_msg_seq_num < 1 or ack_msg_seq_num > 65535:
- raise ValueError("Ack message sequence number must be between 1 and 65535 inclusive.")
- if not ack_master_sha or not isinstance(ack_master_sha, str) or len(ack_master_sha) != 20:
- raise ValueError("Ack message SHA1 checksum invalid.")
- if not isinstance(ack_addr, str):
- raise ValueError("Ack message invalid address type.")
- try:
- foo = socket.inet_aton(ack_addr)
- except socket.error:
- raise ValueError("Ack message invalid address.")
- _verify_data = staticmethod(_verify_data)
-
- def _make_ack_data(ack_msg_seq_num, ack_master_sha, ack_addr):
- """Pack an ack payload."""
- addr_data = socket.inet_aton(ack_addr)
- data = struct.pack(AckSegment._ACK_DATA_TEMPLATE, ack_msg_seq_num,
- ack_master_sha, addr_data)
- return (data, _sha_data(data))
- _make_ack_data = staticmethod(_make_ack_data)
-
- def new_from_parts(addr, msg_seq_num, ack_msg_seq_num, ack_master_sha, ack_addr):
- """Static constructor for creation from individual attributes."""
-
- AckSegment._verify_data(ack_msg_seq_num, ack_master_sha, ack_addr)
- (data, data_sha) = AckSegment._make_ack_data(ack_msg_seq_num,
- ack_master_sha, ack_addr)
- segment = AckSegment(1, 1, msg_seq_num, data_sha)
- segment._data_len = AckSegment._ACK_DATA_LEN
- segment._data = data
- SegmentBase._validate_address(addr)
- segment._addr = addr
-
- segment._ack_msg_seq_num = ack_msg_seq_num
- segment._ack_master_sha = ack_master_sha
- segment._ack_addr = ack_addr
- return segment
- new_from_parts = staticmethod(new_from_parts)
-
- def _unpack_data(self, stream, data_len):
- if data_len != self._ACK_DATA_LEN:
- raise ValueError("Ack segment data had invalid length.")
- data = stream.read(data_len)
- (ack_msg_seq_num, ack_master_sha, ack_addr_data) = struct.unpack(self._ACK_DATA_TEMPLATE, data)
- try:
- ack_addr = socket.inet_ntoa(ack_addr_data)
- except socket.error:
- raise ValueError("Ack segment data had invalid address.")
- AckSegment._verify_data(ack_msg_seq_num, ack_master_sha, ack_addr)
-
- self._data = data
- self._data_len = data_len
- self._ack_msg_seq_num = ack_msg_seq_num
- self._ack_master_sha = ack_master_sha
- self._ack_addr = ack_addr
-
- def ack_msg_seq_num(self):
- return self._ack_msg_seq_num
-
- def ack_master_sha(self):
- return self._ack_master_sha
-
- def ack_addr(self):
- return self._ack_addr
+ """A message segment that encapsulates a message acknowledgement."""
+
+ # Ack data format:
+ # 2: acked message sequence number
+ # 20: acked message total data sha1
+ # 4: acked message source IP address
+ _ACK_DATA_TEMPLATE = "! H20s4s"
+ _ACK_DATA_LEN = struct.calcsize(_ACK_DATA_TEMPLATE)
+
+ def data_template():
+ return AckSegment._ACK_DATA_TEMPLATE
+ data_template = staticmethod(data_template)
+
+ def __init__(self, segno, total_segs, msg_seq_num, master_sha):
+ """Should not be called directly."""
+ if segno != 1 or total_segs != 1:
+ raise ValueError("Acknowledgement messages must have only one segment.")
+
+ SegmentBase.__init__(self, segno, total_segs, msg_seq_num, master_sha)
+ self._type = SegmentBase._SEGMENT_TYPE_ACK
+
+ def _verify_data(ack_msg_seq_num, ack_master_sha, ack_addr):
+ # Sanity checks on the message attributes
+ if not ack_msg_seq_num or not isinstance(ack_msg_seq_num, int):
+ raise ValueError("Ack message sequnce number must be an integer.")
+ if ack_msg_seq_num < 1 or ack_msg_seq_num > 65535:
+ raise ValueError("Ack message sequence number must be between 1 and 65535 inclusive.")
+ if not ack_master_sha or not isinstance(ack_master_sha, str) or len(ack_master_sha) != 20:
+ raise ValueError("Ack message SHA1 checksum invalid.")
+ if not isinstance(ack_addr, str):
+ raise ValueError("Ack message invalid address type.")
+ try:
+ foo = socket.inet_aton(ack_addr)
+ except socket.error:
+ raise ValueError("Ack message invalid address.")
+ _verify_data = staticmethod(_verify_data)
+
+ def _make_ack_data(ack_msg_seq_num, ack_master_sha, ack_addr):
+ """Pack an ack payload."""
+ addr_data = socket.inet_aton(ack_addr)
+ data = struct.pack(AckSegment._ACK_DATA_TEMPLATE, ack_msg_seq_num,
+ ack_master_sha, addr_data)
+ return (data, _sha_data(data))
+ _make_ack_data = staticmethod(_make_ack_data)
+
+ def new_from_parts(addr, msg_seq_num, ack_msg_seq_num, ack_master_sha, ack_addr):
+ """Static constructor for creation from individual attributes."""
+
+ AckSegment._verify_data(ack_msg_seq_num, ack_master_sha, ack_addr)
+ (data, data_sha) = AckSegment._make_ack_data(ack_msg_seq_num,
+ ack_master_sha, ack_addr)
+ segment = AckSegment(1, 1, msg_seq_num, data_sha)
+ segment._data_len = AckSegment._ACK_DATA_LEN
+ segment._data = data
+ SegmentBase._validate_address(addr)
+ segment._addr = addr
+
+ segment._ack_msg_seq_num = ack_msg_seq_num
+ segment._ack_master_sha = ack_master_sha
+ segment._ack_addr = ack_addr
+ return segment
+ new_from_parts = staticmethod(new_from_parts)
+
+ def _unpack_data(self, stream, data_len):
+ if data_len != self._ACK_DATA_LEN:
+ raise ValueError("Ack segment data had invalid length.")
+ data = stream.read(data_len)
+ (ack_msg_seq_num, ack_master_sha, ack_addr_data) = struct.unpack(self._ACK_DATA_TEMPLATE, data)
+ try:
+ ack_addr = socket.inet_ntoa(ack_addr_data)
+ except socket.error:
+ raise ValueError("Ack segment data had invalid address.")
+ AckSegment._verify_data(ack_msg_seq_num, ack_master_sha, ack_addr)
+
+ self._data = data
+ self._data_len = data_len
+ self._ack_msg_seq_num = ack_msg_seq_num
+ self._ack_master_sha = ack_master_sha
+ self._ack_addr = ack_addr
+
+ def ack_msg_seq_num(self):
+ return self._ack_msg_seq_num
+
+ def ack_master_sha(self):
+ return self._ack_master_sha
+
+ def ack_addr(self):
+ return self._ack_addr
class Message(object):
- """Tracks an entire message object, which is composed of a number
- of individual segments."""
- def __init__(self, src_addr, msg_seq_num, msg_sha, total_segments):
- self._rt_target = 0
- self._next_rt_time = 0
- self._last_incoming_time = 0
- self._segments = {}
- self._complete = False
- self._dispatched_time = 0
- self._data = None
- self._data_sha = None
- self._src_addr = src_addr
- self._msg_seq_num = msg_seq_num
- self._msg_sha = msg_sha
- self._total_segments = total_segments
- self._rt_tries = {}
- for i in range(1, self._total_segments + 1):
- self._rt_tries[i] = 0
-
- def __del__(self):
- self.clear()
-
- def sha(self):
- return self._msg_sha
-
- def source_address(self):
- return self._src_addr
-
- def clear(self):
- for key in self._segments.keys()[:]:
- del self._segments[key]
- del self._rt_tries[key]
- self._segments = {}
- self._rt_tries = {}
-
- def has_segment(self, segno):
- return self._segments.has_key(segno)
-
- def first_missing(self):
- for i in range(1, self._total_segments + 1):
- if not self._segments.has_key(i):
- return i
- return 0
-
- _DEF_RT_REQUEST_INTERVAL = 0.09 # 70ms (in seconds)
- def update_rt_wait(self, now):
- """now argument should be in seconds."""
- wait = self._DEF_RT_REQUEST_INTERVAL
- if self._last_incoming_time > now - 0.02:
- msg_completeness = float(len(self._segments)) / float(self._total_segments)
- wait = wait + (self._DEF_RT_REQUEST_INTERVAL * (1.0 - msg_completeness))
- self._next_rt_time = now + wait
-
- def add_segment(self, segment):
- if self.complete():
- return
- segno = segment.segment_number()
- if self._segments.has_key(segno):
- return
- self._segments[segno] = segment
- self._rt_tries[segno] = 0
- now = time.time()
- self._last_incoming_time = now
-
- num_segs = len(self._segments)
- if num_segs == self._total_segments:
- self._complete = True
- self._next_rt_time = 0
- self._data = ''
- for seg in self._segments.values():
- self._data = self._data + seg.data()
- self._data_sha = _sha_data(self._data)
- elif segno == num_segs or num_segs == 1:
- # If we're not missing segments, push back retransmit request
- self.update_rt_wait(now)
-
- def get_retransmit_message(self, msg_seq_num, segno):
- if segno < 1 or segno > self._total_segments:
- return None
- seg = RetransmitSegment.new_from_parts(self._src_addr, msg_seq_num,
- self._msg_seq_num, self._msg_sha, segno)
- self._rt_tries[segno] = self._rt_tries[segno] + 1
- self.update_rt_wait(time.time())
- return seg
-
- def complete(self):
- return self._complete
-
- def dispatch_time(self):
- return self._dispatch_time
-
- def set_dispatch_time(self):
- self._dispatch_time = time.time()
-
- def data(self):
- return (self._data, self._data_sha)
-
- def last_incoming_time(self):
- return self._last_incoming_time
-
- def next_rt_time(self):
- return self._next_rt_time
-
- def rt_tries(self, segno):
- if self._rt_tries.has_key(segno):
- return self._rt_tries[segno]
- return 0
+ """Tracks an entire message object, which is composed of a number
+ of individual segments."""
+ def __init__(self, src_addr, msg_seq_num, msg_sha, total_segments):
+ self._rt_target = 0
+ self._next_rt_time = 0
+ self._last_incoming_time = 0
+ self._segments = {}
+ self._complete = False
+ self._dispatched_time = 0
+ self._data = None
+ self._data_sha = None
+ self._src_addr = src_addr
+ self._msg_seq_num = msg_seq_num
+ self._msg_sha = msg_sha
+ self._total_segments = total_segments
+ self._rt_tries = {}
+ for i in range(1, self._total_segments + 1):
+ self._rt_tries[i] = 0
+
+ def __del__(self):
+ self.clear()
+
+ def sha(self):
+ return self._msg_sha
+
+ def source_address(self):
+ return self._src_addr
+
+ def clear(self):
+ for key in self._segments.keys()[:]:
+ del self._segments[key]
+ del self._rt_tries[key]
+ self._segments = {}
+ self._rt_tries = {}
+
+ def has_segment(self, segno):
+ return self._segments.has_key(segno)
+
+ def first_missing(self):
+ for i in range(1, self._total_segments + 1):
+ if not self._segments.has_key(i):
+ return i
+ return 0
+
+ _DEF_RT_REQUEST_INTERVAL = 0.09 # 70ms (in seconds)
+ def update_rt_wait(self, now):
+ """now argument should be in seconds."""
+ wait = self._DEF_RT_REQUEST_INTERVAL
+ if self._last_incoming_time > now - 0.02:
+ msg_completeness = float(len(self._segments)) / float(self._total_segments)
+ wait = wait + (self._DEF_RT_REQUEST_INTERVAL * (1.0 - msg_completeness))
+ self._next_rt_time = now + wait
+
+ def add_segment(self, segment):
+ if self.complete():
+ return
+ segno = segment.segment_number()
+ if self._segments.has_key(segno):
+ return
+ self._segments[segno] = segment
+ self._rt_tries[segno] = 0
+ now = time.time()
+ self._last_incoming_time = now
+
+ num_segs = len(self._segments)
+ if num_segs == self._total_segments:
+ self._complete = True
+ self._next_rt_time = 0
+ self._data = ''
+ for seg in self._segments.values():
+ self._data = self._data + seg.data()
+ self._data_sha = _sha_data(self._data)
+ elif segno == num_segs or num_segs == 1:
+ # If we're not missing segments, push back retransmit request
+ self.update_rt_wait(now)
+
+ def get_retransmit_message(self, msg_seq_num, segno):
+ if segno < 1 or segno > self._total_segments:
+ return None
+ seg = RetransmitSegment.new_from_parts(self._src_addr, msg_seq_num,
+ self._msg_seq_num, self._msg_sha, segno)
+ self._rt_tries[segno] = self._rt_tries[segno] + 1
+ self.update_rt_wait(time.time())
+ return seg
+
+ def complete(self):
+ return self._complete
+
+ def dispatch_time(self):
+ return self._dispatch_time
+
+ def set_dispatch_time(self):
+ self._dispatch_time = time.time()
+
+ def data(self):
+ return (self._data, self._data_sha)
+
+ def last_incoming_time(self):
+ return self._last_incoming_time
+
+ def next_rt_time(self):
+ return self._next_rt_time
+
+ def rt_tries(self, segno):
+ if self._rt_tries.has_key(segno):
+ return self._rt_tries[segno]
+ return 0
def _get_local_interfaces():
- import array
- import struct
- import fcntl
- import socket
+ import array
+ import struct
+ import fcntl
+ import socket
- max_possible = 4
- bytes = max_possible * 32
- SIOCGIFCONF = 0x8912
- names = array.array('B', '\0' * bytes)
+ max_possible = 4
+ bytes = max_possible * 32
+ SIOCGIFCONF = 0x8912
+ names = array.array('B', '\0' * bytes)
- sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- ifreq = struct.pack('iL', bytes, names.buffer_info()[0])
- result = fcntl.ioctl(sockfd.fileno(), SIOCGIFCONF, ifreq)
- sockfd.close()
+ sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ ifreq = struct.pack('iL', bytes, names.buffer_info()[0])
+ result = fcntl.ioctl(sockfd.fileno(), SIOCGIFCONF, ifreq)
+ sockfd.close()
- outbytes = struct.unpack('iL', result)[0]
- namestr = names.tostring()
+ outbytes = struct.unpack('iL', result)[0]
+ namestr = names.tostring()
- return [namestr[i:i+32].split('\0', 1)[0] for i in range(0, outbytes, 32)]
+ return [namestr[i:i+32].split('\0', 1)[0] for i in range(0, outbytes, 32)]
def _get_local_ip_addresses():
- """Call Linux specific bits to retrieve our own IP address."""
- import socket
- import sys
- import fcntl
- import struct
-
- intfs = _get_local_interfaces()
-
- ips = []
- SIOCGIFADDR = 0x8915
- sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- for intf in intfs:
- if intf == "lo":
- continue
- try:
- ifreq = (intf + '\0'*32)[:32]
- result = fcntl.ioctl(sockfd.fileno(), SIOCGIFADDR, ifreq)
- addr = socket.inet_ntoa(result[20:24])
- ips.append(addr)
- except IOError, exc:
- print "Error getting IP address: %s" % exc
- sockfd.close()
- return ips
+ """Call Linux specific bits to retrieve our own IP address."""
+ import socket
+ import sys
+ import fcntl
+ import struct
+
+ intfs = _get_local_interfaces()
+
+ ips = []
+ SIOCGIFADDR = 0x8915
+ sockfd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ for intf in intfs:
+ if intf == "lo":
+ continue
+ try:
+ ifreq = (intf + '\0'*32)[:32]
+ result = fcntl.ioctl(sockfd.fileno(), SIOCGIFADDR, ifreq)
+ addr = socket.inet_ntoa(result[20:24])
+ ips.append(addr)
+ except IOError, exc:
+ print "Error getting IP address: %s" % exc
+ sockfd.close()
+ return ips
class MostlyReliablePipe(object):
- """Implement Mostly-Reliable UDP. We don't actually care about guaranteeing
- delivery or receipt, just a better effort than no effort at all."""
-
- _UDP_MSG_SIZE = SegmentBase.mtu() + SegmentBase.header_len()
- _SEGMENT_TTL = 120 # 2 minutes
-
- def __init__(self, local_addr, remote_addr, port, data_cb, user_data=None):
- self._local_addr = local_addr
- self._remote_addr = remote_addr
- self._port = port
- self._data_cb = data_cb
- self._user_data = user_data
- self._started = False
- self._send_worker = 0
- self._seq_counter = 0
- self._drop_prob = 0
- self._rt_check_worker_id = 0
-
- self._outgoing = []
- self._sent = {}
-
- self._incoming = {} # (message sha, # of segments) -> [segment1, segment2, ...]
- self._dispatched = {}
- self._acks = {} # (message sequence #, master sha, source addr) -> received timestamp
- self._ack_check_worker_id = 0
-
- self._local_ips = _get_local_ip_addresses()
-
- self._setup_listener()
- self._setup_sender()
-
- def __del__(self):
- if self._send_worker > 0:
- gobject.source_remove(self._send_worker)
- self._send_worker = 0
- if self._rt_check_worker_id > 0:
- gobject.source_remove(self._rt_check_worker_id)
- self._rt_check_worker_id = 0
- if self._ack_check_worker_id > 0:
- gobject.source_remove(self._ack_check_worker_id)
- self._ack_check_worker_id = 0
-
- def _setup_sender(self):
- """Setup the send socket for multicast."""
- self._send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- # Make the socket multicast-aware, and set TTL.
- self._send_sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 20) # Change TTL (=20) to suit
-
- def _setup_listener(self):
- """Set up the listener socket for multicast traffic."""
- # Listener socket
- self._listen_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
-
- # Set some options to make it multicast-friendly
- self._listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_TTL, 20)
- self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
-
- def start(self):
- """Let the listener socket start listening for network data."""
- # Set some more multicast options
- self._listen_sock.bind((self._local_addr, self._port))
- self._listen_sock.settimeout(2)
+ """Implement Mostly-Reliable UDP. We don't actually care about guaranteeing
+ delivery or receipt, just a better effort than no effort at all."""
+
+ _UDP_MSG_SIZE = SegmentBase.mtu() + SegmentBase.header_len()
+ _SEGMENT_TTL = 120 # 2 minutes
+
+ def __init__(self, local_addr, remote_addr, port, data_cb, user_data=None):
+ self._local_addr = local_addr
+ self._remote_addr = remote_addr
+ self._port = port
+ self._data_cb = data_cb
+ self._user_data = user_data
+ self._started = False
+ self._send_worker = 0
+ self._seq_counter = 0
+ self._drop_prob = 0
+ self._rt_check_worker_id = 0
+
+ self._outgoing = []
+ self._sent = {}
+
+ self._incoming = {} # (message sha, # of segments) -> [segment1, segment2, ...]
+ self._dispatched = {}
+ self._acks = {} # (message sequence #, master sha, source addr) -> received timestamp
+ self._ack_check_worker_id = 0
+
+ self._local_ips = _get_local_ip_addresses()
+
+ self._setup_listener()
+ self._setup_sender()
+
+ def __del__(self):
+ if self._send_worker > 0:
+ gobject.source_remove(self._send_worker)
+ self._send_worker = 0
+ if self._rt_check_worker_id > 0:
+ gobject.source_remove(self._rt_check_worker_id)
+ self._rt_check_worker_id = 0
+ if self._ack_check_worker_id > 0:
+ gobject.source_remove(self._ack_check_worker_id)
+ self._ack_check_worker_id = 0
+
+ def _setup_sender(self):
+ """Setup the send socket for multicast."""
+ self._send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ # Make the socket multicast-aware, and set TTL.
+ self._send_sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 20) # Change TTL (=20) to suit
+
+ def _setup_listener(self):
+ """Set up the listener socket for multicast traffic."""
+ # Listener socket
+ self._listen_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+
+ # Set some options to make it multicast-friendly
+ self._listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_TTL, 20)
+ self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
+
+ def start(self):
+ """Let the listener socket start listening for network data."""
+ # Set some more multicast options
+ self._listen_sock.bind((self._local_addr, self._port))
+ self._listen_sock.settimeout(2)
# Disable for now to try to fix "cannot assign requested address" errors
-# intf = socket.gethostbyname(socket.gethostname())
-# self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF,
-# socket.inet_aton(intf) + socket.inet_aton('0.0.0.0'))
- self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP,
- socket.inet_aton(self._remote_addr) + socket.inet_aton('0.0.0.0'))
-
- # Watch the listener socket for data
- gobject.io_add_watch(self._listen_sock, gobject.IO_IN, self._handle_incoming_data)
- gobject.timeout_add(self._SEGMENT_TTL * 1000, self._segment_ttl_worker)
- self._rt_check_worker_id = gobject.timeout_add(50, self._retransmit_check_worker)
- self._ack_check_worker_id = gobject.timeout_add(50, self._ack_check_worker)
-
- self._started = True
-
- def _segment_ttl_worker(self):
- """Cull already-sent message segments that are past their TTL."""
- now = time.time()
- for key in self._sent.keys()[:]:
- segment = self._sent[key]
- if segment.stime() < now - self._SEGMENT_TTL:
- if segment.userdata:
- gobject.source_remove(segment.userdata)
- del self._sent[key]
-
- # Cull incomplete incoming segment chains that haven't gotten any data
- # for a long time either
- for msg_key in self._incoming.keys()[:]:
- message = self._incoming[msg_key]
- if message.last_incoming_time() < now - self._SEGMENT_TTL:
- del self._incoming[msg_key]
-
- # Remove already received and dispatched messages after a while
- for msg_key in self._dispatched.keys()[:]:
- message = self._dispatched[msg_key]
- if message.dispatch_time() < now - (self._SEGMENT_TTL*2):
- del self._dispatched[msg_key]
-
- # Remove received acks after a while
- for ack_key in self._acks.keys()[:]:
- ack_time = self._acks[ack_key]
- if ack_time < now - (self._SEGMENT_TTL*2):
- del self._acks[ack_key]
-
- return True
-
- _MAX_SEGMENT_RETRIES = 10
- def _retransmit_request(self, message):
- """Returns true if the message has exceeded it's retry limit."""
- first_missing = message.first_missing()
- if first_missing > 0:
- num_retries = message.rt_tries(first_missing)
- if num_retries > self._MAX_SEGMENT_RETRIES:
- return True
- msg_seq = self._next_msg_seq()
- seg = message.get_retransmit_message(msg_seq, first_missing)
- if seg:
- print "(MRP): Requesting retransmit of %d by %s" % (first_missing, message.source_address())
- self._outgoing.append(seg)
- self._schedule_send_worker()
- return False
-
- def _retransmit_check_worker(self):
- """Periodically check for and send retransmit requests for message
- segments that got lost."""
- try:
- now = time.time()
- for key in self._incoming.keys()[:]:
- message = self._incoming[key]
- if message.complete():
- continue
- next_rt = message.next_rt_time()
- if next_rt == 0 or next_rt > now:
- continue
- if self._retransmit_request(message):
- # Kill the message, too many retries
- print "(MRP): Dropped message %s, exceeded retries." % _stringify_sha(message.sha())
- self._dispatched[key] = message
- message.set_dispatch_time()
- del self._incoming[key]
- except KeyboardInterrupt:
- return False
- return True
-
- def _process_incoming_data(self, segment):
- """Handle a new message segment. First checks if there is only one
- segment to the message, and if the checksum from the header matches
- that computed from the data, dispatches it. Otherwise, it adds the
- new segment to the list of other segments for that message, and
- checks to see if the message is complete. If all segments are present,
- the message is reassembled and dispatched."""
-
- msg_sha = segment.master_sha()
- nsegs = segment.total_segments()
- addr = segment.address()
- segno = segment.segment_number()
-
- msg_seq_num = segment.message_sequence_number()
- msg_key = (addr[0], msg_seq_num, msg_sha, nsegs)
-
- if self._dispatched.has_key(msg_key):
- # We already dispatched this message, this segment is useless
- return
- # First segment in the message
- if not self._incoming.has_key(msg_key):
- self._incoming[msg_key] = Message((addr[0], self._port), msg_seq_num, msg_sha, nsegs)
- # Acknowledge the message if it didn't come from us
- if addr[0] not in self._local_ips:
- ack_key = (msg_seq_num, msg_sha, addr[0])
- if not self._acks.has_key(ack_key):
- self._send_ack_for_message(msg_seq_num, msg_sha, addr[0])
-
- message = self._incoming[msg_key]
- # Look for a dupe, and if so, drop the new segment
- if message.has_segment(segno):
- return
- message.add_segment(segment)
-
- # Dispatch the message if all segments are present and the sha is correct
- if message.complete():
- (msg_data, complete_data_sha) = message.data()
- if msg_sha == complete_data_sha:
- self._data_cb(addr, msg_data, self._user_data)
- self._dispatched[msg_key] = message
- message.set_dispatch_time()
- del self._incoming[msg_key]
- return
-
- def _segment_retransmit_cb(self, key, segment):
- """Add a segment ot the outgoing queue and schedule its transmission."""
- del self._sent[key]
- self._outgoing.append(segment)
- self._schedule_send_worker()
- return False
-
- def _schedule_segment_retransmit(self, key, segment, when, now):
- """Schedule retransmission of a segment if one is not already scheduled."""
- if segment.userdata:
- # Already scheduled for retransmit
- return
-
- if when <= now:
- # Immediate retransmission
- self._segment_retransmit_cb(key, segment)
- else:
- # convert time to milliseconds
- timeout = int((when - now) * 1000)
- segment.userdata = gobject.timeout_add(timeout, self._segment_retransmit_cb,
- key, segment)
-
- _STD_RETRANSMIT_INTERVAL = 0.05 # 50ms (in seconds)
- def _process_retransmit_request(self, segment):
- """Validate and process a retransmission request."""
- key = (segment.rt_msg_seq_num(), segment.rt_master_sha(), segment.rt_segment_number())
- if not self._sent.has_key(key):
- # Either we don't know about the segment, or it was already culled
- return
-
- # Calculate next retransmission time and schedule packet for retransmit
- segment = self._sent[key]
- # only retransmit segments every 150ms or more
- now = time.time()
- next_transmit = max(now, segment.last_transmit() + self._STD_RETRANSMIT_INTERVAL)
- self._schedule_segment_retransmit(key, segment, next_transmit, now)
-
- def _ack_check_worker(self):
- """Periodically check for messages that haven't received an ack
- yet, and retransmit them."""
- try:
- now = time.time()
- for key in self._sent.keys()[:]:
- segment = self._sent[key]
- # We only care about retransmitting the first segment
- # of a message, since if other machines don't have the
- # rest of the segments, they'll issue retransmit requests
- if segment.segment_number() != 1:
- continue
- if segment.last_transmit() > now - 0.150: # 150ms
- # Was just retransmitted recently, wait longer
- # before retransmitting it
- continue
- ack_key = None
- for ip in self._local_ips:
- ack_key = (segment.message_sequence_number(), segment.master_sha(), ip)
- if self._acks.has_key(ack_key):
- break
- ack_key = None
- # If the segment already has been acked, don't send it
- # again unless somebody explicitly requests a retransmit
- if ack_key is not None:
- continue
-
- del self._sent[key]
- self._outgoing.append(segment)
- self._schedule_send_worker()
- except KeyboardInterrupt:
- return False
- return True
-
- def _send_ack_for_message(self, ack_msg_seq_num, ack_msg_sha, ack_addr):
- """Send an ack segment for a message."""
- msg_seq_num = self._next_msg_seq()
- full_remote_addr = (self._remote_addr, self._port)
- ack = AckSegment.new_from_parts(full_remote_addr, msg_seq_num,
- ack_msg_seq_num, ack_msg_sha, ack_addr)
- self._outgoing.append(ack)
- self._schedule_send_worker()
- self._process_incoming_ack(ack)
-
- def _process_incoming_ack(self, segment):
- """Save the ack so that we don't send an ack when we start getting the segments
- the ack was acknowledging."""
- # If the ack is supposed to be for a message we sent, only accept it if
- # we actually sent the message to which it refers
- ack_addr = segment.ack_addr()
- ack_master_sha = segment.ack_master_sha()
- ack_msg_seq_num = segment.ack_msg_seq_num()
- if ack_addr in self._local_ips:
- sent_key = (ack_msg_seq_num, ack_master_sha, 1)
- if not self._sent.has_key(sent_key):
- return
- ack_key = (ack_msg_seq_num, ack_master_sha, ack_addr)
- if not self._acks.has_key(ack_key):
- self._acks[ack_key] = time.time()
-
- def set_drop_probability(self, prob=4):
- """Debugging function to randomly drop incoming packets.
- The prob argument should be an integer between 1 and 10 to drop,
- or 0 to drop none. Higher numbers drop more packets."""
- if not isinstance(prob, int):
- raise ValueError("Drop probability must be an integer.")
- if prob < 1 or prob > 10:
- raise ValueError("Drop probability must be between 1 and 10 inclusive.")
- self._drop_prob = prob
-
- def _handle_incoming_data(self, source, condition):
- """Handle incoming network data by making a message segment out of it
- sending it off to the processing function."""
- if not (condition & gobject.IO_IN):
- return True
- msg = {}
- data, addr = source.recvfrom(self._UDP_MSG_SIZE)
-
- should_drop = False
- p = random.random() * 10.0
- if self._drop_prob > 0 and p <= self._drop_prob:
- should_drop = True
-
- try:
- segment = SegmentBase.new_from_data(addr, data)
- if should_drop:
- print "(MRP): Dropped segment %d." % segment.segment_number()
- else:
- stype = segment.segment_type()
- if stype == SegmentBase.type_data():
- self._process_incoming_data(segment)
- elif stype == SegmentBase.type_retransmit():
- self._process_retransmit_request(segment)
- elif stype == SegmentBase.type_ack():
- self._process_incoming_ack(segment)
- except ValueError, exc:
- print "(MRP): Bad segment: %s" % exc
- return True
-
- def _next_msg_seq(self):
- self._seq_counter = self._seq_counter + 1
- if self._seq_counter > 65535:
- self._seq_counter = 1
- return self._seq_counter
-
- def send(self, data):
- """Break data up into chunks and queue for later transmission."""
- if not self._started:
- raise Exception("Can't send anything until started!")
-
- msg_seq = self._next_msg_seq()
-
- # Pack the data into network byte order
- template = "! %ds" % len(str(data))
- data = struct.pack(template, str(data))
- master_sha = _sha_data(data)
-
- # Split up the data into segments
- left = length = len(data)
- mtu = SegmentBase.mtu()
- nmessages = length / mtu
- if length % mtu > 0:
- nmessages = nmessages + 1
- seg_num = 1
- while left > 0:
- seg = DataSegment.new_from_parts(seg_num, nmessages,
- msg_seq, master_sha, data[:mtu])
- self._outgoing.append(seg)
- seg_num = seg_num + 1
- data = data[mtu:]
- left = left - mtu
- self._schedule_send_worker()
-
- def _schedule_send_worker(self):
- if len(self._outgoing) > 0 and self._send_worker == 0:
- self._send_worker = gobject.timeout_add(50, self._send_worker_cb)
-
- def _send_worker_cb(self):
- """Send all queued segments that have yet to be transmitted."""
- self._send_worker = 0
- nsent = 0
- for segment in self._outgoing:
- packet = segment.packetize()
- segment.inc_transmits()
- addr = (self._remote_addr, self._port)
- if segment.address():
- addr = segment.address()
- self._send_sock.sendto(packet, addr)
- if segment.userdata:
- gobject.source_remove(segment.userdata)
- segment.userdata = None # Retransmission GSource
- key = (segment.message_sequence_number(), segment.master_sha(), segment.segment_number())
- self._sent[key] = segment
- nsent = nsent + 1
- if nsent > 10:
- break
- self._outgoing = self._outgoing[nsent:]
- if len(self._outgoing):
- self._schedule_send_worker()
- return False
+# intf = socket.gethostbyname(socket.gethostname())
+# self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF,
+# socket.inet_aton(intf) + socket.inet_aton('0.0.0.0'))
+ self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP,
+ socket.inet_aton(self._remote_addr) + socket.inet_aton('0.0.0.0'))
+
+ # Watch the listener socket for data
+ gobject.io_add_watch(self._listen_sock, gobject.IO_IN, self._handle_incoming_data)
+ gobject.timeout_add(self._SEGMENT_TTL * 1000, self._segment_ttl_worker)
+ self._rt_check_worker_id = gobject.timeout_add(50, self._retransmit_check_worker)
+ self._ack_check_worker_id = gobject.timeout_add(50, self._ack_check_worker)
+
+ self._started = True
+
+ def _segment_ttl_worker(self):
+ """Cull already-sent message segments that are past their TTL."""
+ now = time.time()
+ for key in self._sent.keys()[:]:
+ segment = self._sent[key]
+ if segment.stime() < now - self._SEGMENT_TTL:
+ if segment.userdata:
+ gobject.source_remove(segment.userdata)
+ del self._sent[key]
+
+ # Cull incomplete incoming segment chains that haven't gotten any data
+ # for a long time either
+ for msg_key in self._incoming.keys()[:]:
+ message = self._incoming[msg_key]
+ if message.last_incoming_time() < now - self._SEGMENT_TTL:
+ del self._incoming[msg_key]
+
+ # Remove already received and dispatched messages after a while
+ for msg_key in self._dispatched.keys()[:]:
+ message = self._dispatched[msg_key]
+ if message.dispatch_time() < now - (self._SEGMENT_TTL*2):
+ del self._dispatched[msg_key]
+
+ # Remove received acks after a while
+ for ack_key in self._acks.keys()[:]:
+ ack_time = self._acks[ack_key]
+ if ack_time < now - (self._SEGMENT_TTL*2):
+ del self._acks[ack_key]
+
+ return True
+
+ _MAX_SEGMENT_RETRIES = 10
+ def _retransmit_request(self, message):
+ """Returns true if the message has exceeded it's retry limit."""
+ first_missing = message.first_missing()
+ if first_missing > 0:
+ num_retries = message.rt_tries(first_missing)
+ if num_retries > self._MAX_SEGMENT_RETRIES:
+ return True
+ msg_seq = self._next_msg_seq()
+ seg = message.get_retransmit_message(msg_seq, first_missing)
+ if seg:
+ print "(MRP): Requesting retransmit of %d by %s" % (first_missing, message.source_address())
+ self._outgoing.append(seg)
+ self._schedule_send_worker()
+ return False
+
+ def _retransmit_check_worker(self):
+ """Periodically check for and send retransmit requests for message
+ segments that got lost."""
+ try:
+ now = time.time()
+ for key in self._incoming.keys()[:]:
+ message = self._incoming[key]
+ if message.complete():
+ continue
+ next_rt = message.next_rt_time()
+ if next_rt == 0 or next_rt > now:
+ continue
+ if self._retransmit_request(message):
+ # Kill the message, too many retries
+ print "(MRP): Dropped message %s, exceeded retries." % _stringify_sha(message.sha())
+ self._dispatched[key] = message
+ message.set_dispatch_time()
+ del self._incoming[key]
+ except KeyboardInterrupt:
+ return False
+ return True
+
+ def _process_incoming_data(self, segment):
+ """Handle a new message segment. First checks if there is only one
+ segment to the message, and if the checksum from the header matches
+ that computed from the data, dispatches it. Otherwise, it adds the
+ new segment to the list of other segments for that message, and
+ checks to see if the message is complete. If all segments are present,
+ the message is reassembled and dispatched."""
+
+ msg_sha = segment.master_sha()
+ nsegs = segment.total_segments()
+ addr = segment.address()
+ segno = segment.segment_number()
+
+ msg_seq_num = segment.message_sequence_number()
+ msg_key = (addr[0], msg_seq_num, msg_sha, nsegs)
+
+ if self._dispatched.has_key(msg_key):
+ # We already dispatched this message, this segment is useless
+ return
+ # First segment in the message
+ if not self._incoming.has_key(msg_key):
+ self._incoming[msg_key] = Message((addr[0], self._port), msg_seq_num, msg_sha, nsegs)
+ # Acknowledge the message if it didn't come from us
+ if addr[0] not in self._local_ips:
+ ack_key = (msg_seq_num, msg_sha, addr[0])
+ if not self._acks.has_key(ack_key):
+ self._send_ack_for_message(msg_seq_num, msg_sha, addr[0])
+
+ message = self._incoming[msg_key]
+ # Look for a dupe, and if so, drop the new segment
+ if message.has_segment(segno):
+ return
+ message.add_segment(segment)
+
+ # Dispatch the message if all segments are present and the sha is correct
+ if message.complete():
+ (msg_data, complete_data_sha) = message.data()
+ if msg_sha == complete_data_sha:
+ self._data_cb(addr, msg_data, self._user_data)
+ self._dispatched[msg_key] = message
+ message.set_dispatch_time()
+ del self._incoming[msg_key]
+ return
+
+ def _segment_retransmit_cb(self, key, segment):
+ """Add a segment ot the outgoing queue and schedule its transmission."""
+ del self._sent[key]
+ self._outgoing.append(segment)
+ self._schedule_send_worker()
+ return False
+
+ def _schedule_segment_retransmit(self, key, segment, when, now):
+ """Schedule retransmission of a segment if one is not already scheduled."""
+ if segment.userdata:
+ # Already scheduled for retransmit
+ return
+
+ if when <= now:
+ # Immediate retransmission
+ self._segment_retransmit_cb(key, segment)
+ else:
+ # convert time to milliseconds
+ timeout = int((when - now) * 1000)
+ segment.userdata = gobject.timeout_add(timeout, self._segment_retransmit_cb,
+ key, segment)
+
+ _STD_RETRANSMIT_INTERVAL = 0.05 # 50ms (in seconds)
+ def _process_retransmit_request(self, segment):
+ """Validate and process a retransmission request."""
+ key = (segment.rt_msg_seq_num(), segment.rt_master_sha(), segment.rt_segment_number())
+ if not self._sent.has_key(key):
+ # Either we don't know about the segment, or it was already culled
+ return
+
+ # Calculate next retransmission time and schedule packet for retransmit
+ segment = self._sent[key]
+ # only retransmit segments every 150ms or more
+ now = time.time()
+ next_transmit = max(now, segment.last_transmit() + self._STD_RETRANSMIT_INTERVAL)
+ self._schedule_segment_retransmit(key, segment, next_transmit, now)
+
+ def _ack_check_worker(self):
+ """Periodically check for messages that haven't received an ack
+ yet, and retransmit them."""
+ try:
+ now = time.time()
+ for key in self._sent.keys()[:]:
+ segment = self._sent[key]
+ # We only care about retransmitting the first segment
+ # of a message, since if other machines don't have the
+ # rest of the segments, they'll issue retransmit requests
+ if segment.segment_number() != 1:
+ continue
+ if segment.last_transmit() > now - 0.150: # 150ms
+ # Was just retransmitted recently, wait longer
+ # before retransmitting it
+ continue
+ ack_key = None
+ for ip in self._local_ips:
+ ack_key = (segment.message_sequence_number(), segment.master_sha(), ip)
+ if self._acks.has_key(ack_key):
+ break
+ ack_key = None
+ # If the segment already has been acked, don't send it
+ # again unless somebody explicitly requests a retransmit
+ if ack_key is not None:
+ continue
+
+ del self._sent[key]
+ self._outgoing.append(segment)
+ self._schedule_send_worker()
+ except KeyboardInterrupt:
+ return False
+ return True
+
+ def _send_ack_for_message(self, ack_msg_seq_num, ack_msg_sha, ack_addr):
+ """Send an ack segment for a message."""
+ msg_seq_num = self._next_msg_seq()
+ full_remote_addr = (self._remote_addr, self._port)
+ ack = AckSegment.new_from_parts(full_remote_addr, msg_seq_num,
+ ack_msg_seq_num, ack_msg_sha, ack_addr)
+ self._outgoing.append(ack)
+ self._schedule_send_worker()
+ self._process_incoming_ack(ack)
+
+ def _process_incoming_ack(self, segment):
+ """Save the ack so that we don't send an ack when we start getting the segments
+ the ack was acknowledging."""
+ # If the ack is supposed to be for a message we sent, only accept it if
+ # we actually sent the message to which it refers
+ ack_addr = segment.ack_addr()
+ ack_master_sha = segment.ack_master_sha()
+ ack_msg_seq_num = segment.ack_msg_seq_num()
+ if ack_addr in self._local_ips:
+ sent_key = (ack_msg_seq_num, ack_master_sha, 1)
+ if not self._sent.has_key(sent_key):
+ return
+ ack_key = (ack_msg_seq_num, ack_master_sha, ack_addr)
+ if not self._acks.has_key(ack_key):
+ self._acks[ack_key] = time.time()
+
+ def set_drop_probability(self, prob=4):
+ """Debugging function to randomly drop incoming packets.
+ The prob argument should be an integer between 1 and 10 to drop,
+ or 0 to drop none. Higher numbers drop more packets."""
+ if not isinstance(prob, int):
+ raise ValueError("Drop probability must be an integer.")
+ if prob < 1 or prob > 10:
+ raise ValueError("Drop probability must be between 1 and 10 inclusive.")
+ self._drop_prob = prob
+
+ def _handle_incoming_data(self, source, condition):
+ """Handle incoming network data by making a message segment out of it
+ sending it off to the processing function."""
+ if not (condition & gobject.IO_IN):
+ return True
+ msg = {}
+ data, addr = source.recvfrom(self._UDP_MSG_SIZE)
+
+ should_drop = False
+ p = random.random() * 10.0
+ if self._drop_prob > 0 and p <= self._drop_prob:
+ should_drop = True
+
+ try:
+ segment = SegmentBase.new_from_data(addr, data)
+ if should_drop:
+ print "(MRP): Dropped segment %d." % segment.segment_number()
+ else:
+ stype = segment.segment_type()
+ if stype == SegmentBase.type_data():
+ self._process_incoming_data(segment)
+ elif stype == SegmentBase.type_retransmit():
+ self._process_retransmit_request(segment)
+ elif stype == SegmentBase.type_ack():
+ self._process_incoming_ack(segment)
+ except ValueError, exc:
+ print "(MRP): Bad segment: %s" % exc
+ return True
+
+ def _next_msg_seq(self):
+ self._seq_counter = self._seq_counter + 1
+ if self._seq_counter > 65535:
+ self._seq_counter = 1
+ return self._seq_counter
+
+ def send(self, data):
+ """Break data up into chunks and queue for later transmission."""
+ if not self._started:
+ raise Exception("Can't send anything until started!")
+
+ msg_seq = self._next_msg_seq()
+
+ # Pack the data into network byte order
+ template = "! %ds" % len(str(data))
+ data = struct.pack(template, str(data))
+ master_sha = _sha_data(data)
+
+ # Split up the data into segments
+ left = length = len(data)
+ mtu = SegmentBase.mtu()
+ nmessages = length / mtu
+ if length % mtu > 0:
+ nmessages = nmessages + 1
+ seg_num = 1
+ while left > 0:
+ seg = DataSegment.new_from_parts(seg_num, nmessages,
+ msg_seq, master_sha, data[:mtu])
+ self._outgoing.append(seg)
+ seg_num = seg_num + 1
+ data = data[mtu:]
+ left = left - mtu
+ self._schedule_send_worker()
+
+ def _schedule_send_worker(self):
+ if len(self._outgoing) > 0 and self._send_worker == 0:
+ self._send_worker = gobject.timeout_add(50, self._send_worker_cb)
+
+ def _send_worker_cb(self):
+ """Send all queued segments that have yet to be transmitted."""
+ self._send_worker = 0
+ nsent = 0
+ for segment in self._outgoing:
+ packet = segment.packetize()
+ segment.inc_transmits()
+ addr = (self._remote_addr, self._port)
+ if segment.address():
+ addr = segment.address()
+ self._send_sock.sendto(packet, addr)
+ if segment.userdata:
+ gobject.source_remove(segment.userdata)
+ segment.userdata = None # Retransmission GSource
+ key = (segment.message_sequence_number(), segment.master_sha(), segment.segment_number())
+ self._sent[key] = segment
+ nsent = nsent + 1
+ if nsent > 10:
+ break
+ self._outgoing = self._outgoing[nsent:]
+ if len(self._outgoing):
+ self._schedule_send_worker()
+ return False
#################################################################
@@ -988,348 +988,348 @@ import unittest
class SegmentBaseTestCase(unittest.TestCase):
- _DEF_SEGNO = 1
- _DEF_TOT_SEGS = 5
- _DEF_MSG_SEQ_NUM = 4556
- _DEF_MASTER_SHA = "12345678901234567890"
- _DEF_SEG_TYPE = 0
+ _DEF_SEGNO = 1
+ _DEF_TOT_SEGS = 5
+ _DEF_MSG_SEQ_NUM = 4556
+ _DEF_MASTER_SHA = "12345678901234567890"
+ _DEF_SEG_TYPE = 0
- _DEF_ADDRESS = ('123.3.2.1', 3333)
- _SEG_MAGIC = 0xbaea4304
+ _DEF_ADDRESS = ('123.3.2.1', 3333)
+ _SEG_MAGIC = 0xbaea4304
class SegmentBaseInitTestCase(SegmentBaseTestCase):
- def _test_init_fail(self, segno, total_segs, msg_seq_num, master_sha, fail_msg):
- try:
- seg = SegmentBase(segno, total_segs, msg_seq_num, master_sha)
- except ValueError, exc:
- pass
- else:
- self.fail("expected a ValueError for %s." % fail_msg)
-
- def testSegmentBase(self):
- assert SegmentBase.magic() == self._SEG_MAGIC, "Segment magic wasn't correct!"
- assert SegmentBase.header_len() > 0, "header size was not greater than zero."
- assert SegmentBase.mtu() > 0, "MTU was not greater than zero."
- assert SegmentBase.mtu() + SegmentBase.header_len() == _UDP_DATAGRAM_SIZE, "MTU + header size didn't equal expected %d." % _UDP_DATAGRAM_SIZE
-
- def testGoodInit(self):
- seg = SegmentBase(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA)
- assert seg.stime() < time.time(), "segment start time is less than now!"
- assert not seg.address(), "Segment address was not None after init."
- assert seg.segment_number() == self._DEF_SEGNO, "Segment number wasn't correct after init."
- assert seg.total_segments() == self._DEF_TOT_SEGS, "Total segments wasn't correct after init."
- assert seg.message_sequence_number() == self._DEF_MSG_SEQ_NUM, "Message sequence number wasn't correct after init."
- assert seg.master_sha() == self._DEF_MASTER_SHA, "Message master SHA wasn't correct after init."
- assert seg.segment_type() == None, "Segment type was not None after init."
- assert seg.transmits() == 0, "Segment transmits was not 0 after init."
- assert seg.last_transmit() == 0, "Segment last transmit was not 0 after init."
- assert seg.data() == None, "Segment data was not None after init."
-
- def testSegmentNumber(self):
- self._test_init_fail(0, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid segment number")
- self._test_init_fail(65536, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid segment number")
- self._test_init_fail(None, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid segment number")
- self._test_init_fail("", self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid segment number")
-
- def testTotalMessageSegmentNumber(self):
- self._test_init_fail(self._DEF_SEGNO, 0, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid total segments")
- self._test_init_fail(self._DEF_SEGNO, 65536, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid total segments")
- self._test_init_fail(self._DEF_SEGNO, None, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid total segments")
- self._test_init_fail(self._DEF_SEGNO, "", self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid total segments")
-
- def testMessageSequenceNumber(self):
- self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, 0, self._DEF_MASTER_SHA, "invalid message sequence number")
- self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, 65536, self._DEF_MASTER_SHA, "invalid message sequence number")
- self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, None, self._DEF_MASTER_SHA, "invalid message sequence number")
- self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, "", self._DEF_MASTER_SHA, "invalid message sequence number")
-
- def testMasterSHA(self):
- self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, "1" * 19, "invalid SHA1 data hash")
- self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, "1" * 21, "invalid SHA1 data hash")
- self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, None, "invalid SHA1 data hash")
- self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, 1234, "invalid SHA1 data hash")
-
- def _testNewFromDataFail(self, addr, data, fail_msg):
- try:
- seg = SegmentBase.new_from_data(addr, data)
- except ValueError, exc:
- pass
- else:
- self.fail("expected a ValueError about %s." % fail_msg)
-
- def testNewFromDataAddress(self):
- self._testNewFromDataFail(None, None, "bad address")
- self._testNewFromDataFail('', None, "bad address")
- self._testNewFromDataFail((''), None, "bad address")
- self._testNewFromDataFail((1), None, "bad address")
- self._testNewFromDataFail(('', ''), None, "bad address")
- self._testNewFromDataFail((1, 3333), None, "bad address")
- self._testNewFromDataFail(('', 0), None, "bad address")
- self._testNewFromDataFail(('', 65536), None, "bad address")
-
- def testNewFromDataData(self):
- """Only test generic new_from_data() bits, not type-specific ones."""
- self._testNewFromDataFail(self._DEF_ADDRESS, None, "invalid data")
-
- really_short_data = "111"
- self._testNewFromDataFail(self._DEF_ADDRESS, really_short_data, "data too short")
-
- only_header_data = "1" * SegmentBase.header_len()
- self._testNewFromDataFail(self._DEF_ADDRESS, only_header_data, "data too short")
-
- too_much_data = "1" * (_UDP_DATAGRAM_SIZE + 1)
- self._testNewFromDataFail(self._DEF_ADDRESS, too_much_data, "too much data")
-
- header_template = SegmentBase.header_template()
- bad_magic_data = struct.pack(header_template, 0x12345678, self._DEF_SEG_TYPE,
- self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA)
- self._testNewFromDataFail(self._DEF_ADDRESS, bad_magic_data, "invalid magic")
-
- bad_type_data = struct.pack(header_template, self._SEG_MAGIC, -1, self._DEF_SEGNO,
- self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA)
- self._testNewFromDataFail(self._DEF_ADDRESS, bad_type_data, "invalid segment type")
-
- # Test master_sha that doesn't match data's SHA
- header = struct.pack(header_template, self._SEG_MAGIC, self._DEF_SEG_TYPE, 1, 1,
- self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA)
- data = struct.pack("! 15s", "7" * 15)
- self._testNewFromDataFail(self._DEF_ADDRESS, header + data, "single-segment message SHA mismatch")
-
- def addToSuite(suite):
- suite.addTest(SegmentBaseInitTestCase("testGoodInit"))
- suite.addTest(SegmentBaseInitTestCase("testSegmentNumber"))
- suite.addTest(SegmentBaseInitTestCase("testTotalMessageSegmentNumber"))
- suite.addTest(SegmentBaseInitTestCase("testMessageSequenceNumber"))
- suite.addTest(SegmentBaseInitTestCase("testMasterSHA"))
- suite.addTest(SegmentBaseInitTestCase("testNewFromDataAddress"))
- suite.addTest(SegmentBaseInitTestCase("testNewFromDataData"))
- addToSuite = staticmethod(addToSuite)
+ def _test_init_fail(self, segno, total_segs, msg_seq_num, master_sha, fail_msg):
+ try:
+ seg = SegmentBase(segno, total_segs, msg_seq_num, master_sha)
+ except ValueError, exc:
+ pass
+ else:
+ self.fail("expected a ValueError for %s." % fail_msg)
+
+ def testSegmentBase(self):
+ assert SegmentBase.magic() == self._SEG_MAGIC, "Segment magic wasn't correct!"
+ assert SegmentBase.header_len() > 0, "header size was not greater than zero."
+ assert SegmentBase.mtu() > 0, "MTU was not greater than zero."
+ assert SegmentBase.mtu() + SegmentBase.header_len() == _UDP_DATAGRAM_SIZE, "MTU + header size didn't equal expected %d." % _UDP_DATAGRAM_SIZE
+
+ def testGoodInit(self):
+ seg = SegmentBase(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA)
+ assert seg.stime() < time.time(), "segment start time is less than now!"
+ assert not seg.address(), "Segment address was not None after init."
+ assert seg.segment_number() == self._DEF_SEGNO, "Segment number wasn't correct after init."
+ assert seg.total_segments() == self._DEF_TOT_SEGS, "Total segments wasn't correct after init."
+ assert seg.message_sequence_number() == self._DEF_MSG_SEQ_NUM, "Message sequence number wasn't correct after init."
+ assert seg.master_sha() == self._DEF_MASTER_SHA, "Message master SHA wasn't correct after init."
+ assert seg.segment_type() == None, "Segment type was not None after init."
+ assert seg.transmits() == 0, "Segment transmits was not 0 after init."
+ assert seg.last_transmit() == 0, "Segment last transmit was not 0 after init."
+ assert seg.data() == None, "Segment data was not None after init."
+
+ def testSegmentNumber(self):
+ self._test_init_fail(0, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid segment number")
+ self._test_init_fail(65536, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid segment number")
+ self._test_init_fail(None, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid segment number")
+ self._test_init_fail("", self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid segment number")
+
+ def testTotalMessageSegmentNumber(self):
+ self._test_init_fail(self._DEF_SEGNO, 0, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid total segments")
+ self._test_init_fail(self._DEF_SEGNO, 65536, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid total segments")
+ self._test_init_fail(self._DEF_SEGNO, None, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid total segments")
+ self._test_init_fail(self._DEF_SEGNO, "", self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid total segments")
+
+ def testMessageSequenceNumber(self):
+ self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, 0, self._DEF_MASTER_SHA, "invalid message sequence number")
+ self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, 65536, self._DEF_MASTER_SHA, "invalid message sequence number")
+ self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, None, self._DEF_MASTER_SHA, "invalid message sequence number")
+ self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, "", self._DEF_MASTER_SHA, "invalid message sequence number")
+
+ def testMasterSHA(self):
+ self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, "1" * 19, "invalid SHA1 data hash")
+ self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, "1" * 21, "invalid SHA1 data hash")
+ self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, None, "invalid SHA1 data hash")
+ self._test_init_fail(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, 1234, "invalid SHA1 data hash")
+
+ def _testNewFromDataFail(self, addr, data, fail_msg):
+ try:
+ seg = SegmentBase.new_from_data(addr, data)
+ except ValueError, exc:
+ pass
+ else:
+ self.fail("expected a ValueError about %s." % fail_msg)
+
+ def testNewFromDataAddress(self):
+ self._testNewFromDataFail(None, None, "bad address")
+ self._testNewFromDataFail('', None, "bad address")
+ self._testNewFromDataFail((''), None, "bad address")
+ self._testNewFromDataFail((1), None, "bad address")
+ self._testNewFromDataFail(('', ''), None, "bad address")
+ self._testNewFromDataFail((1, 3333), None, "bad address")
+ self._testNewFromDataFail(('', 0), None, "bad address")
+ self._testNewFromDataFail(('', 65536), None, "bad address")
+
+ def testNewFromDataData(self):
+ """Only test generic new_from_data() bits, not type-specific ones."""
+ self._testNewFromDataFail(self._DEF_ADDRESS, None, "invalid data")
+
+ really_short_data = "111"
+ self._testNewFromDataFail(self._DEF_ADDRESS, really_short_data, "data too short")
+
+ only_header_data = "1" * SegmentBase.header_len()
+ self._testNewFromDataFail(self._DEF_ADDRESS, only_header_data, "data too short")
+
+ too_much_data = "1" * (_UDP_DATAGRAM_SIZE + 1)
+ self._testNewFromDataFail(self._DEF_ADDRESS, too_much_data, "too much data")
+
+ header_template = SegmentBase.header_template()
+ bad_magic_data = struct.pack(header_template, 0x12345678, self._DEF_SEG_TYPE,
+ self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA)
+ self._testNewFromDataFail(self._DEF_ADDRESS, bad_magic_data, "invalid magic")
+
+ bad_type_data = struct.pack(header_template, self._SEG_MAGIC, -1, self._DEF_SEGNO,
+ self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA)
+ self._testNewFromDataFail(self._DEF_ADDRESS, bad_type_data, "invalid segment type")
+
+ # Test master_sha that doesn't match data's SHA
+ header = struct.pack(header_template, self._SEG_MAGIC, self._DEF_SEG_TYPE, 1, 1,
+ self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA)
+ data = struct.pack("! 15s", "7" * 15)
+ self._testNewFromDataFail(self._DEF_ADDRESS, header + data, "single-segment message SHA mismatch")
+
+ def addToSuite(suite):
+ suite.addTest(SegmentBaseInitTestCase("testGoodInit"))
+ suite.addTest(SegmentBaseInitTestCase("testSegmentNumber"))
+ suite.addTest(SegmentBaseInitTestCase("testTotalMessageSegmentNumber"))
+ suite.addTest(SegmentBaseInitTestCase("testMessageSequenceNumber"))
+ suite.addTest(SegmentBaseInitTestCase("testMasterSHA"))
+ suite.addTest(SegmentBaseInitTestCase("testNewFromDataAddress"))
+ suite.addTest(SegmentBaseInitTestCase("testNewFromDataData"))
+ addToSuite = staticmethod(addToSuite)
class DataSegmentTestCase(SegmentBaseTestCase):
- """Test DataSegment class specific initialization and stuff."""
-
- def testInit(self):
- seg = DataSegment(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM,
- self._DEF_MASTER_SHA)
- assert seg.segment_type() == SegmentBase.type_data(), "Segment wasn't a data segment."
-
- def testNewFromParts(self):
- try:
- seg = DataSegment.new_from_parts(self._DEF_SEGNO, self._DEF_TOT_SEGS,
- self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, None)
- except ValueError, exc:
- pass
- else:
- self.fail("Expected ValueError about invalid data.")
-
- # Ensure message data is same as we stuff in after object is instantiated
- payload = "How are you today?"
- seg = DataSegment.new_from_parts(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM,
- self._DEF_MASTER_SHA, payload)
- assert seg.data() == payload, "Data after segment creation didn't match expected."
-
- def testNewFromData(self):
- """Test DataSegment's new_from_data() functionality."""
-
- # Make sure something valid actually works
- header_template = SegmentBase.header_template()
- payload_str = "How are you today?"
- payload = struct.pack("! %ds" % len(payload_str), payload_str)
- payload_sha = _sha_data(payload)
- header = struct.pack(header_template, self._SEG_MAGIC, SegmentBase.type_data(), self._DEF_SEGNO,
- self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, payload_sha)
- seg = SegmentBase.new_from_data(self._DEF_ADDRESS, header + payload)
-
- assert seg.address() == self._DEF_ADDRESS, "Segment address did not match expected."
- assert seg.segment_type() == SegmentBase.type_data(), "Segment type did not match expected."
- assert seg.segment_number() == self._DEF_SEGNO, "Segment number did not match expected."
- assert seg.total_segments() == self._DEF_TOT_SEGS, "Total segments did not match expected."
- assert seg.message_sequence_number() == self._DEF_MSG_SEQ_NUM, "Message sequence number did not match expected."
- assert seg.master_sha() == payload_sha, "Message master SHA did not match expected."
- assert seg.data() == payload, "Segment data did not match expected payload."
-
- def addToSuite(suite):
- suite.addTest(DataSegmentTestCase("testInit"))
- suite.addTest(DataSegmentTestCase("testNewFromParts"))
- suite.addTest(DataSegmentTestCase("testNewFromData"))
- addToSuite = staticmethod(addToSuite)
+ """Test DataSegment class specific initialization and stuff."""
+
+ def testInit(self):
+ seg = DataSegment(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM,
+ self._DEF_MASTER_SHA)
+ assert seg.segment_type() == SegmentBase.type_data(), "Segment wasn't a data segment."
+
+ def testNewFromParts(self):
+ try:
+ seg = DataSegment.new_from_parts(self._DEF_SEGNO, self._DEF_TOT_SEGS,
+ self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, None)
+ except ValueError, exc:
+ pass
+ else:
+ self.fail("Expected ValueError about invalid data.")
+
+ # Ensure message data is same as we stuff in after object is instantiated
+ payload = "How are you today?"
+ seg = DataSegment.new_from_parts(self._DEF_SEGNO, self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM,
+ self._DEF_MASTER_SHA, payload)
+ assert seg.data() == payload, "Data after segment creation didn't match expected."
+
+ def testNewFromData(self):
+ """Test DataSegment's new_from_data() functionality."""
+
+ # Make sure something valid actually works
+ header_template = SegmentBase.header_template()
+ payload_str = "How are you today?"
+ payload = struct.pack("! %ds" % len(payload_str), payload_str)
+ payload_sha = _sha_data(payload)
+ header = struct.pack(header_template, self._SEG_MAGIC, SegmentBase.type_data(), self._DEF_SEGNO,
+ self._DEF_TOT_SEGS, self._DEF_MSG_SEQ_NUM, payload_sha)
+ seg = SegmentBase.new_from_data(self._DEF_ADDRESS, header + payload)
+
+ assert seg.address() == self._DEF_ADDRESS, "Segment address did not match expected."
+ assert seg.segment_type() == SegmentBase.type_data(), "Segment type did not match expected."
+ assert seg.segment_number() == self._DEF_SEGNO, "Segment number did not match expected."
+ assert seg.total_segments() == self._DEF_TOT_SEGS, "Total segments did not match expected."
+ assert seg.message_sequence_number() == self._DEF_MSG_SEQ_NUM, "Message sequence number did not match expected."
+ assert seg.master_sha() == payload_sha, "Message master SHA did not match expected."
+ assert seg.data() == payload, "Segment data did not match expected payload."
+
+ def addToSuite(suite):
+ suite.addTest(DataSegmentTestCase("testInit"))
+ suite.addTest(DataSegmentTestCase("testNewFromParts"))
+ suite.addTest(DataSegmentTestCase("testNewFromData"))
+ addToSuite = staticmethod(addToSuite)
class RetransmitSegmentTestCase(SegmentBaseTestCase):
- """Test RetransmitSegment class specific initialization and stuff."""
-
- def _test_init_fail(self, segno, total_segs, msg_seq_num, master_sha, fail_msg):
- try:
- seg = RetransmitSegment(segno, total_segs, msg_seq_num, master_sha)
- except ValueError, exc:
- pass
- else:
- self.fail("expected a ValueError for %s." % fail_msg)
-
- def testInit(self):
- self._test_init_fail(0, 1, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid segment number")
- self._test_init_fail(2, 1, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid segment number")
- self._test_init_fail(1, 0, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid number of total segments")
- self._test_init_fail(1, 2, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid number of total segments")
-
- # Something that's supposed to work
- seg = RetransmitSegment(1, 1, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA)
- assert seg.segment_type() == SegmentBase.type_retransmit(), "Segment wasn't a retransmit segment."
-
- def _test_new_from_parts_fail(self, msg_seq_num, rt_msg_seq_num, rt_master_sha, rt_segment_number, fail_msg):
- try:
- seg = RetransmitSegment.new_from_parts(self._DEF_ADDRESS, msg_seq_num, rt_msg_seq_num,
- rt_master_sha, rt_segment_number)
- except ValueError, exc:
- pass
- else:
- self.fail("expected a ValueError for %s." % fail_msg)
-
- def testNewFromParts(self):
- """Test RetransmitSegment's new_from_parts() functionality."""
- self._test_new_from_parts_fail(0, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA,
- self._DEF_SEGNO, "invalid message sequence number")
- self._test_new_from_parts_fail(65536, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA,
- self._DEF_SEGNO, "invalid message sequence number")
- self._test_new_from_parts_fail(None, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA,
- self._DEF_SEGNO, "invalid message sequence number")
- self._test_new_from_parts_fail("", self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA,
- self._DEF_SEGNO, "invalid message sequence number")
-
- self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, 0, self._DEF_MASTER_SHA,
- self._DEF_SEGNO, "invalid retransmit message sequence number")
- self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, 65536, self._DEF_MASTER_SHA,
- self._DEF_SEGNO, "invalid retransmit message sequence number")
- self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, None, self._DEF_MASTER_SHA,
- self._DEF_SEGNO, "invalid retransmit message sequence number")
- self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, "", self._DEF_MASTER_SHA,
- self._DEF_SEGNO, "invalid retransmit message sequence number")
-
- self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM, "1" * 19,
- self._DEF_SEGNO, "invalid retransmit message master SHA")
- self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM, "1" * 21,
- self._DEF_SEGNO, "invalid retransmit message master SHA")
- self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM, None,
- self._DEF_SEGNO, "invalid retransmit message master SHA")
- self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM, 1234,
- self._DEF_SEGNO, "invalid retransmit message master SHA")
-
- self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM,
- self._DEF_MASTER_SHA, 0, "invalid retransmit message segment number")
- self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM,
- self._DEF_MASTER_SHA, 65536, "invalid retransmit message segment number")
- self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM,
- self._DEF_MASTER_SHA, None, "invalid retransmit message segment number")
- self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM,
- self._DEF_MASTER_SHA, "", "invalid retransmit message segment number")
-
- # Ensure message data is same as we stuff in after object is instantiated
- seg = RetransmitSegment.new_from_parts(self._DEF_ADDRESS, self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM,
- self._DEF_MASTER_SHA, self._DEF_SEGNO)
- assert seg.rt_msg_seq_num() == self._DEF_MSG_SEQ_NUM, "RT message sequence number after segment creation didn't match expected."
- assert seg.rt_master_sha() == self._DEF_MASTER_SHA, "RT master SHA after segment creation didn't match expected."
- assert seg.rt_segment_number() == self._DEF_SEGNO, "RT segment number after segment creation didn't match expected."
-
- def _new_from_data(self, rt_msg_seq_num, rt_master_sha, rt_segment_number):
- payload = struct.pack(RetransmitSegment.data_template(), rt_msg_seq_num, rt_master_sha, rt_segment_number)
- payload_sha = _sha_data(payload)
- header_template = SegmentBase.header_template()
- header = struct.pack(header_template, self._SEG_MAGIC, SegmentBase.type_retransmit(), 1, 1,
- self._DEF_MSG_SEQ_NUM, payload_sha)
- return header + payload
-
- def _test_new_from_data_fail(self, rt_msg_seq_num, rt_master_sha, rt_segment_number, fail_msg):
- try:
- packet = self._new_from_data(rt_msg_seq_num, rt_master_sha, rt_segment_number)
- seg = SegmentBase.new_from_data(self._DEF_ADDRESS, packet)
- except ValueError, exc:
- pass
- else:
- self.fail("Expected a ValueError about %s." % fail_msg)
-
- def testNewFromData(self):
- """Test DataSegment's new_from_data() functionality."""
- self._test_new_from_data_fail(0, self._DEF_MASTER_SHA, self._DEF_SEGNO, "invalid RT message sequence number")
- self._test_new_from_data_fail(65536, self._DEF_MASTER_SHA, self._DEF_SEGNO, "invalid RT message sequence number")
-
- self._test_new_from_data_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, 0, "invalid RT segment number")
- self._test_new_from_data_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, 65536, "invalid RT segment number")
-
- # Ensure something that should work
- packet = self._new_from_data(self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, self._DEF_SEGNO)
- seg = SegmentBase.new_from_data(self._DEF_ADDRESS, packet)
- assert seg.segment_type() == SegmentBase.type_retransmit(), "Segment wasn't expected type."
- assert seg.rt_msg_seq_num() == self._DEF_MSG_SEQ_NUM, "Segment RT message sequence number didn't match expected."
- assert seg.rt_master_sha() == self._DEF_MASTER_SHA, "Segment RT master SHA didn't match expected."
- assert seg.rt_segment_number() == self._DEF_SEGNO, "Segment RT segment number didn't match expected."
-
- def testPartsToData(self):
- seg = RetransmitSegment.new_from_parts(self._DEF_ADDRESS, self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM,
- self._DEF_MASTER_SHA, self._DEF_SEGNO)
- new_seg = SegmentBase.new_from_data(self._DEF_ADDRESS, seg.packetize())
- assert new_seg.rt_msg_seq_num() == self._DEF_MSG_SEQ_NUM, "Segment RT message sequence number didn't match expected."
- assert new_seg.rt_master_sha() == self._DEF_MASTER_SHA, "Segment RT master SHA didn't match expected."
- assert new_seg.rt_segment_number() == self._DEF_SEGNO, "Segment RT segment number didn't match expected."
-
- def addToSuite(suite):
- suite.addTest(RetransmitSegmentTestCase("testInit"))
- suite.addTest(RetransmitSegmentTestCase("testNewFromParts"))
- suite.addTest(RetransmitSegmentTestCase("testNewFromData"))
- suite.addTest(RetransmitSegmentTestCase("testPartsToData"))
- addToSuite = staticmethod(addToSuite)
+ """Test RetransmitSegment class specific initialization and stuff."""
+
+ def _test_init_fail(self, segno, total_segs, msg_seq_num, master_sha, fail_msg):
+ try:
+ seg = RetransmitSegment(segno, total_segs, msg_seq_num, master_sha)
+ except ValueError, exc:
+ pass
+ else:
+ self.fail("expected a ValueError for %s." % fail_msg)
+
+ def testInit(self):
+ self._test_init_fail(0, 1, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid segment number")
+ self._test_init_fail(2, 1, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid segment number")
+ self._test_init_fail(1, 0, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid number of total segments")
+ self._test_init_fail(1, 2, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, "invalid number of total segments")
+
+ # Something that's supposed to work
+ seg = RetransmitSegment(1, 1, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA)
+ assert seg.segment_type() == SegmentBase.type_retransmit(), "Segment wasn't a retransmit segment."
+
+ def _test_new_from_parts_fail(self, msg_seq_num, rt_msg_seq_num, rt_master_sha, rt_segment_number, fail_msg):
+ try:
+ seg = RetransmitSegment.new_from_parts(self._DEF_ADDRESS, msg_seq_num, rt_msg_seq_num,
+ rt_master_sha, rt_segment_number)
+ except ValueError, exc:
+ pass
+ else:
+ self.fail("expected a ValueError for %s." % fail_msg)
+
+ def testNewFromParts(self):
+ """Test RetransmitSegment's new_from_parts() functionality."""
+ self._test_new_from_parts_fail(0, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA,
+ self._DEF_SEGNO, "invalid message sequence number")
+ self._test_new_from_parts_fail(65536, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA,
+ self._DEF_SEGNO, "invalid message sequence number")
+ self._test_new_from_parts_fail(None, self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA,
+ self._DEF_SEGNO, "invalid message sequence number")
+ self._test_new_from_parts_fail("", self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA,
+ self._DEF_SEGNO, "invalid message sequence number")
+
+ self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, 0, self._DEF_MASTER_SHA,
+ self._DEF_SEGNO, "invalid retransmit message sequence number")
+ self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, 65536, self._DEF_MASTER_SHA,
+ self._DEF_SEGNO, "invalid retransmit message sequence number")
+ self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, None, self._DEF_MASTER_SHA,
+ self._DEF_SEGNO, "invalid retransmit message sequence number")
+ self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, "", self._DEF_MASTER_SHA,
+ self._DEF_SEGNO, "invalid retransmit message sequence number")
+
+ self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM, "1" * 19,
+ self._DEF_SEGNO, "invalid retransmit message master SHA")
+ self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM, "1" * 21,
+ self._DEF_SEGNO, "invalid retransmit message master SHA")
+ self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM, None,
+ self._DEF_SEGNO, "invalid retransmit message master SHA")
+ self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM, 1234,
+ self._DEF_SEGNO, "invalid retransmit message master SHA")
+
+ self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM,
+ self._DEF_MASTER_SHA, 0, "invalid retransmit message segment number")
+ self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM,
+ self._DEF_MASTER_SHA, 65536, "invalid retransmit message segment number")
+ self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM,
+ self._DEF_MASTER_SHA, None, "invalid retransmit message segment number")
+ self._test_new_from_parts_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM,
+ self._DEF_MASTER_SHA, "", "invalid retransmit message segment number")
+
+ # Ensure message data is same as we stuff in after object is instantiated
+ seg = RetransmitSegment.new_from_parts(self._DEF_ADDRESS, self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM,
+ self._DEF_MASTER_SHA, self._DEF_SEGNO)
+ assert seg.rt_msg_seq_num() == self._DEF_MSG_SEQ_NUM, "RT message sequence number after segment creation didn't match expected."
+ assert seg.rt_master_sha() == self._DEF_MASTER_SHA, "RT master SHA after segment creation didn't match expected."
+ assert seg.rt_segment_number() == self._DEF_SEGNO, "RT segment number after segment creation didn't match expected."
+
+ def _new_from_data(self, rt_msg_seq_num, rt_master_sha, rt_segment_number):
+ payload = struct.pack(RetransmitSegment.data_template(), rt_msg_seq_num, rt_master_sha, rt_segment_number)
+ payload_sha = _sha_data(payload)
+ header_template = SegmentBase.header_template()
+ header = struct.pack(header_template, self._SEG_MAGIC, SegmentBase.type_retransmit(), 1, 1,
+ self._DEF_MSG_SEQ_NUM, payload_sha)
+ return header + payload
+
+ def _test_new_from_data_fail(self, rt_msg_seq_num, rt_master_sha, rt_segment_number, fail_msg):
+ try:
+ packet = self._new_from_data(rt_msg_seq_num, rt_master_sha, rt_segment_number)
+ seg = SegmentBase.new_from_data(self._DEF_ADDRESS, packet)
+ except ValueError, exc:
+ pass
+ else:
+ self.fail("Expected a ValueError about %s." % fail_msg)
+
+ def testNewFromData(self):
+ """Test DataSegment's new_from_data() functionality."""
+ self._test_new_from_data_fail(0, self._DEF_MASTER_SHA, self._DEF_SEGNO, "invalid RT message sequence number")
+ self._test_new_from_data_fail(65536, self._DEF_MASTER_SHA, self._DEF_SEGNO, "invalid RT message sequence number")
+
+ self._test_new_from_data_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, 0, "invalid RT segment number")
+ self._test_new_from_data_fail(self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, 65536, "invalid RT segment number")
+
+ # Ensure something that should work
+ packet = self._new_from_data(self._DEF_MSG_SEQ_NUM, self._DEF_MASTER_SHA, self._DEF_SEGNO)
+ seg = SegmentBase.new_from_data(self._DEF_ADDRESS, packet)
+ assert seg.segment_type() == SegmentBase.type_retransmit(), "Segment wasn't expected type."
+ assert seg.rt_msg_seq_num() == self._DEF_MSG_SEQ_NUM, "Segment RT message sequence number didn't match expected."
+ assert seg.rt_master_sha() == self._DEF_MASTER_SHA, "Segment RT master SHA didn't match expected."
+ assert seg.rt_segment_number() == self._DEF_SEGNO, "Segment RT segment number didn't match expected."
+
+ def testPartsToData(self):
+ seg = RetransmitSegment.new_from_parts(self._DEF_ADDRESS, self._DEF_MSG_SEQ_NUM, self._DEF_MSG_SEQ_NUM,
+ self._DEF_MASTER_SHA, self._DEF_SEGNO)
+ new_seg = SegmentBase.new_from_data(self._DEF_ADDRESS, seg.packetize())
+ assert new_seg.rt_msg_seq_num() == self._DEF_MSG_SEQ_NUM, "Segment RT message sequence number didn't match expected."
+ assert new_seg.rt_master_sha() == self._DEF_MASTER_SHA, "Segment RT master SHA didn't match expected."
+ assert new_seg.rt_segment_number() == self._DEF_SEGNO, "Segment RT segment number didn't match expected."
+
+ def addToSuite(suite):
+ suite.addTest(RetransmitSegmentTestCase("testInit"))
+ suite.addTest(RetransmitSegmentTestCase("testNewFromParts"))
+ suite.addTest(RetransmitSegmentTestCase("testNewFromData"))
+ suite.addTest(RetransmitSegmentTestCase("testPartsToData"))
+ addToSuite = staticmethod(addToSuite)
class SHAUtilsTestCase(unittest.TestCase):
- def testSHA(self):
- data = "235jklqt3hjwasdv879wfe89723rqjh32tr3hwaejksdvd89udsv89dsgiougjktqjhk23tjht23hjt3qhjewagthjasgdgsd"
- data_sha = _sha_data(data)
- assert len(data_sha) == 20, "SHA wasn't correct size."
- known_sha = "\xee\x9e\xb9\x1d\xe8\x96\x75\xcb\x12\xf1\x25\x22\x0f\x76\xf7\xf3\xc8\x4e\xbf\xcd"
- assert data_sha == known_sha, "SHA didn't match known SHA."
+ def testSHA(self):
+ data = "235jklqt3hjwasdv879wfe89723rqjh32tr3hwaejksdvd89udsv89dsgiougjktqjhk23tjht23hjt3qhjewagthjasgdgsd"
+ data_sha = _sha_data(data)
+ assert len(data_sha) == 20, "SHA wasn't correct size."
+ known_sha = "\xee\x9e\xb9\x1d\xe8\x96\x75\xcb\x12\xf1\x25\x22\x0f\x76\xf7\xf3\xc8\x4e\xbf\xcd"
+ assert data_sha == known_sha, "SHA didn't match known SHA."
- def testStringifySHA(self):
- data = "jlkwjlkaegdjlksgdjklsdgajklganjtwn23n325n23tjwgeajkga nafDA fwqnjlqtjkl23tjk2365jlk235jkl2356jlktjkltewjlktewjklewtjklaggsda"
- data_known_sha = "9650c23db78092a0ffda4577c87ebf36d25c868e"
- assert _stringify_sha(_sha_data(data)) == data_known_sha, "SHA stringify didn't return correct SHA."
- # Do it twice for kicks
- assert _stringify_sha(_sha_data(data)) == data_known_sha, "SHA stringify didn't return correct SHA."
+ def testStringifySHA(self):
+ data = "jlkwjlkaegdjlksgdjklsdgajklganjtwn23n325n23tjwgeajkga nafDA fwqnjlqtjkl23tjk2365jlk235jkl2356jlktjkltewjlktewjklewtjklaggsda"
+ data_known_sha = "9650c23db78092a0ffda4577c87ebf36d25c868e"
+ assert _stringify_sha(_sha_data(data)) == data_known_sha, "SHA stringify didn't return correct SHA."
+ # Do it twice for kicks
+ assert _stringify_sha(_sha_data(data)) == data_known_sha, "SHA stringify didn't return correct SHA."
- def addToSuite(suite):
- suite.addTest(SHAUtilsTestCase("testSHA"))
- suite.addTest(SHAUtilsTestCase("testStringifySHA"))
- addToSuite = staticmethod(addToSuite)
+ def addToSuite(suite):
+ suite.addTest(SHAUtilsTestCase("testSHA"))
+ suite.addTest(SHAUtilsTestCase("testStringifySHA"))
+ addToSuite = staticmethod(addToSuite)
def unit_test():
- suite = unittest.TestSuite()
- SegmentBaseInitTestCase.addToSuite(suite)
- DataSegmentTestCase.addToSuite(suite)
- RetransmitSegmentTestCase.addToSuite(suite)
- SHAUtilsTestCase.addToSuite(suite)
+ suite = unittest.TestSuite()
+ SegmentBaseInitTestCase.addToSuite(suite)
+ DataSegmentTestCase.addToSuite(suite)
+ RetransmitSegmentTestCase.addToSuite(suite)
+ SHAUtilsTestCase.addToSuite(suite)
- runner = unittest.TextTestRunner()
- runner.run(suite)
+ runner = unittest.TextTestRunner()
+ runner.run(suite)
def got_data(addr, data, user_data=None):
- print "Got data from %s, writing to %s." % (addr, user_data)
- fl = open(user_data, "w+")
- fl.write(data)
- fl.close()
+ print "Got data from %s, writing to %s." % (addr, user_data)
+ fl = open(user_data, "w+")
+ fl.write(data)
+ fl.close()
def simple_test():
- import sys
- pipe = MostlyReliablePipe('', '224.0.0.222', 2293, got_data, sys.argv[2])
-# pipe.set_drop_probability(4)
- pipe.start()
- fl = open(sys.argv[1], "r")
- data = fl.read()
- fl.close()
- msg = """The said Eliza, John, and Georgiana were now clustered round their mama in the drawing-room:
+ import sys
+ pipe = MostlyReliablePipe('', '224.0.0.222', 2293, got_data, sys.argv[2])
+# pipe.set_drop_probability(4)
+ pipe.start()
+ fl = open(sys.argv[1], "r")
+ data = fl.read()
+ fl.close()
+ msg = """The said Eliza, John, and Georgiana were now clustered round their mama in the drawing-room:
she lay reclined on a sofa by the fireside, and with her darlings about her (for the time neither
quarrelling nor crying) looked perfectly happy. Me, she had dispensed from joining the group; saying,
'She regretted to be under the necessity of keeping me at a distance; but that until she heard from
@@ -1337,58 +1337,58 @@ Bessie, and could discover by her own observation, that I was endeavouring in go
a more sociable and childlike disposition, a more attractive and sprightly manner -- something lighter,
franker, more natural, as it were -- she really must exclude me from privileges intended only for
contented, happy, little children.'"""
- pipe.send(data)
- try:
- gtk.main()
- except KeyboardInterrupt:
- print 'Ctrl+C pressed, exiting...'
+ pipe.send(data)
+ try:
+ gtk.main()
+ except KeyboardInterrupt:
+ print 'Ctrl+C pressed, exiting...'
def net_test_got_data(addr, data, user_data=None):
- # Don't report data if we are a sender
- if user_data:
- return
- print "%s (%s)" % (data, addr)
+ # Don't report data if we are a sender
+ if user_data:
+ return
+ print "%s (%s)" % (data, addr)
idstamp = 0
def transmit_data(pipe):
- global idstamp
- msg = "Message #%d" % idstamp
- print "Sending '%s'" % msg
- pipe.send(msg)
- idstamp = idstamp + 1
- return True
+ global idstamp
+ msg = "Message #%d" % idstamp
+ print "Sending '%s'" % msg
+ pipe.send(msg)
+ idstamp = idstamp + 1
+ return True
def network_test():
- import sys, os
- send = False
- if len(sys.argv) != 2:
- print "Need one arg, either 'send' or 'recv'"
- os._exit(1)
- if sys.argv[1] == "send":
- send = True
- elif sys.argv[1] == "recv":
- send = False
- else:
- print "Arg should be either 'send' or 'recv'"
- os._exit(1)
-
- pipe = MostlyReliablePipe('', '224.0.0.222', 2293, net_test_got_data, send)
- pipe.start()
- if send:
- gobject.timeout_add(1000, transmit_data, pipe)
- try:
- gtk.main()
- except KeyboardInterrupt:
- print 'Ctrl+C pressed, exiting...'
+ import sys, os
+ send = False
+ if len(sys.argv) != 2:
+ print "Need one arg, either 'send' or 'recv'"
+ os._exit(1)
+ if sys.argv[1] == "send":
+ send = True
+ elif sys.argv[1] == "recv":
+ send = False
+ else:
+ print "Arg should be either 'send' or 'recv'"
+ os._exit(1)
+
+ pipe = MostlyReliablePipe('', '224.0.0.222', 2293, net_test_got_data, send)
+ pipe.start()
+ if send:
+ gobject.timeout_add(1000, transmit_data, pipe)
+ try:
+ gtk.main()
+ except KeyboardInterrupt:
+ print 'Ctrl+C pressed, exiting...'
def main():
-# unit_test()
-# simple_test()
- network_test()
+# unit_test()
+# simple_test()
+ network_test()
if __name__ == "__main__":
- main()
+ main()
diff --git a/sugar/p2p/NotificationListener.py b/sugar/p2p/NotificationListener.py
index f68bbb2..42668ad 100644
--- a/sugar/p2p/NotificationListener.py
+++ b/sugar/p2p/NotificationListener.py
@@ -21,18 +21,18 @@ from sugar.p2p.Notifier import Notifier
from sugar.p2p import network
class NotificationListener:
- def __init__(self, service):
- logging.debug('Start notification listener. Service %s, address %s, port %s' % (service.get_type(), service.get_address(), service.get_port()))
- server = network.GroupServer(service.get_address(),
- service.get_port(),
- self._recv_multicast)
- server.start()
-
- self._listeners = []
-
- def add_listener(self, listener):
- self._listeners.append(listener)
-
- def _recv_multicast(self, msg):
- for listener in self._listeners:
- listener(msg)
+ def __init__(self, service):
+ logging.debug('Start notification listener. Service %s, address %s, port %s' % (service.get_type(), service.get_address(), service.get_port()))
+ server = network.GroupServer(service.get_address(),
+ service.get_port(),
+ self._recv_multicast)
+ server.start()
+
+ self._listeners = []
+
+ def add_listener(self, listener):
+ self._listeners.append(listener)
+
+ def _recv_multicast(self, msg):
+ for listener in self._listeners:
+ listener(msg)
diff --git a/sugar/p2p/Notifier.py b/sugar/p2p/Notifier.py
index f216fda..69d0af6 100644
--- a/sugar/p2p/Notifier.py
+++ b/sugar/p2p/Notifier.py
@@ -18,10 +18,10 @@
from sugar.p2p import network
class Notifier:
- def __init__(self, service):
- address = service.get_address()
- port = service.get_port()
- self._client = network.GroupClient(address, port)
-
- def notify(self, msg):
- self._client.send_msg(msg)
+ def __init__(self, service):
+ address = service.get_address()
+ port = service.get_port()
+ self._client = network.GroupClient(address, port)
+
+ def notify(self, msg):
+ self._client.send_msg(msg)
diff --git a/sugar/p2p/Stream.py b/sugar/p2p/Stream.py
index edb4d1b..b3239b3 100644
--- a/sugar/p2p/Stream.py
+++ b/sugar/p2p/Stream.py
@@ -26,135 +26,135 @@ 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
+ """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():
- raise ValueError("service must have an address.")
- self._service = service
- self._reader_port = self._service.get_port()
- self._writer_port = self._reader_port
- self._address = self._service.get_address()
- self._callback = None
-
- def new_from_service(service, start_reader=True):
- if is_multicast_address(service.get_address()):
- return MulticastStream(service)
- else:
- return UnicastStream(service, start_reader)
- new_from_service = staticmethod(new_from_service)
-
- def set_data_listener(self, callback):
- self._callback = callback
-
- def _recv(self, address, data):
- if self._callback:
- self._callback(address, data)
+ def __init__(self, service):
+ if not service.get_port():
+ raise ValueError("service must have an address.")
+ self._service = service
+ self._reader_port = self._service.get_port()
+ self._writer_port = self._reader_port
+ self._address = self._service.get_address()
+ self._callback = None
+
+ def new_from_service(service, start_reader=True):
+ if is_multicast_address(service.get_address()):
+ return MulticastStream(service)
+ else:
+ return UnicastStream(service, start_reader)
+ new_from_service = staticmethod(new_from_service)
+
+ def set_data_listener(self, callback):
+ self._callback = callback
+
+ def _recv(self, address, data):
+ if self._callback:
+ self._callback(address, data)
class UnicastStreamWriter(object):
- def __init__(self, stream, service):
- # set up the writer
- self._service = service
- if not service.get_address():
- raise ValueError("service must have a valid address.")
- self._address = self._service.get_address()
- self._port = self._service.get_port()
- self._xmlrpc_addr = "http://%s:%d" % (self._address, self._port)
- self._writer = network.GlibServerProxy(self._xmlrpc_addr)
-
- def write(self, xmlrpc_data):
- """Write some data to the default endpoint of this pipe on the remote server."""
- try:
- self._writer.message(None, None, xmlrpc_data)
- return True
- except (socket.error, xmlrpclib.Fault, xmlrpclib.ProtocolError):
- traceback.print_exc()
- return False
-
- def custom_request(self, method_name, request_cb, user_data, *args):
- """Call a custom XML-RPC method on the remote server."""
- try:
- method = getattr(self._writer, method_name)
- method(request_cb, user_data, *args)
- return True
- except (socket.error, xmlrpclib.Fault, xmlrpclib.ProtocolError):
- traceback.print_exc()
- return False
+ def __init__(self, stream, service):
+ # set up the writer
+ self._service = service
+ if not service.get_address():
+ raise ValueError("service must have a valid address.")
+ self._address = self._service.get_address()
+ self._port = self._service.get_port()
+ self._xmlrpc_addr = "http://%s:%d" % (self._address, self._port)
+ self._writer = network.GlibServerProxy(self._xmlrpc_addr)
+
+ def write(self, xmlrpc_data):
+ """Write some data to the default endpoint of this pipe on the remote server."""
+ try:
+ self._writer.message(None, None, xmlrpc_data)
+ return True
+ except (socket.error, xmlrpclib.Fault, xmlrpclib.ProtocolError):
+ traceback.print_exc()
+ return False
+
+ def custom_request(self, method_name, request_cb, user_data, *args):
+ """Call a custom XML-RPC method on the remote server."""
+ try:
+ method = getattr(self._writer, method_name)
+ method(request_cb, user_data, *args)
+ return True
+ except (socket.error, xmlrpclib.Fault, xmlrpclib.ProtocolError):
+ traceback.print_exc()
+ return False
class UnicastStream(Stream):
- def __init__(self, service, start_reader=True):
- """Initializes the stream. If the 'start_reader' argument is True,
- the stream will initialize and start a new stream reader, if it
- is False, no reader will be created and the caller must call the
- start_reader() method to start the stream reader and be able to
- receive any data from the stream."""
- Stream.__init__(self, service)
- if start_reader:
- self.start_reader()
-
- 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
- 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."""
- address = network.get_authinfo()
- self._recv(address, message)
- return True
-
- def register_reader_handler(self, handler, name):
- """Register a custom message handler with the reader. This call
- adds a custom XMLRPC method call with the name 'name' to the reader's
- XMLRPC server, which then calls the 'handler' argument back when
- a method call for it arrives over the network."""
- if name == "message":
- raise ValueError("Handler name 'message' is a reserved handler.")
- self._reader.register_function(handler, name)
-
- def new_writer(self, service):
- """Return a new stream writer object."""
- return UnicastStreamWriter(self, service)
+ def __init__(self, service, start_reader=True):
+ """Initializes the stream. If the 'start_reader' argument is True,
+ the stream will initialize and start a new stream reader, if it
+ is False, no reader will be created and the caller must call the
+ start_reader() method to start the stream reader and be able to
+ receive any data from the stream."""
+ Stream.__init__(self, service)
+ if start_reader:
+ self.start_reader()
+
+ 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
+ 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."""
+ address = network.get_authinfo()
+ self._recv(address, message)
+ return True
+
+ def register_reader_handler(self, handler, name):
+ """Register a custom message handler with the reader. This call
+ adds a custom XMLRPC method call with the name 'name' to the reader's
+ XMLRPC server, which then calls the 'handler' argument back when
+ a method call for it arrives over the network."""
+ if name == "message":
+ raise ValueError("Handler name 'message' is a reserved handler.")
+ self._reader.register_function(handler, name)
+
+ def new_writer(self, service):
+ """Return a new stream writer object."""
+ return UnicastStreamWriter(self, service)
class MulticastStream(Stream):
- def __init__(self, service):
- Stream.__init__(self, service)
- self._service = service
- self._internal_start_reader()
-
- def start_reader(self):
- return self._reader_port
-
- def _internal_start_reader(self):
- logging.debug('Start multicast stream, address %s, port %d' % (self._address, self._reader_port))
- if not self._service.get_address():
- raise ValueError("service must have a valid address.")
- self._pipe = MostlyReliablePipe('', self._address, self._reader_port,
- self._recv_data_cb)
- self._pipe.start()
-
- def write(self, data):
- self._pipe.send(data)
-
- def _recv_data_cb(self, address, data, user_data=None):
- self._recv(address[0], data)
-
- def new_writer(self, service=None):
- return self
+ def __init__(self, service):
+ Stream.__init__(self, service)
+ self._service = service
+ self._internal_start_reader()
+
+ def start_reader(self):
+ return self._reader_port
+
+ def _internal_start_reader(self):
+ logging.debug('Start multicast stream, address %s, port %d' % (self._address, self._reader_port))
+ if not self._service.get_address():
+ raise ValueError("service must have a valid address.")
+ self._pipe = MostlyReliablePipe('', self._address, self._reader_port,
+ self._recv_data_cb)
+ self._pipe.start()
+
+ def write(self, data):
+ self._pipe.send(data)
+
+ def _recv_data_cb(self, address, data, user_data=None):
+ self._recv(address[0], data)
+
+ def new_writer(self, service=None):
+ return self
diff --git a/sugar/p2p/network.py b/sugar/p2p/network.py
index 6718669..e5b4e4b 100644
--- a/sugar/p2p/network.py
+++ b/sugar/p2p/network.py
@@ -35,347 +35,347 @@ RESULT_SUCCESS = 1
__authinfos = {}
def _add_authinfo(authinfo):
- __authinfos[threading.currentThread()] = authinfo
+ __authinfos[threading.currentThread()] = authinfo
def get_authinfo():
- return __authinfos.get(threading.currentThread())
+ return __authinfos.get(threading.currentThread())
def _del_authinfo():
- del __authinfos[threading.currentThread()]
+ del __authinfos[threading.currentThread()]
class GlibTCPServer(SocketServer.TCPServer):
- """GlibTCPServer
+ """GlibTCPServer
- Integrate socket accept into glib mainloop.
- """
+ Integrate socket accept into glib mainloop.
+ """
- allow_reuse_address = True
- request_queue_size = 20
+ allow_reuse_address = True
+ request_queue_size = 20
- def __init__(self, server_address, RequestHandlerClass):
- SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass)
- self.socket.setblocking(0) # Set nonblocking
+ def __init__(self, server_address, RequestHandlerClass):
+ SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass)
+ self.socket.setblocking(0) # Set nonblocking
- # Watch the listener socket for data
- gobject.io_add_watch(self.socket, gobject.IO_IN, self._handle_accept)
+ # Watch the listener socket for data
+ gobject.io_add_watch(self.socket, gobject.IO_IN, self._handle_accept)
- def _handle_accept(self, source, condition):
- """Process incoming data on the server's socket by doing an accept()
- via handle_request()."""
- if not (condition & gobject.IO_IN):
- return True
- self.handle_request()
- return True
+ def _handle_accept(self, source, condition):
+ """Process incoming data on the server's socket by doing an accept()
+ via handle_request()."""
+ if not (condition & gobject.IO_IN):
+ return True
+ self.handle_request()
+ return True
class GlibXMLRPCRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
- """ GlibXMLRPCRequestHandler
-
- The stock SimpleXMLRPCRequestHandler and server don't allow any way to pass
- the client's address and/or SSL certificate into the function that actually
- _processes_ the request. So we have to store it in a thread-indexed dict.
- """
-
- def do_POST(self):
- _add_authinfo(self.client_address)
- try:
- SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.do_POST(self)
- except socket.timeout:
- pass
- except socket.error, e:
- print "Error (%s): socket error - '%s'" % (self.client_address, e)
- except:
- print "Error while processing POST:"
- traceback.print_exc()
- _del_authinfo()
+ """ GlibXMLRPCRequestHandler
+
+ The stock SimpleXMLRPCRequestHandler and server don't allow any way to pass
+ the client's address and/or SSL certificate into the function that actually
+ _processes_ the request. So we have to store it in a thread-indexed dict.
+ """
+
+ def do_POST(self):
+ _add_authinfo(self.client_address)
+ try:
+ SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.do_POST(self)
+ except socket.timeout:
+ pass
+ except socket.error, e:
+ print "Error (%s): socket error - '%s'" % (self.client_address, e)
+ except:
+ print "Error while processing POST:"
+ traceback.print_exc()
+ _del_authinfo()
class GlibXMLRPCServer(GlibTCPServer, SimpleXMLRPCServer.SimpleXMLRPCDispatcher):
- """GlibXMLRPCServer
-
- Use nonblocking sockets and handle the accept via glib rather than
- blocking on accept().
- """
-
- def __init__(self, addr, requestHandler=GlibXMLRPCRequestHandler, logRequests=0):
- self.logRequests = logRequests
- SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self)
- GlibTCPServer.__init__(self, addr, requestHandler)
-
- def _marshaled_dispatch(self, data, dispatch_method = None):
- """Dispatches an XML-RPC method from marshalled (XML) data.
-
- XML-RPC methods are dispatched from the marshalled (XML) data
- using the _dispatch method and the result is returned as
- marshalled data. For backwards compatibility, a dispatch
- function can be provided as an argument (see comment in
- SimpleXMLRPCRequestHandler.do_POST) but overriding the
- existing method through subclassing is the prefered means
- of changing method dispatch behavior.
- """
-
- params, method = xmlrpclib.loads(data)
-
- # generate response
- try:
- if dispatch_method is not None:
- response = dispatch_method(method, params)
- else:
- response = self._dispatch(method, params)
- # wrap response in a singleton tuple
- response = (response,)
- response = xmlrpclib.dumps(response, methodresponse=1)
- except xmlrpclib.Fault, fault:
- response = xmlrpclib.dumps(fault)
- except:
- print "Exception while processing request:"
- traceback.print_exc()
-
- # report exception back to server
- response = xmlrpclib.dumps(
- xmlrpclib.Fault(1, "%s:%s" % (sys.exc_type, sys.exc_value))
- )
-
- return response
+ """GlibXMLRPCServer
+
+ Use nonblocking sockets and handle the accept via glib rather than
+ blocking on accept().
+ """
+
+ def __init__(self, addr, requestHandler=GlibXMLRPCRequestHandler, logRequests=0):
+ self.logRequests = logRequests
+ SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self)
+ GlibTCPServer.__init__(self, addr, requestHandler)
+
+ def _marshaled_dispatch(self, data, dispatch_method = None):
+ """Dispatches an XML-RPC method from marshalled (XML) data.
+
+ XML-RPC methods are dispatched from the marshalled (XML) data
+ using the _dispatch method and the result is returned as
+ marshalled data. For backwards compatibility, a dispatch
+ function can be provided as an argument (see comment in
+ SimpleXMLRPCRequestHandler.do_POST) but overriding the
+ existing method through subclassing is the prefered means
+ of changing method dispatch behavior.
+ """
+
+ params, method = xmlrpclib.loads(data)
+
+ # generate response
+ try:
+ if dispatch_method is not None:
+ response = dispatch_method(method, params)
+ else:
+ response = self._dispatch(method, params)
+ # wrap response in a singleton tuple
+ response = (response,)
+ response = xmlrpclib.dumps(response, methodresponse=1)
+ except xmlrpclib.Fault, fault:
+ response = xmlrpclib.dumps(fault)
+ except:
+ print "Exception while processing request:"
+ traceback.print_exc()
+
+ # report exception back to server
+ response = xmlrpclib.dumps(
+ xmlrpclib.Fault(1, "%s:%s" % (sys.exc_type, sys.exc_value))
+ )
+
+ return response
class GlibHTTP(httplib.HTTP):
- """Subclass HTTP so we can return it's connection class' socket."""
- def connect(self, host=None, port=None):
- httplib.HTTP.connect(self, host, port)
- self._conn.sock.setblocking(0)
- def get_sock(self):
- return self._conn.sock
+ """Subclass HTTP so we can return it's connection class' socket."""
+ def connect(self, host=None, port=None):
+ httplib.HTTP.connect(self, host, port)
+ self._conn.sock.setblocking(0)
+ def get_sock(self):
+ return self._conn.sock
class GlibXMLRPCTransport(xmlrpclib.Transport):
- """Integrate the request with the glib mainloop rather than blocking."""
- ##
- # Connect to server.
- #
- # @param host Target host.
- # @return A connection handle.
-
- def __init__(self):
- pass
-
- def make_connection(self, host):
- """Use our own connection object so we can get its socket."""
- # create a HTTP connection object from a host descriptor
- host, extra_headers, x509 = self.get_host_info(host)
- return GlibHTTP(host)
-
- ##
- # Send a complete request, and parse the response.
- #
- # @param host Target host.
- # @param handler Target PRC handler.
- # @param request_body XML-RPC request body.
- # @param verbose Debugging flag.
- # @return Parsed response.
-
- def start_request(self, host, handler, request_body, verbose=0, request_cb=None, user_data=None):
- """Do the first half of the request by sending data to the remote
- server. The bottom half bits get run when the remote server's response
- actually comes back."""
- # issue XML-RPC request
-
- h = self.make_connection(host)
- if verbose:
- h.set_debuglevel(1)
-
- self.send_request(h, handler, request_body)
- self.send_host(h, host)
- self.send_user_agent(h)
- self.send_content(h, request_body)
-
- # Schedule a GIOWatch so we don't block waiting for the response
- gobject.io_add_watch(h.get_sock(), gobject.IO_IN, self._finish_request,
- h, host, handler, verbose, request_cb, user_data)
-
- def _finish_request(self, source, condition, h, host, handler, verbose, request_cb, user_data):
- """Parse and return response when the remote server actually returns it."""
- if not (condition & gobject.IO_IN):
- return True
-
- try:
- errcode, errmsg, headers = h.getreply()
- except socket.error, err:
- if err[0] != 104:
- raise socket.error(err)
- else:
- gobject.idle_add(request_cb, RESULT_FAILED, None, user_data)
- return False
-
- if errcode != 200:
- raise xmlrpclib.ProtocolError(host + handler, errcode, errmsg, headers)
- self.verbose = verbose
- response = self._parse_response(h.getfile(), h.get_sock())
- if request_cb:
- if len(response) == 1:
- response = response[0]
- gobject.idle_add(request_cb, RESULT_SUCCESS, response, user_data)
- return False
+ """Integrate the request with the glib mainloop rather than blocking."""
+ ##
+ # Connect to server.
+ #
+ # @param host Target host.
+ # @return A connection handle.
+
+ def __init__(self):
+ pass
+
+ def make_connection(self, host):
+ """Use our own connection object so we can get its socket."""
+ # create a HTTP connection object from a host descriptor
+ host, extra_headers, x509 = self.get_host_info(host)
+ return GlibHTTP(host)
+
+ ##
+ # Send a complete request, and parse the response.
+ #
+ # @param host Target host.
+ # @param handler Target PRC handler.
+ # @param request_body XML-RPC request body.
+ # @param verbose Debugging flag.
+ # @return Parsed response.
+
+ def start_request(self, host, handler, request_body, verbose=0, request_cb=None, user_data=None):
+ """Do the first half of the request by sending data to the remote
+ server. The bottom half bits get run when the remote server's response
+ actually comes back."""
+ # issue XML-RPC request
+
+ h = self.make_connection(host)
+ if verbose:
+ h.set_debuglevel(1)
+
+ self.send_request(h, handler, request_body)
+ self.send_host(h, host)
+ self.send_user_agent(h)
+ self.send_content(h, request_body)
+
+ # Schedule a GIOWatch so we don't block waiting for the response
+ gobject.io_add_watch(h.get_sock(), gobject.IO_IN, self._finish_request,
+ h, host, handler, verbose, request_cb, user_data)
+
+ def _finish_request(self, source, condition, h, host, handler, verbose, request_cb, user_data):
+ """Parse and return response when the remote server actually returns it."""
+ if not (condition & gobject.IO_IN):
+ return True
+
+ try:
+ errcode, errmsg, headers = h.getreply()
+ except socket.error, err:
+ if err[0] != 104:
+ raise socket.error(err)
+ else:
+ gobject.idle_add(request_cb, RESULT_FAILED, None, user_data)
+ return False
+
+ if errcode != 200:
+ raise xmlrpclib.ProtocolError(host + handler, errcode, errmsg, headers)
+ self.verbose = verbose
+ response = self._parse_response(h.getfile(), h.get_sock())
+ if request_cb:
+ if len(response) == 1:
+ response = response[0]
+ gobject.idle_add(request_cb, RESULT_SUCCESS, response, user_data)
+ return False
class _Method:
- """Right, so python people thought it would be funny to make this
- class private to xmlrpclib.py..."""
- # some magic to bind an XML-RPC method to an RPC server.
- # supports "nested" methods (e.g. examples.getStateName)
- def __init__(self, send, name):
- self.__send = send
- self.__name = name
- def __getattr__(self, name):
- return _Method(self.__send, "%s.%s" % (self.__name, name))
- def __call__(self, request_cb, user_data, *args):
- return self.__send(self.__name, request_cb, user_data, args)
+ """Right, so python people thought it would be funny to make this
+ class private to xmlrpclib.py..."""
+ # some magic to bind an XML-RPC method to an RPC server.
+ # supports "nested" methods (e.g. examples.getStateName)
+ def __init__(self, send, name):
+ self.__send = send
+ self.__name = name
+ def __getattr__(self, name):
+ return _Method(self.__send, "%s.%s" % (self.__name, name))
+ def __call__(self, request_cb, user_data, *args):
+ return self.__send(self.__name, request_cb, user_data, args)
class GlibServerProxy(xmlrpclib.ServerProxy):
- """Subclass xmlrpclib.ServerProxy so we can run the XML-RPC request
- in two parts, integrated with the glib mainloop, such that we don't
- block anywhere.
-
- Using this object is somewhat special; it requires more arguments to each
- XML-RPC request call than the normal xmlrpclib.ServerProxy object:
-
- client = GlibServerProxy("http://127.0.0.1:8888")
- user_data = "bar"
- xmlrpc_arg1 = "test"
- xmlrpc_arg2 = "foo"
- client.test(xmlrpc_test_cb, user_data, xmlrpc_arg1, xmlrpc_arg2)
-
- Here, 'xmlrpc_test_cb' is the callback function, which has the following
- signature:
-
- def xmlrpc_test_cb(result_status, response, user_data=None):
- ...
- """
- def __init__(self, uri, encoding=None, verbose=0, allow_none=0):
- self._transport = GlibXMLRPCTransport()
- self._encoding = encoding
- self._verbose = verbose
- self._allow_none = allow_none
- xmlrpclib.ServerProxy.__init__(self, uri, self._transport, encoding, verbose, allow_none)
-
- # get the url
- import urllib
- urltype, uri = urllib.splittype(uri)
- if urltype not in ("http", "https"):
- raise IOError, "unsupported XML-RPC protocol"
- self._host, self._handler = urllib.splithost(uri)
- if not self._handler:
- self._handler = "/RPC2"
-
- def __request(self, methodname, request_cb, user_data, params):
- """Call the method on the remote server. We just start the request here
- and the transport itself takes care of scheduling the response callback
- when the remote server returns the response. We don't want to block anywhere."""
-
- request = xmlrpclib.dumps(params, methodname, encoding=self._encoding,
- allow_none=self._allow_none)
-
- try:
- response = self._transport.start_request(
- self._host,
- self._handler,
- request,
- verbose=self._verbose,
- request_cb=request_cb,
- user_data=user_data
- )
- except socket.error, exc:
- gobject.idle_add(request_cb, RESULT_FAILED, None, user_data)
-
- def __getattr__(self, name):
- # magic method dispatcher
- return _Method(self.__request, name)
+ """Subclass xmlrpclib.ServerProxy so we can run the XML-RPC request
+ in two parts, integrated with the glib mainloop, such that we don't
+ block anywhere.
+
+ Using this object is somewhat special; it requires more arguments to each
+ XML-RPC request call than the normal xmlrpclib.ServerProxy object:
+
+ client = GlibServerProxy("http://127.0.0.1:8888")
+ user_data = "bar"
+ xmlrpc_arg1 = "test"
+ xmlrpc_arg2 = "foo"
+ client.test(xmlrpc_test_cb, user_data, xmlrpc_arg1, xmlrpc_arg2)
+
+ Here, 'xmlrpc_test_cb' is the callback function, which has the following
+ signature:
+
+ def xmlrpc_test_cb(result_status, response, user_data=None):
+ ...
+ """
+ def __init__(self, uri, encoding=None, verbose=0, allow_none=0):
+ self._transport = GlibXMLRPCTransport()
+ self._encoding = encoding
+ self._verbose = verbose
+ self._allow_none = allow_none
+ xmlrpclib.ServerProxy.__init__(self, uri, self._transport, encoding, verbose, allow_none)
+
+ # get the url
+ import urllib
+ urltype, uri = urllib.splittype(uri)
+ if urltype not in ("http", "https"):
+ raise IOError, "unsupported XML-RPC protocol"
+ self._host, self._handler = urllib.splithost(uri)
+ if not self._handler:
+ self._handler = "/RPC2"
+
+ def __request(self, methodname, request_cb, user_data, params):
+ """Call the method on the remote server. We just start the request here
+ and the transport itself takes care of scheduling the response callback
+ when the remote server returns the response. We don't want to block anywhere."""
+
+ request = xmlrpclib.dumps(params, methodname, encoding=self._encoding,
+ allow_none=self._allow_none)
+
+ try:
+ response = self._transport.start_request(
+ self._host,
+ self._handler,
+ request,
+ verbose=self._verbose,
+ request_cb=request_cb,
+ user_data=user_data
+ )
+ except socket.error, exc:
+ gobject.idle_add(request_cb, RESULT_FAILED, None, user_data)
+
+ def __getattr__(self, name):
+ # magic method dispatcher
+ return _Method(self.__request, name)
class GroupServer(object):
- _MAX_MSG_SIZE = 500
+ _MAX_MSG_SIZE = 500
- def __init__(self, address, port, data_cb):
- self._address = address
- self._port = port
- self._data_cb = data_cb
+ def __init__(self, address, port, data_cb):
+ self._address = address
+ self._port = port
+ self._data_cb = data_cb
- self._setup_listener()
+ self._setup_listener()
- def _setup_listener(self):
- # Listener socket
- self._listen_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ def _setup_listener(self):
+ # Listener socket
+ self._listen_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- # Set some options to make it multicast-friendly
- self._listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_TTL, 20)
- self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
+ # Set some options to make it multicast-friendly
+ self._listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_TTL, 20)
+ self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
- def start(self):
- # Set some more multicast options
- self._listen_sock.bind(('', self._port))
- self._listen_sock.settimeout(2)
- intf = socket.gethostbyname(socket.gethostname())
- self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, socket.inet_aton(intf) + socket.inet_aton('0.0.0.0'))
- self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(self._address) + socket.inet_aton('0.0.0.0'))
+ def start(self):
+ # Set some more multicast options
+ self._listen_sock.bind(('', self._port))
+ self._listen_sock.settimeout(2)
+ intf = socket.gethostbyname(socket.gethostname())
+ self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_IF, socket.inet_aton(intf) + socket.inet_aton('0.0.0.0'))
+ self._listen_sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP, socket.inet_aton(self._address) + socket.inet_aton('0.0.0.0'))
- # Watch the listener socket for data
- gobject.io_add_watch(self._listen_sock, gobject.IO_IN, self._handle_incoming_data)
+ # Watch the listener socket for data
+ gobject.io_add_watch(self._listen_sock, gobject.IO_IN, self._handle_incoming_data)
- def _handle_incoming_data(self, source, condition):
- if not (condition & gobject.IO_IN):
- return True
- msg = {}
- msg['data'], (msg['addr'], msg['port']) = source.recvfrom(self._MAX_MSG_SIZE)
- if self._data_cb:
- self._data_cb(msg)
- return True
+ def _handle_incoming_data(self, source, condition):
+ if not (condition & gobject.IO_IN):
+ return True
+ msg = {}
+ msg['data'], (msg['addr'], msg['port']) = source.recvfrom(self._MAX_MSG_SIZE)
+ if self._data_cb:
+ self._data_cb(msg)
+ return True
class GroupClient(object):
- _MAX_MSG_SIZE = 500
+ _MAX_MSG_SIZE = 500
- def __init__(self, address, port):
- self._address = address
- self._port = port
+ def __init__(self, address, port):
+ self._address = address
+ self._port = port
- self._send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- # Make the socket multicast-aware, and set TTL.
- self._send_sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 20) # Change TTL (=20) to suit
+ self._send_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ # Make the socket multicast-aware, and set TTL.
+ self._send_sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 20) # Change TTL (=20) to suit
- def send_msg(self, data):
- self._send_sock.sendto(data, (self._address, self._port))
+ def send_msg(self, data):
+ self._send_sock.sendto(data, (self._address, self._port))
class Test(object):
- def test(self, arg1):
- print "Request got %s" % arg1
- return "success"
+ def test(self, arg1):
+ print "Request got %s" % arg1
+ return "success"
def xmlrpc_test_cb(response, user_data=None):
- print "Response was %s, user_data was %s" % (response, user_data)
- import gtk
- gtk.main_quit()
+ print "Response was %s, user_data was %s" % (response, user_data)
+ import gtk
+ gtk.main_quit()
def xmlrpc_test():
- client = GlibServerProxy("http://127.0.0.1:8888")
- client.test(xmlrpc_test_cb, "bar", "test data")
+ client = GlibServerProxy("http://127.0.0.1:8888")
+ client.test(xmlrpc_test_cb, "bar", "test data")
def main():
- import gtk
- server = GlibXMLRPCServer(("", 8888))
- inst = Test()
- server.register_instance(inst)
-
- gobject.idle_add(xmlrpc_test)
-
- try:
- gtk.main()
- except KeyboardInterrupt:
- print 'Ctrl+C pressed, exiting...'
- print "Done."
+ import gtk
+ server = GlibXMLRPCServer(("", 8888))
+ inst = Test()
+ server.register_instance(inst)
+
+ gobject.idle_add(xmlrpc_test)
+
+ try:
+ gtk.main()
+ except KeyboardInterrupt:
+ print 'Ctrl+C pressed, exiting...'
+ print "Done."
if __name__ == "__main__":
- main()
+ main()
diff --git a/sugar/presence/Activity.py b/sugar/presence/Activity.py
index e267d83..06c8a00 100644
--- a/sugar/presence/Activity.py
+++ b/sugar/presence/Activity.py
@@ -20,98 +20,98 @@ import dbus
class Activity(gobject.GObject):
- __gsignals__ = {
- 'buddy-joined': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'buddy-left': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT]))
- }
-
- _PRESENCE_SERVICE = "org.laptop.Presence"
- _ACTIVITY_DBUS_INTERFACE = "org.laptop.Presence.Activity"
-
- def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
- gobject.GObject.__init__(self)
- 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('BuddyJoined', self._buddy_joined_cb)
- self._activity.connect_to_signal('BuddyLeft', self._buddy_left_cb)
- self._activity.connect_to_signal('ServiceAppeared', self._service_appeared_cb)
- self._activity.connect_to_signal('ServiceDisappeared', self._service_disappeared_cb)
-
- self._id = None
- self._color = None
-
- def object_path(self):
- return self._object_path
-
- def _emit_buddy_joined_signal(self, 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('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('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('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 get_id(self):
- # Cache activity ID, which should never change anyway
- if not self._id:
- self._id = self._activity.getId()
- return self._id
-
- def get_color(self):
- if not self._color:
- self._color = self._activity.getColor()
- return self._color
-
- def get_services(self):
- resp = self._activity.getServices()
- servs = []
- for item in resp:
- servs.append(self._ps_new_object(item))
- return servs
-
- 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 get_joined_buddies(self):
- resp = self._activity.getJoinedBuddies()
- buddies = []
- for item in resp:
- buddies.append(self._ps_new_object(item))
- return buddies
-
- def owner_has_joined(self):
- # FIXME
- return False
+ __gsignals__ = {
+ 'buddy-joined': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'buddy-left': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT]))
+ }
+
+ _PRESENCE_SERVICE = "org.laptop.Presence"
+ _ACTIVITY_DBUS_INTERFACE = "org.laptop.Presence.Activity"
+
+ def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
+ gobject.GObject.__init__(self)
+ 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('BuddyJoined', self._buddy_joined_cb)
+ self._activity.connect_to_signal('BuddyLeft', self._buddy_left_cb)
+ self._activity.connect_to_signal('ServiceAppeared', self._service_appeared_cb)
+ self._activity.connect_to_signal('ServiceDisappeared', self._service_disappeared_cb)
+
+ self._id = None
+ self._color = None
+
+ def object_path(self):
+ return self._object_path
+
+ def _emit_buddy_joined_signal(self, 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('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('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('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 get_id(self):
+ # Cache activity ID, which should never change anyway
+ if not self._id:
+ self._id = self._activity.getId()
+ return self._id
+
+ def get_color(self):
+ if not self._color:
+ self._color = self._activity.getColor()
+ return self._color
+
+ def get_services(self):
+ resp = self._activity.getServices()
+ servs = []
+ for item in resp:
+ servs.append(self._ps_new_object(item))
+ return servs
+
+ 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 get_joined_buddies(self):
+ resp = self._activity.getJoinedBuddies()
+ buddies = []
+ for item in resp:
+ buddies.append(self._ps_new_object(item))
+ return buddies
+
+ def owner_has_joined(self):
+ # FIXME
+ return False
diff --git a/sugar/presence/Buddy.py b/sugar/presence/Buddy.py
index 579592b..740b29b 100644
--- a/sugar/presence/Buddy.py
+++ b/sugar/presence/Buddy.py
@@ -21,173 +21,173 @@ import dbus
class Buddy(gobject.GObject):
- __gsignals__ = {
- 'icon-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([])),
- 'disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([])),
- 'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'joined-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'left-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'property-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'current-activity-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT]))
- }
-
- _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._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)
- 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('Disappeared', self._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._buddy.connect_to_signal('CurrentActivityChanged', self._current_activity_changed_cb)
- self._properties = self._get_properties_helper()
-
- self._current_activity = None
- try:
- self._current_activity = self._buddy.getCurrentActivity()
- except Exception, e:
- pass
-
- def _get_properties_helper(self):
- props = self._buddy.getProperties()
- if not props:
- return {}
- return props
-
- def object_path(self):
- return self._object_path
-
- def _emit_icon_changed_signal(self):
- self.emit('icon-changed')
- return False
-
- def _icon_changed_cb(self):
- gobject.idle_add(self._emit_icon_changed_signal)
-
- def _emit_disappeared_signal(self):
- self.emit('disappeared')
-
- def _disappeared_cb(self):
- gobject.idle_add(self._emit_disappeared_signal)
-
- def _emit_service_appeared_signal(self, 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('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('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('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 _handle_property_changed_signal(self, prop_list):
- self._properties = self._get_properties_helper()
- self.emit('property-changed', prop_list)
- return False
-
- def _property_changed_cb(self, prop_list):
- gobject.idle_add(self._handle_property_changed_signal, prop_list)
-
- def _handle_current_activity_changed_signal(self, act_list):
- if len(act_list) == 0:
- self._current_activity = None
- self.emit('current-activity-changed', None)
- else:
- self._current_activity = act_list[0]
- self.emit('current-activity-changed', self._ps_new_object(act_list[0]))
- return False
-
- def _current_activity_changed_cb(self, act_list):
- gobject.idle_add(self._handle_current_activity_changed_signal, act_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_color(self):
- return self._properties['color']
-
- def get_icon(self):
- return self._buddy.getIcon()
-
- def get_current_activity(self):
- if not self._current_activity:
- return None
- return self._ps_new_object(self._current_activity)
-
- def get_icon_pixbuf(self):
- icon = self._buddy.getIcon()
- if icon and len(icon):
- pbl = gtk.gdk.PixbufLoader()
- icon_data = ""
- for item in icon:
- if item < 0:
- item = item + 128
- icon_data = icon_data + chr(item)
- pbl.write(icon_data)
- pbl.close()
- return pbl.get_pixbuf()
- else:
- return None
-
- def get_service_of_type(self, stype, activity=None):
- try:
- act_op = "/"
- if activity:
- act_op = activity.object_path()
- object_path = self._buddy.getServiceOfType(stype, act_op)
- except dbus.exceptions.DBusException:
- return None
- return self._ps_new_object(object_path)
-
- def get_joined_activities(self):
- try:
- resp = self._buddy.getJoinedActivities()
- except dbus.exceptions.DBusException:
- return []
- acts = []
- for item in resp:
- acts.append(self._ps_new_object(item))
- return acts
+ __gsignals__ = {
+ 'icon-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([])),
+ 'disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([])),
+ 'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'joined-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'left-activity': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'property-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'current-activity-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT]))
+ }
+
+ _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._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)
+ 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('Disappeared', self._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._buddy.connect_to_signal('CurrentActivityChanged', self._current_activity_changed_cb)
+ self._properties = self._get_properties_helper()
+
+ self._current_activity = None
+ try:
+ self._current_activity = self._buddy.getCurrentActivity()
+ except Exception, e:
+ pass
+
+ def _get_properties_helper(self):
+ props = self._buddy.getProperties()
+ if not props:
+ return {}
+ return props
+
+ def object_path(self):
+ return self._object_path
+
+ def _emit_icon_changed_signal(self):
+ self.emit('icon-changed')
+ return False
+
+ def _icon_changed_cb(self):
+ gobject.idle_add(self._emit_icon_changed_signal)
+
+ def _emit_disappeared_signal(self):
+ self.emit('disappeared')
+
+ def _disappeared_cb(self):
+ gobject.idle_add(self._emit_disappeared_signal)
+
+ def _emit_service_appeared_signal(self, 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('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('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('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 _handle_property_changed_signal(self, prop_list):
+ self._properties = self._get_properties_helper()
+ self.emit('property-changed', prop_list)
+ return False
+
+ def _property_changed_cb(self, prop_list):
+ gobject.idle_add(self._handle_property_changed_signal, prop_list)
+
+ def _handle_current_activity_changed_signal(self, act_list):
+ if len(act_list) == 0:
+ self._current_activity = None
+ self.emit('current-activity-changed', None)
+ else:
+ self._current_activity = act_list[0]
+ self.emit('current-activity-changed', self._ps_new_object(act_list[0]))
+ return False
+
+ def _current_activity_changed_cb(self, act_list):
+ gobject.idle_add(self._handle_current_activity_changed_signal, act_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_color(self):
+ return self._properties['color']
+
+ def get_icon(self):
+ return self._buddy.getIcon()
+
+ def get_current_activity(self):
+ if not self._current_activity:
+ return None
+ return self._ps_new_object(self._current_activity)
+
+ def get_icon_pixbuf(self):
+ icon = self._buddy.getIcon()
+ if icon and len(icon):
+ pbl = gtk.gdk.PixbufLoader()
+ icon_data = ""
+ for item in icon:
+ if item < 0:
+ item = item + 128
+ icon_data = icon_data + chr(item)
+ pbl.write(icon_data)
+ pbl.close()
+ return pbl.get_pixbuf()
+ else:
+ return None
+
+ def get_service_of_type(self, stype, activity=None):
+ try:
+ act_op = "/"
+ if activity:
+ act_op = activity.object_path()
+ object_path = self._buddy.getServiceOfType(stype, act_op)
+ except dbus.exceptions.DBusException:
+ return None
+ return self._ps_new_object(object_path)
+
+ def get_joined_activities(self):
+ try:
+ resp = self._buddy.getJoinedActivities()
+ except dbus.exceptions.DBusException:
+ return []
+ acts = []
+ for item in resp:
+ acts.append(self._ps_new_object(item))
+ return acts
diff --git a/sugar/presence/PresenceService.py b/sugar/presence/PresenceService.py
index d74b0c5..fd6091e 100644
--- a/sugar/presence/PresenceService.py
+++ b/sugar/presence/PresenceService.py
@@ -20,23 +20,23 @@ import dbus, dbus.glib, gobject
import Buddy, Service, Activity
class ObjectCache(object):
- def __init__(self):
- self._cache = {}
+ def __init__(self):
+ self._cache = {}
- def get(self, object_path):
- try:
- return self._cache[object_path]
- except KeyError:
- return None
+ def get(self, object_path):
+ try:
+ return self._cache[object_path]
+ except KeyError:
+ return None
- def add(self, obj):
- op = obj.object_path()
- if not self._cache.has_key(op):
- self._cache[op] = obj
+ def add(self, obj):
+ op = obj.object_path()
+ if not self._cache.has_key(op):
+ self._cache[op] = obj
- def remove(self, object_path):
- if self._cache.has_key(object_path):
- del self._cache[object_path]
+ def remove(self, object_path):
+ if self._cache.has_key(object_path):
+ del self._cache[object_path]
DBUS_SERVICE = "org.laptop.Presence"
@@ -46,192 +46,192 @@ DBUS_PATH = "/org/laptop/Presence"
class PresenceService(gobject.GObject):
- __gsignals__ = {
- 'buddy-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'buddy-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'activity-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT])),
- 'activity-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT]))
- }
-
- _PS_BUDDY_OP = DBUS_PATH + "/Buddies/"
- _PS_SERVICE_OP = DBUS_PATH + "/Services/"
- _PS_ACTIVITY_OP = DBUS_PATH + "/Activities/"
-
-
- def __init__(self):
- gobject.GObject.__init__(self)
- self._objcache = ObjectCache()
- self._bus = dbus.SessionBus()
- self._ps = dbus.Interface(self._bus.get_object(DBUS_SERVICE,
- DBUS_PATH), 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)
- if not obj:
- if object_path.startswith(self._PS_SERVICE_OP):
- obj = Service.Service(self._bus, self._new_object,
- self._del_object, object_path)
- elif object_path.startswith(self._PS_BUDDY_OP):
- obj = Buddy.Buddy(self._bus, self._new_object,
- self._del_object, object_path)
- elif object_path.startswith(self._PS_ACTIVITY_OP):
- obj = Activity.Activity(self._bus, self._new_object,
- self._del_object, object_path)
- else:
- raise RuntimeError("Unknown object type")
- self._objcache.add(obj)
- return obj
-
- def _del_object(self, object_path):
- # FIXME
- pass
-
- def _emit_buddy_appeared_signal(self, 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('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('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('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('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('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 get(self, object_path):
- return self._new_object(object_path)
-
- def get_services(self):
- resp = self._ps.getServices()
- servs = []
- for item in resp:
- servs.append(self._new_object(item))
- return servs
-
- 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 get_activities(self):
- resp = self._ps.getActivities()
- acts = []
- for item in resp:
- acts.append(self._new_object(item))
- return acts
-
- def get_activity(self, activity_id):
- try:
- act_op = self._ps.getActivity(activity_id)
- except dbus.exceptions.DBusException:
- return None
- return self._new_object(act_op)
-
- def get_buddies(self):
- resp = self._ps.getBuddies()
- buddies = []
- for item in resp:
- buddies.append(self._new_object(item))
- return buddies
-
- def get_buddy_by_name(self, name):
- try:
- buddy_op = self._ps.getBuddyByName(name)
- except dbus.exceptions.DBusException:
- return None
- return self._new_object(buddy_op)
-
- def get_buddy_by_address(self, addr):
- try:
- buddy_op = self._ps.getBuddyByAddress(addr)
- except dbus.exceptions.DBusException:
- return None
- return self._new_object(buddy_op)
-
- def get_owner(self):
- try:
- owner_op = self._ps.getOwner()
- except dbus.exceptions.DBusException:
- return None
- return self._new_object(owner_op)
-
- def share_activity(self, activity, stype, properties={}, address=None, port=-1, domain=u"local"):
- actid = activity.get_id()
- if address == None:
- address = u""
- serv_op = self._ps.shareActivity(actid, stype, properties, address, port, domain)
- return self._new_object(serv_op)
-
- def register_service(self, name, stype, properties={}, address=None, port=-1, domain=u"local"):
- if address == None:
- address = u""
- serv_op = self._ps.registerService(name, stype, properties, address, port, domain)
- return self._new_object(serv_op)
-
- def unregister_service(self, service):
- self._ps.unregisterService(service.object_path())
-
- def register_service_type(self, stype):
- self._ps.registerServiceType(stype)
-
- def unregister_service_type(self, stype):
- self._ps.unregisterServiceType(stype)
+ __gsignals__ = {
+ 'buddy-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'buddy-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'service-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'service-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'activity-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT])),
+ 'activity-disappeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT]))
+ }
+
+ _PS_BUDDY_OP = DBUS_PATH + "/Buddies/"
+ _PS_SERVICE_OP = DBUS_PATH + "/Services/"
+ _PS_ACTIVITY_OP = DBUS_PATH + "/Activities/"
+
+
+ def __init__(self):
+ gobject.GObject.__init__(self)
+ self._objcache = ObjectCache()
+ self._bus = dbus.SessionBus()
+ self._ps = dbus.Interface(self._bus.get_object(DBUS_SERVICE,
+ DBUS_PATH), 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)
+ if not obj:
+ if object_path.startswith(self._PS_SERVICE_OP):
+ obj = Service.Service(self._bus, self._new_object,
+ self._del_object, object_path)
+ elif object_path.startswith(self._PS_BUDDY_OP):
+ obj = Buddy.Buddy(self._bus, self._new_object,
+ self._del_object, object_path)
+ elif object_path.startswith(self._PS_ACTIVITY_OP):
+ obj = Activity.Activity(self._bus, self._new_object,
+ self._del_object, object_path)
+ else:
+ raise RuntimeError("Unknown object type")
+ self._objcache.add(obj)
+ return obj
+
+ def _del_object(self, object_path):
+ # FIXME
+ pass
+
+ def _emit_buddy_appeared_signal(self, 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('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('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('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('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('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 get(self, object_path):
+ return self._new_object(object_path)
+
+ def get_services(self):
+ resp = self._ps.getServices()
+ servs = []
+ for item in resp:
+ servs.append(self._new_object(item))
+ return servs
+
+ 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 get_activities(self):
+ resp = self._ps.getActivities()
+ acts = []
+ for item in resp:
+ acts.append(self._new_object(item))
+ return acts
+
+ def get_activity(self, activity_id):
+ try:
+ act_op = self._ps.getActivity(activity_id)
+ except dbus.exceptions.DBusException:
+ return None
+ return self._new_object(act_op)
+
+ def get_buddies(self):
+ resp = self._ps.getBuddies()
+ buddies = []
+ for item in resp:
+ buddies.append(self._new_object(item))
+ return buddies
+
+ def get_buddy_by_name(self, name):
+ try:
+ buddy_op = self._ps.getBuddyByName(name)
+ except dbus.exceptions.DBusException:
+ return None
+ return self._new_object(buddy_op)
+
+ def get_buddy_by_address(self, addr):
+ try:
+ buddy_op = self._ps.getBuddyByAddress(addr)
+ except dbus.exceptions.DBusException:
+ return None
+ return self._new_object(buddy_op)
+
+ def get_owner(self):
+ try:
+ owner_op = self._ps.getOwner()
+ except dbus.exceptions.DBusException:
+ return None
+ return self._new_object(owner_op)
+
+ def share_activity(self, activity, stype, properties={}, address=None, port=-1, domain=u"local"):
+ actid = activity.get_id()
+ if address == None:
+ address = u""
+ serv_op = self._ps.shareActivity(actid, stype, properties, address, port, domain)
+ return self._new_object(serv_op)
+
+ def register_service(self, name, stype, properties={}, address=None, port=-1, domain=u"local"):
+ if address == None:
+ address = u""
+ serv_op = self._ps.registerService(name, stype, properties, address, port, domain)
+ return self._new_object(serv_op)
+
+ def unregister_service(self, service):
+ self._ps.unregisterService(service.object_path())
+
+ def register_service_type(self, stype):
+ self._ps.registerServiceType(stype)
+
+ def unregister_service_type(self, stype):
+ self._ps.unregisterServiceType(stype)
_ps = None
def get_instance():
- global _ps
- if not _ps:
- _ps = PresenceService()
- return _ps
+ global _ps
+ if not _ps:
+ _ps = PresenceService()
+ return _ps
def start():
- bus = dbus.SessionBus()
- ps = dbus.Interface(bus.get_object(DBUS_SERVICE, DBUS_PATH), DBUS_INTERFACE)
- ps.start()
+ bus = dbus.SessionBus()
+ ps = dbus.Interface(bus.get_object(DBUS_SERVICE, DBUS_PATH), DBUS_INTERFACE)
+ ps.start()
diff --git a/sugar/presence/Service.py b/sugar/presence/Service.py
index a1ef98a..22b436f 100644
--- a/sugar/presence/Service.py
+++ b/sugar/presence/Service.py
@@ -20,101 +20,101 @@ import dbus
def _one_dict_differs(dict1, dict2):
- diff_keys = []
- for key, value in dict1.items():
- if not dict2.has_key(key) or dict2[key] != value:
- diff_keys.append(key)
- return diff_keys
+ diff_keys = []
+ for key, value in dict1.items():
+ if not dict2.has_key(key) or dict2[key] != value:
+ diff_keys.append(key)
+ return diff_keys
def _dicts_differ(dict1, dict2):
- diff_keys = []
- diff1 = _one_dict_differs(dict1, dict2)
- diff2 = _one_dict_differs(dict2, dict1)
- for key in diff2:
- if key not in diff1:
- diff_keys.append(key)
- diff_keys += diff1
- return diff_keys
+ diff_keys = []
+ diff1 = _one_dict_differs(dict1, dict2)
+ diff2 = _one_dict_differs(dict2, dict1)
+ for key in diff2:
+ if key not in diff1:
+ diff_keys.append(key)
+ diff_keys += diff1
+ return diff_keys
class Service(gobject.GObject):
- _PRESENCE_SERVICE = "org.laptop.Presence"
- _SERVICE_DBUS_INTERFACE = "org.laptop.Presence.Service"
-
- __gsignals__ = {
- 'published-value-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
- ([gobject.TYPE_PYOBJECT]))
- }
-
- def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
- gobject.GObject.__init__(self)
- self._object_path = object_path
- self._ps_new_object = new_obj_cb
- 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._service.connect_to_signal('PublishedValueChanged',
- self.__published_value_changed_cb)
- self._props = self._service.getProperties()
- self._pubvals = self._service.getPublishedValues()
-
- def object_path(self):
- return self._object_path
-
- def __property_changed_cb(self, prop_list):
- self._props = self._service.getProperties()
-
- def get_published_value(self, key):
- return self._pubvals[key]
-
- def get_published_values(self):
- self._pubvals = self._service.getPublishedValues()
- return self._pubvals
-
- def set_published_value(self, key, value):
- if self._pubvals.has_key(key):
- if self._pubvals[key] == value:
- return
- self._pubvals[key] = value
- self._service.setPublishedValue(key, value)
-
- def set_published_values(self, vals):
- self._service.setPublishedValues(vals)
- self._pubvals = vals
-
- def __published_value_changed_cb(self, keys):
- oldvals = self._pubvals
- self.get_published_values()
- diff_keys = _dicts_differ(oldvals, self._pubvals)
- if len(diff_keys) > 0:
- self.emit('published-value-changed', diff_keys)
-
- 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
+ _PRESENCE_SERVICE = "org.laptop.Presence"
+ _SERVICE_DBUS_INTERFACE = "org.laptop.Presence.Service"
+
+ __gsignals__ = {
+ 'published-value-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
+ ([gobject.TYPE_PYOBJECT]))
+ }
+
+ def __init__(self, bus, new_obj_cb, del_obj_cb, object_path):
+ gobject.GObject.__init__(self)
+ self._object_path = object_path
+ self._ps_new_object = new_obj_cb
+ 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._service.connect_to_signal('PublishedValueChanged',
+ self.__published_value_changed_cb)
+ self._props = self._service.getProperties()
+ self._pubvals = self._service.getPublishedValues()
+
+ def object_path(self):
+ return self._object_path
+
+ def __property_changed_cb(self, prop_list):
+ self._props = self._service.getProperties()
+
+ def get_published_value(self, key):
+ return self._pubvals[key]
+
+ def get_published_values(self):
+ self._pubvals = self._service.getPublishedValues()
+ return self._pubvals
+
+ def set_published_value(self, key, value):
+ if self._pubvals.has_key(key):
+ if self._pubvals[key] == value:
+ return
+ self._pubvals[key] = value
+ self._service.setPublishedValue(key, value)
+
+ def set_published_values(self, vals):
+ self._service.setPublishedValues(vals)
+ self._pubvals = vals
+
+ def __published_value_changed_cb(self, keys):
+ oldvals = self._pubvals
+ self.get_published_values()
+ diff_keys = _dicts_differ(oldvals, self._pubvals)
+ if len(diff_keys) > 0:
+ self.emit('published-value-changed', diff_keys)
+
+ 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
diff --git a/sugar/profile.py b/sugar/profile.py
index 5b1c782..f731fba 100644
--- a/sugar/profile.py
+++ b/sugar/profile.py
@@ -21,34 +21,34 @@ from sugar import env
from sugar.graphics.iconcolor import IconColor
class _Profile(object):
- def __init__(self):
- self.name = None
- self.color = None
- self._load()
+ def __init__(self):
+ self.name = None
+ self.color = None
+ self._load()
- def update(self):
- self._load()
+ def update(self):
+ self._load()
- def _load(self):
- cp = ConfigParser()
- config_path = os.path.join(env.get_profile_path(), 'config')
- parsed = cp.read([config_path])
+ def _load(self):
+ cp = ConfigParser()
+ config_path = os.path.join(env.get_profile_path(), 'config')
+ parsed = cp.read([config_path])
- if cp.has_option('Buddy', 'NickName'):
- self.name = cp.get('Buddy', 'NickName')
+ if cp.has_option('Buddy', 'NickName'):
+ self.name = cp.get('Buddy', 'NickName')
- if cp.has_option('Buddy', 'Color'):
- self.color = IconColor(cp.get('Buddy', 'Color'))
+ if cp.has_option('Buddy', 'Color'):
+ self.color = IconColor(cp.get('Buddy', 'Color'))
- del cp
+ del cp
def get_nick_name():
- return _profile.name
+ return _profile.name
def get_color():
- return _profile.color
+ return _profile.color
def update():
- _profile.update()
+ _profile.update()
_profile = _Profile()
diff --git a/sugar/simulator.py b/sugar/simulator.py
index 7a2d24f..c97f364 100644
--- a/sugar/simulator.py
+++ b/sugar/simulator.py
@@ -33,151 +33,151 @@ _PRESENCE_SERVICE_TYPE = "_presence_olpc._tcp"
_activity_refs = {}
class _NameCollection(object):
- def __init__(self):
- self._names = copy.copy(_nick_names)
+ def __init__(self):
+ self._names = copy.copy(_nick_names)
- def get_name(self):
- i = random.randint(0, len(self._names))
- return self._names.pop(i)
+ def get_name(self):
+ i = random.randint(0, len(self._names))
+ return self._names.pop(i)
class _BotService(object):
- def __init__(self, bot):
- self._bot = bot
-
- def announce(self):
- props = { 'color': self._bot.color.to_string() }
- pservice = PresenceService.get_instance()
- self._service = pservice.register_service(self._bot.name,
- _PRESENCE_SERVICE_TYPE, properties=props)
-
- self._stream = Stream.Stream.new_from_service(self._service)
- self._stream.register_reader_handler(
- self._handle_buddy_icon_request, "get_buddy_icon")
- self._stream.register_reader_handler(
- self._handle_invite, "invite")
-
- def _handle_buddy_icon_request(self):
- if self._bot.icon:
- fd = open(self._bot.icon, "r")
- icon_data = fd.read()
- fd.close()
- if icon_data:
- return base64.b64encode(self._icon)
- return ''
-
- def _handle_invite(self, issuer, bundle_id, activity_id):
- return ''
-
- def set_current_activity(self, activity_id):
- self._service.set_published_value('curact', dbus.String(activity_id))
+ def __init__(self, bot):
+ self._bot = bot
+
+ def announce(self):
+ props = { 'color': self._bot.color.to_string() }
+ pservice = PresenceService.get_instance()
+ self._service = pservice.register_service(self._bot.name,
+ _PRESENCE_SERVICE_TYPE, properties=props)
+
+ self._stream = Stream.Stream.new_from_service(self._service)
+ self._stream.register_reader_handler(
+ self._handle_buddy_icon_request, "get_buddy_icon")
+ self._stream.register_reader_handler(
+ self._handle_invite, "invite")
+
+ def _handle_buddy_icon_request(self):
+ if self._bot.icon:
+ fd = open(self._bot.icon, "r")
+ icon_data = fd.read()
+ fd.close()
+ if icon_data:
+ return base64.b64encode(self._icon)
+ return ''
+
+ def _handle_invite(self, issuer, bundle_id, activity_id):
+ return ''
+
+ def set_current_activity(self, activity_id):
+ self._service.set_published_value('curact', dbus.String(activity_id))
class _JoinActivityAction(object):
- def __init__(self, bot, named_ref):
- self._bot = bot
- self._named_ref = named_ref
+ def __init__(self, bot, named_ref):
+ self._bot = bot
+ self._named_ref = named_ref
- def execute(self):
- activity_id = _activity_refs[self._named_ref]
+ def execute(self):
+ activity_id = _activity_refs[self._named_ref]
- pservice = PresenceService.get_instance()
- activity = pservice.get_activity(activity_id)
- service = activity.get_services()[0]
+ pservice = PresenceService.get_instance()
+ activity = pservice.get_activity(activity_id)
+ service = activity.get_services()[0]
- name = "%s [%s]" % (self._bot.name, activity_id)
- properties = { 'title' : service.get_published_value('title'),
- 'color' : service.get_published_value('color') }
+ name = "%s [%s]" % (self._bot.name, activity_id)
+ properties = { 'title' : service.get_published_value('title'),
+ 'color' : service.get_published_value('color') }
- pservice.register_service(name, service.get_type(),
- properties, service.get_address(),
- service.get_port())
+ pservice.register_service(name, service.get_type(),
+ properties, service.get_address(),
+ service.get_port())
- self._bot._service.set_current_activity(activity_id)
+ self._bot._service.set_current_activity(activity_id)
class _ChangeActivityAction(object):
- def __init__(self, bot, named_ref):
- self._bot = bot
- self._named_ref = named_ref
+ def __init__(self, bot, named_ref):
+ self._bot = bot
+ self._named_ref = named_ref
- def execute(self):
- activity_id = _activity_refs[self._named_ref]
- self._bot._service.set_current_activity(activity_id)
+ def execute(self):
+ activity_id = _activity_refs[self._named_ref]
+ self._bot._service.set_current_activity(activity_id)
class _ShareChatAction(object):
- def __init__(self, bot, named_ref, title):
- self._bot = bot
- self._title = title
- self._id = util.unique_id()
+ def __init__(self, bot, named_ref, title):
+ self._bot = bot
+ self._title = title
+ self._id = util.unique_id()
- _activity_refs[named_ref] = self._id
+ _activity_refs[named_ref] = self._id
- def execute(self):
- name = "%s [%s]" % (self._bot.name, self._id)
- stype = '_GroupChatActivity_Sugar_redhat_com._udp'
- properties = { 'title' : self._title,
- 'color' : self._bot.color.to_string() }
- address = u"232.%d.%d.%d" % (random.randint(0, 254),
- random.randint(1, 254),
- random.randint(1, 254))
+ def execute(self):
+ name = "%s [%s]" % (self._bot.name, self._id)
+ stype = '_GroupChatActivity_Sugar_redhat_com._udp'
+ properties = { 'title' : self._title,
+ 'color' : self._bot.color.to_string() }
+ address = u"232.%d.%d.%d" % (random.randint(0, 254),
+ random.randint(1, 254),
+ random.randint(1, 254))
- pservice = PresenceService.get_instance()
- pservice.register_service(name, stype, properties, address)
+ pservice = PresenceService.get_instance()
+ pservice.register_service(name, stype, properties, address)
class _WaitAction(object):
- def __init__(self, bot, seconds):
- self._bot = bot
- self._seconds = seconds
-
- def execute(self):
- self._bot._pause_queue(self._seconds)
+ def __init__(self, bot, seconds):
+ self._bot = bot
+ self._seconds = seconds
+
+ def execute(self):
+ self._bot._pause_queue(self._seconds)
class Bot(object):
- _name_collection = _NameCollection()
+ _name_collection = _NameCollection()
- def __init__(self):
- self.name = Bot._name_collection.get_name()
- self.color = IconColor()
- self.icon = None
+ def __init__(self):
+ self.name = Bot._name_collection.get_name()
+ self.color = IconColor()
+ self.icon = None
- self._queue = []
+ self._queue = []
- def wait(self, seconds):
- action = _WaitAction(self, seconds)
- self._queue.append(action)
+ def wait(self, seconds):
+ action = _WaitAction(self, seconds)
+ self._queue.append(action)
- def share_chat(self, activity_id, title):
- action = _ShareChatAction(self, activity_id, title)
- self._queue.append(action)
+ def share_chat(self, activity_id, title):
+ action = _ShareChatAction(self, activity_id, title)
+ self._queue.append(action)
- def change_activity(self, activity_id):
- action = _ChangeActivityAction(self, activity_id)
- self._queue.append(action)
+ def change_activity(self, activity_id):
+ action = _ChangeActivityAction(self, activity_id)
+ self._queue.append(action)
- def join_activity(self, activity_id):
- action = _JoinActivityAction(self, activity_id)
- self._queue.append(action)
+ def join_activity(self, activity_id):
+ action = _JoinActivityAction(self, activity_id)
+ self._queue.append(action)
- def start(self):
- self._service = _BotService(self)
- self._service.announce()
+ def start(self):
+ self._service = _BotService(self)
+ self._service.announce()
- self._start_queue()
+ self._start_queue()
- def _idle_cb(self):
- self._next_action()
- return True
+ def _idle_cb(self):
+ self._next_action()
+ return True
- def _pause_done_cb(self):
- self._start_queue()
- return False
+ def _pause_done_cb(self):
+ self._start_queue()
+ return False
- def _start_queue(self):
- self._queue_sid = gobject.idle_add(self._idle_cb)
+ def _start_queue(self):
+ self._queue_sid = gobject.idle_add(self._idle_cb)
- def _pause_queue(self, seconds):
- gobject.source_remove(self._queue_sid)
- gobject.timeout_add(int(seconds * 1000), self._pause_done_cb)
+ def _pause_queue(self, seconds):
+ gobject.source_remove(self._queue_sid)
+ gobject.timeout_add(int(seconds * 1000), self._pause_done_cb)
- def _next_action(self):
- if len(self._queue) > 0:
- action = self._queue.pop(0)
- action.execute()
+ def _next_action(self):
+ if len(self._queue) > 0:
+ action = self._queue.pop(0)
+ action.execute()
diff --git a/sugar/util.py b/sugar/util.py
index 108c48e..8ad840d 100644
--- a/sugar/util.py
+++ b/sugar/util.py
@@ -25,50 +25,50 @@ from ConfigParser import ConfigParser
from ConfigParser import NoOptionError
def printable_hash(in_hash):
- """Convert binary hash data into printable characters."""
- printable = ""
- for char in in_hash:
- printable = printable + binascii.b2a_hex(char)
- return printable
+ """Convert binary hash data into printable characters."""
+ printable = ""
+ for char in in_hash:
+ printable = printable + binascii.b2a_hex(char)
+ return printable
def _sha_data(data):
- """sha1 hash some bytes."""
- sha_hash = sha.new()
- sha_hash.update(data)
- return sha_hash.digest()
+ """sha1 hash some bytes."""
+ sha_hash = sha.new()
+ sha_hash.update(data)
+ return sha_hash.digest()
def unique_id(data = ''):
- data_string = "%s%s%s" % (time.time(), random.randint(10000, 100000), data)
- return printable_hash(_sha_data(data_string))
+ data_string = "%s%s%s" % (time.time(), random.randint(10000, 100000), data)
+ return printable_hash(_sha_data(data_string))
ACTIVITY_ID_LEN = 40
def is_hex(s):
- return s.strip(string.hexdigits) == ''
+ return s.strip(string.hexdigits) == ''
def validate_activity_id(actid):
- """Validate an activity ID."""
- if not isinstance(actid, str) and not isinstance(actid, unicode):
- return False
- if len(actid) != ACTIVITY_ID_LEN:
- return False
- if not is_hex(actid):
- return False
- return True
+ """Validate an activity ID."""
+ if not isinstance(actid, str) and not isinstance(actid, unicode):
+ return False
+ if len(actid) != ACTIVITY_ID_LEN:
+ return False
+ if not is_hex(actid):
+ return False
+ return True
class _ServiceParser(ConfigParser):
- def optionxform(self, option):
- return option
+ def optionxform(self, option):
+ return option
def write_service(name, bin, path):
- service_cp = _ServiceParser()
- section = 'D-BUS Service'
- service_cp.add_section(section)
- service_cp.set(section, 'Name', name)
- service_cp.set(section, 'Exec', bin)
+ service_cp = _ServiceParser()
+ section = 'D-BUS Service'
+ service_cp.add_section(section)
+ service_cp.set(section, 'Name', name)
+ service_cp.set(section, 'Exec', bin)
- dest_filename = os.path.join(path, name + '.service')
- fileobject = open(dest_filename, 'w')
- service_cp.write(fileobject)
- fileobject.close()
+ dest_filename = os.path.join(path, name + '.service')
+ fileobject = open(dest_filename, 'w')
+ service_cp.write(fileobject)
+ fileobject.close()