comparison frontends/src/quick_frontend/quick_app.py @ 2123:c42aab22c2c0

plugin XEP-0054, quick frontend(app): various improvments: - memory.cache is now used - getAvatar and setAvatar has been renamed to avatarGet and avatarSet to follow new convention - getAvatar now return (optionally) full path, and may request vCard or only return avatar in cache - getAvatarFile has been removed as it is not needed anymore (avatarGet can return full path) - getCard has been removed from bridge as it was only used to request avatar - new internal method getBareOfFull return jid to use depending of the jid being part of a MUC or not - cache is now set per profile in client, instead of a general one for all profiles - thanks to the use of memory.cache, correct extension is now used in saved file, according to MIME type - fixed and better cache handling - a warning message is shown if given avatar hash differs from computed one - empty hash value is now in a constant, and ignored if received - QuickApp has been updated to follow new behaviour - Primitivus has been fixed (it was not declaring not using avatars correclty) - jp has been updated to follow new methods name
author Goffi <goffi@goffi.org>
date Sun, 15 Jan 2017 17:51:37 +0100
parents b44558286bbb
children 2f264f3df280
comparison
equal deleted inserted replaced
2122:3970ebcf8830 2123:c42aab22c2c0
48 """Class managing all data relative to one profile, and plugging in mechanism""" 48 """Class managing all data relative to one profile, and plugging in mechanism"""
49 # TODO: handle waiting XMLUI requests: getWaitingConf doesn't exist anymore 49 # TODO: handle waiting XMLUI requests: getWaitingConf doesn't exist anymore
50 # and a way to keep some XMLUI request between sessions is expected in backend 50 # and a way to keep some XMLUI request between sessions is expected in backend
51 host = None 51 host = None
52 bridge = None 52 bridge = None
53 cache_keys_to_get = ['avatar'] 53 # cache_keys_to_get = ['avatar']
54 54
55 def __init__(self, profile): 55 def __init__(self, profile):
56 self.profile = profile 56 self.profile = profile
57 self.connected = False 57 self.connected = False
58 self.whoami = None 58 self.whoami = None
104 log.error(u"Couldn't get features: {}".format(failure)) 104 log.error(u"Couldn't get features: {}".format(failure))
105 self._plug_profile_getFeaturesCb({}) 105 self._plug_profile_getFeaturesCb({})
106 106
107 def _plug_profile_getFeaturesCb(self, features): 107 def _plug_profile_getFeaturesCb(self, features):
108 self.host.features = features 108 self.host.features = features
109 self.host.bridge.getEntitiesData([], ProfileManager.cache_keys_to_get, profile=self.profile, callback=self._plug_profile_gotCachedValues, errback=self._plug_profile_failedCachedValues) 109 # FIXME: we don't use cached value at the moment, but keep the code for later use
110 # it was previously used for avatars, but as we don't get full path here, it's better to request later
111 # self.host.bridge.getEntitiesData([], ProfileManager.cache_keys_to_get, profile=self.profile, callback=self._plug_profile_gotCachedValues, errback=self._plug_profile_failedCachedValues)
112 self._plug_profile_gotCachedValues({})
110 113
111 def _plug_profile_failedCachedValues(self, failure): 114 def _plug_profile_failedCachedValues(self, failure):
112 log.error(u"Couldn't get cached values: {}".format(failure)) 115 log.error(u"Couldn't get cached values: {}".format(failure))
113 self._plug_profile_gotCachedValues({}) 116 self._plug_profile_gotCachedValues({})
114 117
815 entity = jid.JID(entity_s) 818 entity = jid.JID(entity_s)
816 if key == "nick": # this is the roster nick, not the MUC nick 819 if key == "nick": # this is the roster nick, not the MUC nick
817 if entity in self.contact_lists[profile]: 820 if entity in self.contact_lists[profile]:
818 self.contact_lists[profile].setCache(entity, 'nick', value) 821 self.contact_lists[profile].setCache(entity, 'nick', value)
819 self.callListeners('nick', entity, value, profile=profile) 822 self.callListeners('nick', entity, value, profile=profile)
820 elif key == "avatar": 823 elif key == "avatar" and self.AVATARS_HANDLER:
821 if value: # and entity in self.contact_lists[profile]: 824 if value and entity in self.contact_lists[profile]:
822 # FIXME: contact_list check is removed to work around 'avatar' issues 825 self.getAvatar(entity, ignore_cache=True, profile=profile)
823 # (avatar can't be requested if we don't save them here)
824 # avatar need to be refactored properly in backend and here
825 def gotFilename(filename):
826 self.contact_lists[profile].setCache(entity, 'avatar', filename)
827 self.callListeners('avatar', entity, filename, profile=profile)
828 self.bridge.getAvatarFile(value, callback=gotFilename)
829 826
830 def actionManager(self, action_data, callback=None, ui_show_cb=None, user_action=True, profile=C.PROF_KEY_NONE): 827 def actionManager(self, action_data, callback=None, ui_show_cb=None, user_action=True, profile=C.PROF_KEY_NONE):
831 """Handle backend action 828 """Handle backend action
832 829
833 @param action_data(dict): action dict as sent by launchAction or returned by an UI action 830 @param action_data(dict): action dict as sent by launchAction or returned by an UI action
884 else: 881 else:
885 callback(data=data, cb_id=callback_id, profile=profile) 882 callback(data=data, cb_id=callback_id, profile=profile)
886 883
887 self.bridge.launchAction(callback_id, data, profile, callback=action_cb, errback=self.dialogFailure) 884 self.bridge.launchAction(callback_id, data, profile, callback=action_cb, errback=self.dialogFailure)
888 885
889 def getAvatar(self, entity, profile): 886 def _avatarGetCb(self, avatar_path, entity, contact_list, profile):
890 """return avatar path for an entity""" 887 path = avatar_path or self.getDefaultAvatar(entity)
888 contact_list.setCache(entity, "avatar", path)
889 self.callListeners('avatar', entity, path, profile=profile)
890
891 def _avatarGetEb(self, failure, entity, contact_list):
892 log.warning(u"Can't get avatar: {}".format(failure))
893 contact_list.setCache(entity, "avatar", self.getDefaultAvatar(entity))
894
895 def getAvatar(self, entity, cache_only=True, hash_only=False, ignore_cache=False, profile=C.PROF_KEY_NONE):
896 """return avatar path for an entity
897
898 @param entity(jid.JID): entity to get avatar from
899 @param cache_only(bool): if False avatar will be requested if not in cache
900 with current vCard based implementation, it's better to keep True
901 except if we request avatars for roster items
902 @param hash_only(bool): if True avatar hash is returned, else full path
903 @param ignore_cache(bool): if False, won't check local cache and will request backend in every case
904 @return (unicode, None): avatar full path (None if no avatar found)
905 """
891 contact_list = self.contact_lists[profile] 906 contact_list = self.contact_lists[profile]
892 avatar = contact_list.getCache(entity, "avatar") 907 if ignore_cache:
908 avatar = None
909 else:
910 avatar = contact_list.getCache(entity, "avatar", bare_default=None)
893 if avatar is None: 911 if avatar is None:
894 self.bridge.getCard(unicode(entity), profile) 912 self.bridge.avatarGet(
913 unicode(entity),
914 cache_only,
915 hash_only,
916 profile=profile,
917 callback=lambda path: self._avatarGetCb(path, entity, contact_list, profile),
918 errback=lambda failure: self._avatarGetEb(failure, entity, contact_list))
919 # we set avatar to empty string to avoid requesting several time the same avatar
920 # while we are waiting for avatarGet result
895 contact_list.setCache(entity, "avatar", "") 921 contact_list.setCache(entity, "avatar", "")
896 if not avatar:
897 avatar = self.getDefaultAvatar(entity)
898 return avatar 922 return avatar
899 923
900 def getDefaultAvatar(self, entity=None): 924 def getDefaultAvatar(self, entity=None):
901 """return default avatar to use with given entity 925 """return default avatar to use with given entity
902 926