comparison src/plugins/plugin_xep_0054.py @ 435:c243f4cb2ad9

plugin XEP-0054: cache now use storage bridge: getCardCache updated to manage profile
author Goffi <goffi@goffi.org>
date Sun, 20 Nov 2011 15:56:51 +0100
parents f964dcec1611
children 02c633a0ddcf
comparison
equal deleted inserted replaced
434:d7e5df876a04 435:c243f4cb2ad9
24 from twisted.internet import protocol, defer, threads, reactor 24 from twisted.internet import protocol, defer, threads, reactor
25 from twisted.words.protocols.jabber import client, jid, xmlstream 25 from twisted.words.protocols.jabber import client, jid, xmlstream
26 from twisted.words.protocols.jabber import error as jab_error 26 from twisted.words.protocols.jabber import error as jab_error
27 from twisted.words.protocols.jabber.xmlstream import IQ 27 from twisted.words.protocols.jabber.xmlstream import IQ
28 import os.path 28 import os.path
29 import pdb
30 29
31 from zope.interface import implements 30 from zope.interface import implements
32 31
33 from wokkel import disco, iwokkel 32 from wokkel import disco, iwokkel
34 33
35 from base64 import b64decode 34 from base64 import b64decode
36 from hashlib import sha1 35 from hashlib import sha1
37 from time import sleep 36 from time import sleep
37 from sat.memory.persistent import PersistentBinaryDict
38 38
39 try: 39 try:
40 from twisted.words.protocols.xmlstream import XMPPHandler 40 from twisted.words.protocols.xmlstream import XMPPHandler
41 except ImportError: 41 except ImportError:
42 from wokkel.subprotocols import XMPPHandler 42 from wokkel.subprotocols import XMPPHandler
66 66
67 def __init__(self, host): 67 def __init__(self, host):
68 info(_("Plugin XEP_0054 initialization")) 68 info(_("Plugin XEP_0054 initialization"))
69 self.host = host 69 self.host = host
70 self.avatar_path = os.path.join(self.host.memory.getConfig('', 'local_dir'), AVATAR_PATH) 70 self.avatar_path = os.path.join(self.host.memory.getConfig('', 'local_dir'), AVATAR_PATH)
71 self.vcard_cache = host.memory.getPrivate("vcard_cache") or {} #used to store nicknames and avatar, key = jid
72 if not os.path.exists(self.avatar_path): 71 if not os.path.exists(self.avatar_path):
73 os.makedirs(self.avatar_path) 72 os.makedirs(self.avatar_path)
74 host.bridge.addMethod("getCard", ".plugin", in_sign='ss', out_sign='s', method=self.getCard) 73 host.bridge.addMethod("getCard", ".plugin", in_sign='ss', out_sign='s', method=self.getCard)
75 host.bridge.addMethod("getAvatarFile", ".plugin", in_sign='s', out_sign='s', method=self.getAvatarFile) 74 host.bridge.addMethod("getAvatarFile", ".plugin", in_sign='s', out_sign='s', method=self.getAvatarFile)
76 host.bridge.addMethod("getCardCache", ".plugin", in_sign='s', out_sign='a{ss}', method=self.getCardCache) 75 host.bridge.addMethod("getCardCache", ".plugin", in_sign='s', out_sign='a{ss}', method=self.getCardCache)
85 @param jid: jid of the owner of the vcard 84 @param jid: jid of the owner of the vcard
86 @param name: name of the item which changed 85 @param name: name of the item which changed
87 @param value: new value of the item 86 @param value: new value of the item
88 @param profile: profile which received the update 87 @param profile: profile which received the update
89 """ 88 """
90 if not self.vcard_cache.has_key(jid.userhost()): 89 client = self.host.getClient(profile)
91 self.vcard_cache[jid.userhost()] = {} 90 if not jid.userhost() in client._vcard_cache:
91 client._vcard_cache[jid.userhost()] = {}
92 92
93 cache = self.vcard_cache[jid.userhost()] 93 cache = client._vcard_cache[jid.userhost()]
94 old_value = cache[name] if cache.has_key(name) else None 94 old_value = cache[name] if name in cache else None
95 if not old_value or value != old_value: 95 if not old_value or value != old_value:
96 cache[name] = value 96 cache[name] = value
97 self.host.memory.setPrivate("vcard_cache", self.vcard_cache) 97 client._vcard_cache.force(jid.userhost()) #we force saving of data to storage
98 self.host.bridge.updatedValue('card_'+name, {'jid':jid.userhost(), name:value}, profile) 98 self.host.bridge.updatedValue('card_'+name, {'jid':jid.userhost(), name:value}, profile)
99 99
100 def get_cache(self, jid, name): 100 def get_cache(self, jid, name, profile):
101 """return cached value for jid 101 """return cached value for jid
102 @param jid: target contact 102 @param jid: target contact
103 @param name: name of the value ('nick' or 'avatar') 103 @param name: name of the value ('nick' or 'avatar')
104 @param profile: %(doc_profile)s
104 @return: wanted value or None""" 105 @return: wanted value or None"""
106 client = self.host.getClient(profile)
105 try: 107 try:
106 return self.vcard_cache[jid.userhost()][name] 108 return client._vcard_cache[jid.userhost()][name]
107 except KeyError: 109 except KeyError:
108 return None 110 return None
109 111
110 112
111 def save_photo(self, photo_xml): 113 def save_photo(self, photo_xml):
202 if not os.path.exists(filename): 204 if not os.path.exists(filename):
203 error (_("Asking for an uncached avatar [%s]") % hash) 205 error (_("Asking for an uncached avatar [%s]") % hash)
204 return "" 206 return ""
205 return filename 207 return filename
206 208
207 def getCardCache(self, target): 209 def getCardCache(self, target, profile_key):
208 """Request for cached values of profile 210 """Request for cached values of profile
209 return the cached nickname and avatar if exists, else get VCard 211 return the cached nickname and avatar if exists, else get VCard
210 """ 212 @param target: target's jid
213 @param profile_key: %(doc_profile_key)s
214 """
215 profile = self.host.memory.getProfileName(profile_key)
216 if not profile:
217 error(_("Profile not found"))
218 return {}
211 to_jid = jid.JID(target) 219 to_jid = jid.JID(target)
212 result = {} 220 result = {}
213 nick = self.get_cache(to_jid, 'nick') 221 nick = self.get_cache(to_jid, 'nick', profile)
214 if nick: 222 if nick:
215 result['nick'] = nick 223 result['nick'] = nick
216 avatar = self.get_cache(to_jid, 'avatar') 224 avatar = self.get_cache(to_jid, 'avatar', profile)
217 if avatar: 225 if avatar:
218 result['avatar'] = avatar 226 result['avatar'] = avatar
219 return result 227 return result
220 228
221 229
226 def __init__(self, plugin_parent): 234 def __init__(self, plugin_parent):
227 self.plugin_parent = plugin_parent 235 self.plugin_parent = plugin_parent
228 self.host = plugin_parent.host 236 self.host = plugin_parent.host
229 237
230 def connectionInitialized(self): 238 def connectionInitialized(self):
239 self.parent._vcard_cache = PersistentBinaryDict(NS_VCARD, self.parent.profile)
231 self.xmlstream.addObserver(VCARD_UPDATE, self.update) 240 self.xmlstream.addObserver(VCARD_UPDATE, self.update)
232 241
233 def getDiscoInfo(self, requestor, target, nodeIdentifier=''): 242 def getDiscoInfo(self, requestor, target, nodeIdentifier=''):
234 return [disco.DiscoFeature(NS_VCARD)] 243 return [disco.DiscoFeature(NS_VCARD)]
235 244
239 def update(self, presence): 248 def update(self, presence):
240 """Request for VCard's nickname 249 """Request for VCard's nickname
241 return the cached nickname if exists, else get VCard 250 return the cached nickname if exists, else get VCard
242 """ 251 """
243 from_jid = jid.JID(presence['from']) 252 from_jid = jid.JID(presence['from'])
253 #FIXME: wokkel's data_form should be used here
244 x_elem = filter (lambda x:x.name == "x", presence.elements())[0] #We only want the "x" element 254 x_elem = filter (lambda x:x.name == "x", presence.elements())[0] #We only want the "x" element
245 for elem in x_elem.elements(): 255 for elem in x_elem.elements():
246 if elem.name == 'photo': 256 if elem.name == 'photo':
247 hash = str(elem) 257 hash = str(elem)
248 old_avatar = self.plugin_parent.get_cache(from_jid, 'avatar') 258 old_avatar = self.plugin_parent.get_cache(from_jid, 'avatar', self.parent.profile)
249 if not old_avatar or old_avatar != hash: 259 if not old_avatar or old_avatar != hash:
250 debug(_('New avatar found, requesting vcard')) 260 debug(_('New avatar found, requesting vcard'))
251 self.plugin_parent.getCard(from_jid.userhost(), self.parent.profile) 261 self.plugin_parent.getCard(from_jid.userhost(), self.parent.profile)