changeset 2533:8d82a62fa098

core (disco), plugin XEP-0115: client use + capabilities hash improvment: - modified a couple of method from memory to use client instead of profile - XEP-0115: don't use unique hash for all clients anymore, as disco can be different between clients/components, and even between clients (different identity for instance). hash is now generated per client on each new session.
author Goffi <goffi@goffi.org>
date Sat, 24 Mar 2018 10:44:37 +0100
parents 772447ec070f
children 7da86e1633a5
files src/memory/disco.py src/memory/memory.py src/plugins/plugin_xep_0115.py src/plugins/plugin_xep_0329.py
diffstat 4 files changed, 63 insertions(+), 72 deletions(-) [+]
line wrap: on
line diff
--- a/src/memory/disco.py	Wed Mar 21 19:13:22 2018 +0100
+++ b/src/memory/disco.py	Sat Mar 24 10:44:37 2018 +0100
@@ -284,6 +284,9 @@
         found_entities = set()
 
         def infosCb(infos, entity):
+            if entity is None:
+                log.warning(_(u'received an item without jid'))
+                return
             if identity is not None and identity not in infos.identities:
                 return
             if features.issubset(infos.features):
--- a/src/memory/memory.py	Wed Mar 21 19:13:22 2018 +0100
+++ b/src/memory/memory.py	Sat Mar 24 10:44:37 2018 +0100
@@ -605,7 +605,8 @@
         @param profile_key: %(doc_profile_key)s
         @return: presence data: key=entity JID, value=presence data for this entity
         """
-        profile_cache = self._getProfileCache(profile_key)
+        client = self.host.getClient(profile_key)
+        profile_cache = self._getProfileCache(client)
         entities_presence = {}
 
         for entity_jid, entity_data in profile_cache.iteritems():
@@ -641,14 +642,14 @@
     ## Resources ##
 
     def _getAllResource(self, jid_s, profile_key):
+        client = self.host.getClient(profile_key)
         jid_ = jid.JID(jid_s)
-        return self.getAllResources(jid_, profile_key)
+        return self.getAllResources(client, jid_)
 
-    def getAllResources(self, entity_jid, profile_key):
+    def getAllResources(self, client, entity_jid):
         """Return all resource from jid for which we have had data in this session
 
-        @param entity_jid: bare jid of the entit
-        @param profile_key: %(doc_profile_key)s
+        @param entity_jid: bare jid of the entity
         return (list[unicode]): list of resources
 
         @raise exceptions.UnknownEntityError: if entity is not in cache
@@ -656,7 +657,7 @@
         """
         if entity_jid.resource:
             raise ValueError("getAllResources must be used with a bare jid (got {})".format(entity_jid))
-        profile_cache = self._getProfileCache(profile_key)
+        profile_cache = self._getProfileCache(client)
         try:
             entity_data = profile_cache[entity_jid.userhostJID()]
         except KeyError:
@@ -665,22 +666,21 @@
         resources.discard(None)
         return resources
 
-    def getAvailableResources(self, entity_jid, profile_key):
+    def getAvailableResources(self, client, entity_jid):
         """Return available resource for entity_jid
 
         This method differs from getAllResources by returning only available resources
         @param entity_jid: bare jid of the entit
-        @param profile_key: %(doc_profile_key)s
         return (list[unicode]): list of available resources
 
         @raise exceptions.UnknownEntityError: if entity is not in cache
         """
         available = []
-        for resource in self.getAllResources(entity_jid, profile_key):
+        for resource in self.getAllResources(client, entity_jid):
             full_jid = copy.copy(entity_jid)
             full_jid.resource = resource
             try:
-                presence_data = self.getEntityDatum(full_jid, "presence", profile_key)
+                presence_data = self.getEntityDatum(full_jid, "presence", client.profile)
             except KeyError:
                 log.debug(u"Can't get presence data for {}".format(full_jid))
             else:
@@ -707,7 +707,7 @@
         except KeyError:  # plugin not found
             pass
         try:
-            resources = self.getAllResources(entity_jid, client.profile)
+            resources = self.getAllResources(client, entity_jid)
         except exceptions.UnknownEntityError:
             log.warning(u"Entity is not in cache, we can't find any resource")
             return None
@@ -729,23 +729,13 @@
 
     ## Entities data ##
 
-    def _getProfileCache(self, profile_key):
+    def _getProfileCache(self, client):
         """Check profile validity and return its cache
 
-        @param profile: %(doc_profile_key)_s
+        @param client: SatXMPPClient
         @return (dict): profile cache
-
-        @raise exceptions.ProfileUnknownError: if profile doesn't exist
-        @raise exceptions.ProfileNotInCacheError: if there is no cache for this profile
         """
-        profile = self.getProfileName(profile_key)
-        if not profile:
-            raise exceptions.ProfileUnknownError(_('Trying to get entity data for a non-existant profile'))
-        try:
-            profile_cache = self._entities_cache[profile]
-        except KeyError:
-            raise exceptions.ProfileNotInCacheError
-        return profile_cache
+        return self._entities_cache[client.profile]
 
     def setSignalOnUpdate(self, key, signal=True):
         """Set a signal flag on the key
@@ -759,14 +749,13 @@
         else:
             self._key_signals.discard(key)
 
-    def getAllEntitiesIter(self, with_bare=False, profile_key=C.PROF_KEY_NONE):
+    def getAllEntitiesIter(self, client, with_bare=False):
         """Return an iterator of full jids of all entities in cache
 
         @param with_bare: if True, include bare jids
-        @param profile_key: %(doc_profile_key)s
         @return (list[unicode]): list of jids
         """
-        profile_cache = self._getProfileCache(profile_key)
+        profile_cache = self._getProfileCache(client)
         # we construct a list of all known full jids (bare jid of entities x resources)
         for bare_jid, entity_data in profile_cache.iteritems():
             for resource in entity_data.iterkeys():
@@ -787,9 +776,10 @@
         @param silent(bool): if True, doesn't send signal to frontend, even if there is a signal flag (see setSignalOnUpdate)
         @param profile_key: %(doc_profile_key)s
         """
-        profile_cache = self._getProfileCache(profile_key)
+        client = self.host.getClient(profile_key)
+        profile_cache = self._getProfileCache(client)
         if entity_jid in (C.ENTITY_ALL_RESOURCES, C.ENTITY_ALL):
-            entities = self.getAllEntitiesIter(entity_jid==C.ENTITY_ALL, profile_key)
+            entities = self.getAllEntitiesIter(client, entity_jid==C.ENTITY_ALL)
         else:
             entities = (entity_jid,)
 
@@ -814,9 +804,10 @@
         @raise exceptions.UnknownEntityError: if entity is not in cache
         @raise KeyError: key is not in cache
         """
-        profile_cache = self._getProfileCache(profile_key)
+        client = self.host.getClient(profile_key)
+        profile_cache = self._getProfileCache(client)
         if entity_jid in (C.ENTITY_ALL_RESOURCES, C.ENTITY_ALL):
-            entities = self.getAllEntitiesIter(entity_jid==C.ENTITY_ALL, profile_key)
+            entities = self.getAllEntitiesIter(client, entity_jid==C.ENTITY_ALL)
         else:
             entities = (entity_jid,)
 
@@ -863,7 +854,8 @@
                         continue
             return entity_data
 
-        profile_cache = self._getProfileCache(profile_key)
+        client = self.host.getClient(profile_key)
+        profile_cache = self._getProfileCache(client)
         ret_data = {}
         if entities_jids:
             for entity in entities_jids:
@@ -893,7 +885,8 @@
 
         @raise exceptions.UnknownEntityError: if entity is not in cache
         """
-        profile_cache = self._getProfileCache(profile_key)
+        client = self.host.getClient(profile_key)
+        profile_cache = self._getProfileCache(client)
         try:
             entity_data = profile_cache[entity_jid.userhostJID()][entity_jid.resource]
         except KeyError:
@@ -925,7 +918,8 @@
 
         @raise exceptions.UnknownEntityError: if entity is not in cache
         """
-        profile_cache = self._getProfileCache(profile_key)
+        client = self.host.getClient(profile_key)
+        profile_cache = self._getProfileCache(client)
 
         if delete_all_resources:
             if entity_jid.resource:
@@ -1316,17 +1310,16 @@
 
     ## Misc ##
 
-    def isEntityAvailable(self, entity_jid, profile_key):
+    def isEntityAvailable(self, client, entity_jid):
         """Tell from the presence information if the given entity is available.
 
         @param entity_jid (JID): the entity to check (if bare jid is used, all resources are tested)
-        @param profile_key: %(doc_profile_key)s
         @return (bool): True if entity is available
         """
         if not entity_jid.resource:
-            return bool(self.getAvailableResources) # is any resource is available, entity is available
+            return bool(self.getAvailableResources(client, entity_jid)) # is any resource is available, entity is available
         try:
-            presence_data = self.getEntityDatum(entity_jid, "presence", profile_key)
+            presence_data = self.getEntityDatum(entity_jid, "presence", client.profile)
         except KeyError:
             log.debug(u"No presence information for {}".format(entity_jid))
             return False
--- a/src/plugins/plugin_xep_0115.py	Wed Mar 21 19:13:22 2018 +0100
+++ b/src/plugins/plugin_xep_0115.py	Sat Mar 24 10:44:37 2018 +0100
@@ -62,53 +62,47 @@
     def getHandler(self, client):
         return XEP_0115_handler(self, client.profile)
 
-    def _checkHash(self, disco_d, profile):
-        client = self.host.getClient(profile)
-        client.caps_optimize = None
+    @defer.inlineCallbacks
+    def profileConnected(self, client):
+        # we have to calculate hash for client
+        # because disco infos/identities may change between clients
 
-        if XEP_0115.cap_hash is None:
-            disco_d.addCallback(lambda dummy: self.host.hasFeature(client, NS_CAPS_OPTIMIZE))
-            def updateOptimize(optimize):
-                client.caps_optimize = optimize
-                if optimize:
-                    log.info(_("Caps optimisation enabled"))
-                    client.caps_sent = False
-                else:
-                    log.warning(_("Caps optimisation not available"))
-            disco_d.addCallback(updateOptimize)
-            disco_d.addCallback(lambda dummy: self.recalculateHash(profile))
-        return True
+        # optimize check
+        client._caps_optimize = yield self.host.hasFeature(client, NS_CAPS_OPTIMIZE)
+        if client._caps_optimize:
+            log.info(_(u"Caps optimisation enabled"))
+            client._caps_sent = False
+        else:
+            log.warning(_(u"Caps optimisation not available"))
 
-    def _presenceTrigger(self, client, obj):
-        if XEP_0115.cap_hash is not None:
-            if client.caps_optimize:
-                if client.caps_sent:
-                    return True
-                client.caps_sent = True
-            obj.addChild(XEP_0115.c_elt)
-        return True
-
-    @defer.inlineCallbacks
-    def recalculateHash(self, profile):
-        client = self.host.getClient(profile)
+        # hash generation
         _infos = yield client.discoHandler.info(client.jid, client.jid, '')
         disco_infos = disco.DiscoInfo()
         for item in _infos:
             disco_infos.append(item)
-        cap_hash = self.host.memory.disco.generateHash(disco_infos)
-        log.info("Our capability hash has been generated: [%s]" % cap_hash)
+        disco_infos = disco.DiscoInfo()
+        cap_hash = client._caps_hash = self.host.memory.disco.generateHash(disco_infos)
+        log.info("Our capability hash has been generated: [{cap_hash}]".format(
+            cap_hash = cap_hash))
         log.debug("Generating capability domish.Element")
         c_elt = domish.Element((NS_ENTITY_CAPABILITY, 'c'))
         c_elt['hash'] = 'sha-1'
         c_elt['node'] = C.APP_URL
         c_elt['ver'] = cap_hash
-        XEP_0115.cap_hash = cap_hash
-        XEP_0115.c_elt = c_elt
-        if client.caps_optimize:
-            client.caps_sent = False
+        client._caps_elt = c_elt
+        if client._caps_optimize:
+            client._caps_sent = False
         if cap_hash not in self.host.memory.disco.hashes:
             self.host.memory.disco.hashes[cap_hash] = disco_infos
-            self.host.memory.updateEntityData(client.jid, C.ENTITY_CAP_HASH, cap_hash, profile_key=profile)
+            self.host.memory.updateEntityData(client.jid, C.ENTITY_CAP_HASH, cap_hash, profile_key=client.profile)
+
+    def _presenceTrigger(self, client, obj):
+        if client._caps_optimize:
+            if client._caps_sent:
+                return True
+            client.caps_sent = True
+        obj.addChild(client._caps_elt)
+        return True
 
 
 class XEP_0115_handler(XMPPHandler):
--- a/src/plugins/plugin_xep_0329.py	Wed Mar 21 19:13:22 2018 +0100
+++ b/src/plugins/plugin_xep_0329.py	Sat Mar 24 10:44:37 2018 +0100
@@ -204,6 +204,7 @@
         host.bridge.addMethod("FISList", ".plugin", in_sign='ssa{ss}s', out_sign='aa{ss}', method=self._listFiles, async=True)
         host.bridge.addMethod("FISSharePath", ".plugin", in_sign='ssss', out_sign='s', method=self._sharePath)
         host.trigger.add("XEP-0234_fileSendingRequest", self._fileSendingRequestTrigger)
+        host.registerNamespace('fis', NS_FIS)
 
     def getHandler(self, client):
         return XEP_0329_handler(self)