diff src/memory/disco.py @ 973:4a8903021fda

core (disco): findFeaturesSet and findServiceEntities don't use inlineCallbacks anymore, that allow a better error management (no more anonying debugger raise when discoInfo fails in debug mode)
author Goffi <goffi@goffi.org>
date Wed, 02 Apr 2014 12:31:23 +0200
parents 723f28cd15c7
children 301b342c697a
line wrap: on
line diff
--- a/src/memory/disco.py	Wed Apr 02 12:31:23 2014 +0200
+++ b/src/memory/disco.py	Wed Apr 02 12:31:23 2014 +0200
@@ -21,6 +21,7 @@
 from sat.core import exceptions
 from logging import debug, info, warning, error
 from twisted.words.protocols.jabber import jid
+from twisted.words.protocols.jabber.error import StanzaError
 from twisted.internet import defer
 from sat.core.constants import Const as C
 from wokkel import disco
@@ -67,8 +68,8 @@
         @param profile_key: %(doc_profile_key)s
         @return: a Deferred which fire a boolean (True if feature is available)
         """
-        disco_info = yield self.getInfos(jid_, profile_key)
-        defer.returnValue(feature in disco_info.features)
+        disco_infos = yield self.getInfos(jid_, profile_key)
+        defer.returnValue(feature in disco_infos.features)
 
     @defer.inlineCallbacks
     def checkFeature(self, feature, jid_=None, profile_key=C.PROF_KEY_NONE):
@@ -81,12 +82,11 @@
 
         @raise: exceptions.FeatureNotFound
         """
-        disco_info = yield self.getInfos(jid_, profile_key)
-        if not feature in disco_info.features:
+        disco_infos = yield self.getInfos(jid_, profile_key)
+        if not feature in disco_infos.features:
             raise exceptions.FeatureNotFound
-        defer.returnValue(feature in disco_info)
+        defer.returnValue(feature in disco_infos)
 
-    @defer.inlineCallbacks
     def getInfos(self, jid_=None, profile_key=C.PROF_KEY_NONE):
         """get disco infos from jid_, filling capability hash if needed
 
@@ -99,14 +99,18 @@
             jid_ = jid.JID(client.jid.host)
         try:
             cap_hash = self.host.memory.getEntityData(jid_, [C.ENTITY_CAP_HASH], client.profile)[C.ENTITY_CAP_HASH]
-            disco_info = self.hashes[cap_hash]
+            disco_infos = self.hashes[cap_hash]
+            return defer.succeed(disco_infos)
         except KeyError:
             # capability hash is not available, we'll compute one
-            disco_info = yield client.disco.requestInfo(jid_)
-            cap_hash = self.generateHash(disco_info)
-            self.hashes[cap_hash] = disco_info
-            yield self.host.memory.updateEntityData(jid_, C.ENTITY_CAP_HASH, cap_hash, client.profile)
-        defer.returnValue(disco_info)
+            def infosCb(disco_infos):
+                cap_hash = self.generateHash(disco_infos)
+                self.hashes[cap_hash] = disco_infos
+                self.host.memory.updateEntityData(jid_, C.ENTITY_CAP_HASH, cap_hash, client.profile)
+                return disco_infos
+            d = client.disco.requestInfo(jid_)
+            d.addCallback(infosCb)
+            return d
 
     @defer.inlineCallbacks
     def getItems(self, jid_=None, profile_key=C.PROF_KEY_NONE):
@@ -133,7 +137,11 @@
         defer.returnValue(items)
 
 
-    @defer.inlineCallbacks
+    def _infosEb(self, failure, entity_jid):
+        failure.trap(StanzaError)
+        warning(_("Error while requesting [%(jid)s]: %(error)s") % {'jid': entity_jid.full(),
+                                                                    'error': failure.getErrorMessage()})
+
     def findServiceEntities(self, category, type_, jid_=None, profile_key=C.PROF_KEY_NONE):
         """Return all available items of an entity which correspond to (category, type_)
 
@@ -143,16 +151,25 @@
         @param profile_key: %(doc_profile_key)s
         @return: a set of entities or None if no cached data were found
         """
-        found_identities = set()
-        items = yield self.getItems(jid_, profile_key)
-        for item in items:
-            infos = yield self.getInfos(item.entity, profile_key)
+        found_entities = set()
+
+        def infosCb(infos, entity_jid):
             if (category, type_) in infos.identities:
-                found_identities.add(item.entity)
+                found_entities.add(entity_jid)
 
-        defer.returnValue(found_identities)
+        def gotItems(items):
+            defers_list = []
+            for item in items:
+                info_d = self.getInfos(item.entity, profile_key)
+                info_d.addCallbacks(infosCb, self._infosEb, [item.entity], None, [item.entity])
+                defers_list.append(info_d)
+            return defer.DeferredList(defers_list)
 
-    @defer.inlineCallbacks
+        d = self.getItems(jid_, profile_key)
+        d.addCallback(gotItems)
+        d.addCallback(lambda dummy: found_entities)
+        return d
+
     def findFeaturesSet(self, features, category=None, type_=None, jid_=None, profile_key=C.PROF_KEY_NONE):
         """Return entities (including jid_ and its items) offering features
 
@@ -169,9 +186,7 @@
         features = set(features)
         found_entities = set()
 
-        items = yield self.getItems(jid_, profile_key)
-        for entity in [jid_] + [item.entity for item in items]:
-            infos = yield self.getInfos(entity, profile_key)
+        def infosCb(infos, entity):
             if category is not None or type_ is not None:
                 categories = set()
                 types = set()
@@ -180,13 +195,24 @@
                     categories.add(id_cat)
                     types.add(id_type)
                 if category is not None and category not in categories:
-                    continue
+                    return
                 if type_ is not None and type_ not in types:
-                    continue
+                    return
             if features.issubset(infos.features):
                 found_entities.add(entity)
 
-        defer.returnValue(found_entities)
+        def gotItems(items):
+            defer_list = []
+            for entity in [jid_] + [item.entity for item in items]:
+                infos_d = self.getInfos(entity, profile_key)
+                infos_d.addCallbacks(infosCb, self._infosEb, [entity], None, [entity])
+            defer_list.append(infos_d)
+            return defer.DeferredList(defer_list)
+
+        d = self.getItems(jid_, profile_key)
+        d.addCallback(gotItems)
+        d.addCallback(lambda dummy: found_entities)
+        return d
 
     def generateHash(self, services):
         """ Generate a unique hash for given service