new icon cache system
This commit is contained in:
parent
a1f5684944
commit
4c0352e9bc
@ -32,7 +32,7 @@ class Buddy(dbus.service.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, icon_cache, handle=None):
|
||||
def __init__(self, bus_name, object_id, handle=None):
|
||||
if not bus_name:
|
||||
raise ValueError("DBus bus name must be valid")
|
||||
if not object_id or not isinstance(object_id, int):
|
||||
@ -46,10 +46,9 @@ class Buddy(dbus.service.Object):
|
||||
|
||||
self._activities = {} # Activity ID -> Activity
|
||||
|
||||
self._icon_cache = icon_cache
|
||||
|
||||
self.handles = {} # tp client -> handle
|
||||
|
||||
self._icon = None
|
||||
self._nick_name = None
|
||||
self._color = None
|
||||
self._key = None
|
||||
@ -149,7 +148,7 @@ class Buddy(dbus.service.Object):
|
||||
return None
|
||||
return self._activities[self._current_activity]
|
||||
|
||||
def _set_icon(self, icon):
|
||||
def set_icon(self, icon):
|
||||
"""Can only set icon for other buddies. The Owner
|
||||
takes care of setting it's own icon."""
|
||||
if icon != self._icon:
|
||||
@ -181,8 +180,8 @@ class Buddy(dbus.service.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, icon_cache):
|
||||
Buddy.__init__(self, bus_name, object_id, icon_cache)
|
||||
def __init__(self, ps, bus_name, object_id):
|
||||
Buddy.__init__(self, bus_name, object_id)
|
||||
|
||||
self._ps = ps
|
||||
self._nick_name = profile.get_nick_name()
|
||||
|
@ -1,4 +1,5 @@
|
||||
# Copyright (C) 2007, Red Hat, Inc.
|
||||
# Copyright (C) 2007, Collabora Ltd.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@ -14,64 +15,64 @@
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
import os, time, md5
|
||||
from sugar import env
|
||||
from sugar import util
|
||||
|
||||
import os.path
|
||||
import cPickle
|
||||
|
||||
class BuddyIconCache(object):
|
||||
"""Caches icons on disk and finds them based on md5 hash."""
|
||||
"""Caches icons on disk and finds them based on the jid of their owners."""
|
||||
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._cachepath = os.path.join(ppath, "cache", "buddy-icons", "cache")
|
||||
|
||||
if not os.path.exists(self._cachepath):
|
||||
self._cache = {}
|
||||
else:
|
||||
self._load_cache()
|
||||
|
||||
def _load_cache(self):
|
||||
try:
|
||||
self._cache = cPickle.load(open(self._cachepath, "r"))
|
||||
except:
|
||||
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 _save_cache(self):
|
||||
out = open(self._cachepath, "w")
|
||||
cPickle.dump(self._cache, out, protocol=2)
|
||||
|
||||
def get_icon(self, jid, token):
|
||||
hit = self._cache.get(jid)
|
||||
|
||||
if hit:
|
||||
t, icon = hit[0], hit[1]
|
||||
if t == token:
|
||||
return icon
|
||||
|
||||
def get_icon(self, printable_hash):
|
||||
if not isinstance(printable_hash, unicode):
|
||||
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
|
||||
def store_icon(self, jid, token, data):
|
||||
self._cache[jid] = (token, data)
|
||||
self._save_cache()
|
||||
|
||||
m = md5.new()
|
||||
m.update(icon_data)
|
||||
printable_hash = util.printable_hash(m.digest())
|
||||
if self._cache.has_key(printable_hash):
|
||||
del m
|
||||
return
|
||||
if __name__ == "__main__":
|
||||
my_cache = BuddyIconCache()
|
||||
|
||||
# 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
|
||||
# look for the icon in the cache
|
||||
icon = my_cache.get_icon("test@olpc.collabora.co.uk", "aaaa")
|
||||
print icon
|
||||
|
||||
my_cache.store_icon("test@olpc.collabora.co.uk", "aaaa", "icon1")
|
||||
|
||||
# now we're sure that the icon is in the cache
|
||||
icon = my_cache.get_icon("test@olpc.collabora.co.uk", "aaaa")
|
||||
print icon
|
||||
|
||||
# new icon
|
||||
my_cache.store_icon("test@olpc.collabora.co.uk", "bbbb", "icon2")
|
||||
|
||||
# the icon in the cache is not valid now
|
||||
icon = my_cache.get_icon("test@olpc.collabora.co.uk", "aaaa")
|
||||
print icon
|
||||
|
@ -26,8 +26,6 @@ from linklocal_plugin import LinkLocalPlugin
|
||||
|
||||
from buddy import Buddy, Owner
|
||||
from activity import Activity
|
||||
import buddyiconcache
|
||||
|
||||
|
||||
_PRESENCE_SERVICE = "org.laptop.Sugar.Presence"
|
||||
_PRESENCE_INTERFACE = "org.laptop.Sugar.Presence"
|
||||
@ -48,14 +46,12 @@ class PresenceService(dbus.service.Object):
|
||||
self._handles = {} # tp client -> (handle -> Buddy)
|
||||
self._activities = {} # activity id -> Activity
|
||||
|
||||
self._icon_cache = buddyiconcache.BuddyIconCache()
|
||||
|
||||
bus = dbus.SessionBus()
|
||||
self._bus_name = dbus.service.BusName(_PRESENCE_SERVICE, bus=bus)
|
||||
|
||||
# Create the Owner object
|
||||
objid = self._get_next_object_id()
|
||||
self._owner = Owner(self, self._bus_name, objid, self._icon_cache)
|
||||
self._owner = Owner(self, self._bus_name, objid)
|
||||
self._buddies[self._owner.get_key()] = self._owner
|
||||
|
||||
self._registry = ManagerRegistry()
|
||||
@ -68,6 +64,7 @@ class PresenceService(dbus.service.Object):
|
||||
self._server_plugin.connect('status', self._server_status_cb)
|
||||
self._server_plugin.connect('contact-online', self._contact_online)
|
||||
self._server_plugin.connect('contact-offline', self._contact_offline)
|
||||
self._server_plugin.connect('avatar-updated', self._avatar_updated)
|
||||
self._server_plugin.start()
|
||||
|
||||
# Set up the link local connection
|
||||
@ -86,9 +83,9 @@ class PresenceService(dbus.service.Object):
|
||||
if not buddy:
|
||||
# we don't know yet this buddy
|
||||
objid = self._get_next_object_id()
|
||||
buddy = Buddy(self._bus_name, objid, self._icon_cache, handle=handle)
|
||||
buddy = Buddy(self._bus_name, objid, handle=handle)
|
||||
buddy.set_key(key)
|
||||
print "create buddy"
|
||||
print "create buddy", key
|
||||
self._buddies[key] = buddy
|
||||
new_buddy = True
|
||||
|
||||
@ -120,6 +117,12 @@ class PresenceService(dbus.service.Object):
|
||||
self._next_object_id = self._next_object_id + 1
|
||||
return self._next_object_id
|
||||
|
||||
def _avatar_updated(self, tp, handle, avatar):
|
||||
buddy = self._handles[tp].get(handle)
|
||||
|
||||
if buddy:
|
||||
buddy.set_icon(avatar)
|
||||
|
||||
@dbus.service.signal(_PRESENCE_INTERFACE, signature="o")
|
||||
def ActivityAppeared(self, activity):
|
||||
pass
|
||||
|
@ -18,6 +18,7 @@
|
||||
import gobject
|
||||
from sugar import profile
|
||||
from sugar import util
|
||||
from buddyiconcache import BuddyIconCache
|
||||
import logging
|
||||
|
||||
from telepathy.client import ConnectionManager, ManagerRegistry, Connection, Channel
|
||||
@ -38,14 +39,18 @@ class ServerPlugin(gobject.GObject):
|
||||
'contact-offline': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT])),
|
||||
'status': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_INT, gobject.TYPE_INT]))
|
||||
([gobject.TYPE_INT, gobject.TYPE_INT])),
|
||||
'avatar-updated': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||
([gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT]))
|
||||
}
|
||||
|
||||
def __init__(self, registry):
|
||||
gobject.GObject.__init__(self)
|
||||
|
||||
self._icon_cache = BuddyIconCache()
|
||||
|
||||
self._registry = registry
|
||||
self._online_contacts = set()
|
||||
self._online_contacts = set() # handles of online contacts
|
||||
self._account = self._get_account_info()
|
||||
|
||||
self._ever_connected = False
|
||||
@ -154,8 +159,9 @@ class ServerPlugin(gobject.GObject):
|
||||
# hack
|
||||
self._conn._valid_interfaces.add(CONN_INTERFACE_AVATARS)
|
||||
|
||||
self._conn[CONN_INTERFACE_AVATARS].connect_to_signal('AvatarUpdated', self._avatar_updated_cb)
|
||||
#if CONN_INTERFACE_AVATARS in self._conn:
|
||||
# #tokens = self._conn[CONN_INTERFACE_AVATARS].RequestAvatarTokens(subscribe_handles)
|
||||
# tokens = self._conn[CONN_INTERFACE_AVATARS].RequestAvatarTokens(subscribe_handles)
|
||||
|
||||
# #for handle, token in zip(subscribe_handles, tokens):
|
||||
# for handle in subscribe_handles:
|
||||
@ -212,15 +218,15 @@ class ServerPlugin(gobject.GObject):
|
||||
self._conn[CONN_INTERFACE].Disconnect()
|
||||
|
||||
def _contact_go_offline(self, handle):
|
||||
name = self._conn[CONN_INTERFACE].InspectHandles(CONNECTION_HANDLE_TYPE_CONTACT, [handle])[0]
|
||||
print name, "offline"
|
||||
jid = self._conn[CONN_INTERFACE].InspectHandles(CONNECTION_HANDLE_TYPE_CONTACT, [handle])[0]
|
||||
print jid, "offline"
|
||||
|
||||
self._online_contacts.remove(handle)
|
||||
self.emit("contact-offline", handle)
|
||||
|
||||
def _contact_go_online(self, handle):
|
||||
name = self._conn[CONN_INTERFACE].InspectHandles(CONNECTION_HANDLE_TYPE_CONTACT, [handle])[0]
|
||||
print name, "online"
|
||||
jid = self._conn[CONN_INTERFACE].InspectHandles(CONNECTION_HANDLE_TYPE_CONTACT, [handle])[0]
|
||||
print jid, "online"
|
||||
|
||||
# TODO: use the OLPC interface to get the key
|
||||
key = handle
|
||||
@ -241,3 +247,15 @@ class ServerPlugin(gobject.GObject):
|
||||
elif online and status in ["offline", "invisible"]:
|
||||
self._contact_go_offline(handle)
|
||||
|
||||
def _avatar_updated_cb(self, handle, new_avatar_token):
|
||||
jid = self._conn[CONN_INTERFACE].InspectHandles(CONNECTION_HANDLE_TYPE_CONTACT, [handle])[0]
|
||||
|
||||
icon = self._icon_cache.get_icon(jid, new_avatar_token)
|
||||
|
||||
if not icon:
|
||||
# cache miss
|
||||
avatar, mime_type = self._conn[CONN_INTERFACE_AVATARS].RequestAvatar(handle)
|
||||
icon = ''.join(map(chr, avatar))
|
||||
self._icon_cache.store_icon(jid, new_avatar_token, icon)
|
||||
|
||||
self.emit("avatar-updated", handle, icon)
|
||||
|
Loading…
Reference in New Issue
Block a user