Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarco Pesenti Gritti <marco@localhost.localdomain>2006-09-25 17:15:44 (GMT)
committer Marco Pesenti Gritti <marco@localhost.localdomain>2006-09-25 17:15:44 (GMT)
commitaa71d354b22f50c1f6d4d8fa9353c277fd2374ce (patch)
tree4be5a5c0fe09e75da5c296a3552091bbc47a6956
parent2ad9696c87c039bbf8449665f237157f71f1b060 (diff)
parent5e3d56fe77439b0399d9ff62beb6169be482fffc (diff)
Merge branch 'master' of git+ssh://dev.laptop.org/git/sugar
-rw-r--r--services/presence/Buddy.py33
-rw-r--r--services/presence/BuddyIconCache.py61
-rw-r--r--services/presence/Makefile.am5
-rw-r--r--services/presence/PresenceService.py7
-rw-r--r--shell/model/Owner.py9
5 files changed, 100 insertions, 15 deletions
diff --git a/services/presence/Buddy.py b/services/presence/Buddy.py
index 618902e..2c5d9b6 100644
--- a/services/presence/Buddy.py
+++ b/services/presence/Buddy.py
@@ -104,7 +104,7 @@ class Buddy(object):
"""Represents another person on the network and keeps track of the
activities and resources they make available for sharing."""
- def __init__(self, bus_name, object_id, service):
+ def __init__(self, bus_name, object_id, service, icon_cache):
if not bus_name:
raise ValueError("DBus bus name must be valid")
if not object_id or type(object_id) != type(1):
@@ -137,6 +137,8 @@ class Buddy(object):
if service is not None:
self.add_service(service)
+ self._icon_cache = icon_cache
+
def object_path(self):
return dbus.ObjectPath(self._object_path)
@@ -148,25 +150,37 @@ class Buddy(object):
if result_status == network.RESULT_SUCCESS:
if icon and len(icon):
icon = base64.b64decode(icon)
- logging.debug("Buddy icon for '%s' is size %d" % (self._nick_name, len(icon)))
self._set_icon(icon)
+ self._icon_cache.add_icon(icon)
if (result_status == network.RESULT_FAILED or not icon) and self._icon_tries < 3:
self._icon_tries = self._icon_tries + 1
logging.debug("Failed to retrieve buddy icon for '%s' on try %d of %d" % (self._nick_name, \
self._icon_tries, 3))
- gobject.timeout_add(1000, self._request_buddy_icon, service)
+ gobject.timeout_add(1000, self._get_buddy_icon, service)
return False
- def _request_buddy_icon(self, service):
- """Contact the buddy to retrieve the buddy icon."""
+ def _get_buddy_icon(self, service, retry=False):
+ """Get the buddy's icon. Check the cache first, if its
+ not there get the icon from the buddy over the network."""
+ if retry != True:
+ # Only hit the cache once
+ icon_hash = service.get_one_property('icon-hash')
+ if icon_hash is not None:
+ icon = self._icon_cache.get_icon(icon_hash)
+ if icon:
+ logging.debug("%s: icon cache hit for %s." % (self._nick_name, icon_hash))
+ self._set_icon(icon)
+ return False
+
+ logging.debug("%s: icon cache miss, adding icon to cache." % self._nick_name)
from sugar.p2p import Stream
buddy_stream = Stream.Stream.new_from_service(service, start_reader=False)
writer = buddy_stream.new_writer(service)
success = writer.custom_request("get_buddy_icon", self._request_buddy_icon_cb, service)
if not success:
del writer, buddy_stream
- gobject.timeout_add(1000, self._request_buddy_icon, service)
+ gobject.timeout_add(1000, self._get_buddy_icon, service, True)
return False
def _get_service_key(self, service):
@@ -210,8 +224,7 @@ class Buddy(object):
# A buddy isn't valid until its official presence
# service has been found and resolved
self._valid = True
- logging.debug('Requesting buddy icon %s' % self._nick_name)
- self._request_buddy_icon(service)
+ self._get_buddy_icon(service)
self._color = service.get_one_property(_BUDDY_KEY_COLOR)
if self._color:
self._dbus_helper.PropertyChanged([_BUDDY_KEY_COLOR])
@@ -343,8 +356,8 @@ class Buddy(object):
class Owner(Buddy):
"""Class representing the owner of the machine. This is the client
portion of the Owner, paired with the server portion in Owner.py."""
- def __init__(self, ps, bus_name, object_id):
- Buddy.__init__(self, bus_name, object_id, None)
+ def __init__(self, ps, bus_name, object_id, icon_cache):
+ Buddy.__init__(self, bus_name, object_id, None, icon_cache)
self._nick_name = env.get_nick_name()
self._color = env.get_color()
self._ps = ps
diff --git a/services/presence/BuddyIconCache.py b/services/presence/BuddyIconCache.py
new file mode 100644
index 0000000..59d5e88
--- /dev/null
+++ b/services/presence/BuddyIconCache.py
@@ -0,0 +1,61 @@
+import os, time, md5
+from sugar import env
+from sugar import util
+
+class BuddyIconCache(object):
+ """Caches icons on disk and finds them based on md5 hash."""
+ def __init__(self):
+ ppath = env.get_profile_path()
+ self._cachepath = os.path.join(ppath, "cache", "buddy-icons")
+ if not os.path.exists(self._cachepath):
+ os.makedirs(self._cachepath)
+
+ self._cache = {}
+
+ # Read all cached icons and their sums
+ for fname in os.listdir(self._cachepath):
+ m = md5.new()
+ data = self._get_icon_data(fname)
+ if len(data) == 0:
+ continue
+ m.update(data)
+ printable_hash = util.printable_hash(m.digest())
+ self._cache[printable_hash] = fname
+ del m
+
+ def _get_icon_data(self, fname):
+ fd = open(os.path.join(self._cachepath, fname), "r")
+ data = fd.read()
+ fd.close()
+ del fd
+ return data
+
+ def get_icon(self, printable_hash):
+ if type(printable_hash) != type(u""):
+ raise RuntimeError("printable_hash must be a unicode string.")
+ try:
+ fname = self._cache[printable_hash]
+ return self._get_icon_data(fname)
+ except KeyError:
+ pass
+ return None
+
+ def add_icon(self, icon_data):
+ if len(icon_data) == 0:
+ return
+
+ m = md5.new()
+ m.update(icon_data)
+ printable_hash = util.printable_hash(m.digest())
+ if self._cache.has_key(printable_hash):
+ del m
+ return
+
+ # Write the icon to disk and add an entry to our cache for it
+ m.update(time.asctime())
+ fname = util.printable_hash(m.digest())
+ fd = open(os.path.join(self._cachepath, fname), "w")
+ fd.write(icon_data)
+ fd.close()
+ self._cache[printable_hash] = fname
+ del m
diff --git a/services/presence/Makefile.am b/services/presence/Makefile.am
index c095cb6..f64bc02 100644
--- a/services/presence/Makefile.am
+++ b/services/presence/Makefile.am
@@ -6,11 +6,12 @@ $(service_DATA): $(service_in_files) Makefile
@sed -e "s|\@bindir\@|$(bindir)|" $< > $@
sugardir = $(pkgdatadir)/services/presence
-sugar_PYTHON = \
+sugar_PYTHON = \
__init__.py \
Activity.py \
Buddy.py \
- PresenceService.py \
+ BuddyIconCache.py \
+ PresenceService.py \
Service.py
bin_SCRIPTS = sugar-presence-service
diff --git a/services/presence/PresenceService.py b/services/presence/PresenceService.py
index 73c2efa..77c67ee 100644
--- a/services/presence/PresenceService.py
+++ b/services/presence/PresenceService.py
@@ -5,6 +5,7 @@ import Activity
import random
import logging
from sugar import util
+import BuddyIconCache
_SA_UNRESOLVED = 0
@@ -302,9 +303,11 @@ class PresenceService(object):
self._bus_name = dbus.service.BusName(_PRESENCE_SERVICE, bus=self._session_bus)
self._dbus_helper = PresenceServiceDBusHelper(self, self._bus_name)
+ self._icon_cache = BuddyIconCache.BuddyIconCache()
+
# Our owner object
objid = self._get_next_object_id()
- self._owner = Buddy.Owner(self, self._bus_name, objid)
+ self._owner = Buddy.Owner(self, self._bus_name, objid, self._icon_cache)
self._buddies[self._owner.get_name()] = self._owner
self._started = False
@@ -423,7 +426,7 @@ class PresenceService(object):
except KeyError:
source_addr = service.get_source_address()
objid = self._get_next_object_id()
- buddy = Buddy.Buddy(self._bus_name, objid, service)
+ buddy = Buddy.Buddy(self._bus_name, objid, service, self._icon_cache)
self._buddies[name] = buddy
self._dbus_helper.ServiceAppeared(service.object_path())
if not buddy_was_valid and buddy.is_valid():
diff --git a/shell/model/Owner.py b/shell/model/Owner.py
index 097d9c2..3bf3a55 100644
--- a/shell/model/Owner.py
+++ b/shell/model/Owner.py
@@ -8,6 +8,7 @@ from sugar import env
import logging
from sugar.p2p import Stream
from sugar.presence import PresenceService
+from sugar import util
from model.Invites import Invites
import dbus
@@ -24,11 +25,17 @@ class ShellOwner(object):
user_dir = profile.get_path()
self._icon = None
+ self._icon_hash = ""
for fname in os.listdir(user_dir):
if not fname.startswith("buddy-icon."):
continue
fd = open(os.path.join(user_dir, fname), "r")
self._icon = fd.read()
+ if self._icon:
+ # Get the icon's hash
+ import md5, binascii
+ digest = md5.new(self._icon).digest()
+ self._icon_hash = util.printable_hash(digest)
fd.close()
break
@@ -49,7 +56,7 @@ class ShellOwner(object):
def announce(self):
# Create and announce our presence
color = conf.get_profile().get_color()
- props = {'color':color.to_string()}
+ props = {'color': color.to_string(), 'icon-hash': self._icon_hash}
self._service = self._pservice.register_service(self._nick,
PRESENCE_SERVICE_TYPE, properties=props)
logging.debug("Owner '%s' using port %d" % (self._nick, self._service.get_port()))