diff src/core/sat_main.py @ 944:e1842ebcb2f3

core, plugin XEP-0115: discovery refactoring: - hashing algorithm of XEP-0115 has been including in core - our own hash is still calculated by XEP-0115 and can be regenerated with XEP_0115.recalculateHash - old discovery methods have been removed. Now the following methods are used: - hasFeature: tell if a feature is available for an entity - getDiscoInfos: self explaining - getDiscoItems: self explaining - findServiceEntities: return all available items of an entity which given (category, type) - findFeaturesSet: search for a set of features in entity + entity's items all these methods are asynchronous, and manage cache automatically - XEP-0115 manage in a better way hashes, and now use a trigger for presence instead of monkey patch - new FeatureNotFound exception, when we want to do something which is not available - refactored client initialisation sequence, removed client.initialized Deferred - added constant APP_URL - test_plugin_xep_0033.py has been temporarly deactivated, the time to adapt it - lot of cleaning
author Goffi <goffi@goffi.org>
date Fri, 28 Mar 2014 18:07:22 +0100
parents 71926ec2114d
children b4cd968e30fb
line wrap: on
line diff
--- a/src/core/sat_main.py	Fri Mar 28 18:07:17 2014 +0100
+++ b/src/core/sat_main.py	Fri Mar 28 18:07:22 2014 +0100
@@ -43,11 +43,6 @@
 from glob import glob
 from uuid import uuid4
 
-try:
-    from twisted.words.protocols.xmlstream import XMPPHandler
-except ImportError:
-    from wokkel.subprotocols import XMPPHandler
-
 ### logging configuration FIXME: put this elsewhere ###
 logging.basicConfig(level=logging.DEBUG,
                     format='%(message)s')
@@ -217,16 +212,6 @@
             info(_("already connected !"))
             return defer.succeed("None")
 
-        if profile in self.profiles:
-            # avoid the following error when self.connect() is called twice for the same profile within a short time period:
-            #   Jumping into debugger for post-mortem of exception ''SatXMPPClient' object has no attribute 'discoHandler'':
-            #   > /usr/local/lib/python2.7/dist-packages/sat/plugins/plugin_xep_0115.py(151)generateHash()
-            #   -> services = client.discoHandler.info(client.jid, client.jid, '').addCallback(generateHash_2, profile)
-            # This is a strange issue that is often happening on my system since libervia is being run as a twisted plugin.
-            # FIXME: properly find the problem an fix it
-            debug("being connected...")
-            return defer.succeed("None")
-
         def afterMemoryInit(ignore):
             """This part must be called when we have loaded individual parameters from memory"""
             try:
@@ -262,17 +247,20 @@
 
             debug(_("setting plugins parents"))
 
+            plugin_conn_cb = []
             for plugin in self.plugins.iteritems():
                 if plugin[1].is_handler:
                     plugin[1].getHandler(profile).setHandlerParent(current)
                 connected_cb = getattr(plugin[1], "profileConnected", None)
                 if connected_cb:
-                    connected_cb(profile)
+                    plugin_conn_cb.append(connected_cb)
 
             current.startService()
 
             d = current.getConnectionDeferred()
-            d.addCallback(lambda x: current.roster.got_roster)  # we want to be sure that we got the roster
+            d.addCallback(lambda dummy: current.roster.got_roster)  # we want to be sure that we got the roster
+            for callback in plugin_conn_cb:
+                d.addCallback(lambda dummy: callback(profile))
             return d
 
         self.memory.startProfileSession(profile)
@@ -360,14 +348,6 @@
             raise exceptions.ProfileKeyUnknownError
         return [self.profiles[profile]]
 
-    def getClientHostJid(self, profile_key):
-        """Convenient method to get the client host from profile key
-        @return: host jid or None if it doesn't exist"""
-        profile = self.memory.getProfileName(profile_key)
-        if not profile:
-            return None
-        return self.profiles[profile].getHostJid()
-
     def registerNewAccount(self, login, password, email, server, port=5222, id_=None, profile_key=C.PROF_KEY_NONE):
         """Connect to a server and create a new account using in-band registration"""
         profile = self.memory.getProfileName(profile_key)
@@ -623,113 +603,26 @@
         self.profiles[profile].roster.removeItem(to_jid)
         self.profiles[profile].presence.unsubscribe(to_jid)
 
-    def requestServerDisco(self, feature, jid_=None, cache_only=False, profile_key="@NONE"):
-        """Discover if a server or its items offer a given feature
-        @param feature: the feature to check
-        @param jid_: the jid of the server, local server if None
-        @param cache_only: expect the result to be in cache and don't actually make any request.
-                           This can be used anytime for requesting a feature on the local server because the data are cached for sure.
-        @result: the Deferred entity jid offering the feature, or None
-
-        """
-        profile = self.memory.getProfileName(profile_key)
-
-        if not profile:
-            return defer.succeed(None)
-        if jid_ is None:
-            jid_ = self.getClientHostJid(profile)
-            cache_only = True
-        hasServerFeature = lambda entity: entity if self.memory.hasServerFeature(feature, entity, profile) else None
 
-        def haveItemsFeature(dummy=None):
-            entities = self.memory.getAllServerIdentities(jid_, profile)
-            if entities is None:
-                return None  # no cached data for this server
-            for entity in entities:
-                if hasServerFeature(entity):
-                    return entity
-            return None  # data are cached but no entity was found
-
-        entity = hasServerFeature(jid_) or haveItemsFeature()
-        if entity:
-            return defer.succeed(entity)
-        elif entity is False or cache_only:
-            return defer.succeed(None)
+    ## Discovery ##
+    # discovery methods are shortcuts to self.memory.disco
+    # the main difference with client.disco is that self.memory.disco manage cache
 
-        # data for this server are not in cache
-        disco = self.profiles[profile].disco
-
-        def errback(failure, method, jid_, profile):
-            # the target server is not reachable
-            logging.error("disco.%s on %s failed! [%s]" % (method.func_name, jid_.userhost(), profile))
-            logging.error("reason: %s" % failure.getErrorMessage())
-            if method == disco.requestInfo:
-                features = self.memory.server_features.setdefault(profile, {})
-                features.setdefault(jid_, [])
-            elif method == disco.requestItems:
-                identities = self.memory.server_identities.setdefault(profile, {})
-                identities.setdefault(jid_, {})
-            return failure
+    def hasFeature(self, *args, **kwargs):
+        return self.memory.disco.hasFeature(*args, **kwargs)
 
-        def callback(d):
-            if hasServerFeature(jid_):
-                return jid_
-            else:
-                d2 = disco.requestItems(jid_).addCallback(self.serverDiscoItems, disco, jid_, profile)
-                d2.addErrback(errback, disco.requestItems, jid_, profile)
-                return d2.addCallback(haveItemsFeature)
-
-        d = disco.requestInfo(jid_).addCallback(self.serverDisco, jid_, profile)
-        d.addCallbacks(callback, errback, [], errbackArgs=[disco.requestInfo, jid_, profile])
-        return d
-
-    ## callbacks ##
+    def getDiscoInfos(self, *args, **kwargs):
+        return self.memory.disco.getInfos(*args, **kwargs)
 
-    def serverDisco(self, disco, jid_=None, profile=None):
-        """xep-0030 Discovery Protocol.
-        @param disco: result of the disco info query
-        @param jid_: the jid of the target server
-        @param profile: profile of the user
-        """
-        if jid_ is None:
-            jid_ = self.getClientHostJid(profile)
-        debug(_("Requested disco info on %s") % jid_)
-        for feature in disco.features:
-            debug(_("Feature found: %s") % feature)
-            self.memory.addServerFeature(feature, jid_, profile)
-        for cat, type_ in disco.identities:
-            debug(_("Identity found: [%(category)s/%(type)s] %(identity)s")
-                  % {'category': cat, 'type': type_, 'identity': disco.identities[(cat, type_)]})
+    def getDiscoItems(self, *args, **kwargs):
+        return self.memory.disco.getItems(*args, **kwargs)
 
-    def serverDiscoItems(self, disco_result, disco_client, jid_, profile, initialized=None):
-        """xep-0030 Discovery Protocol.
-        @param disco_result: result of the disco item querry
-        @param disco_client: SatDiscoProtocol instance
-        @param jid_: the jid of the target server
-        @param profile: profile of the user
-        @param initialized: deferred which must be chained when everything is done"""
+    def findServiceEntities(self, *args, **kwargs):
+        return self.memory.disco.findServiceEntities(*args, **kwargs)
 
-        def _check_entity_cb(result, entity, jid_, profile):
-            debug(_("Requested disco info on %s") % entity)
-            for category, type_ in result.identities:
-                debug(_('Identity added: (%(category)s,%(type)s) ==> %(entity)s [%(profile)s]')
-                      % {'category': category, 'type': type_, 'entity': entity, 'profile': profile})
-                self.memory.addServerIdentity(category, type_, entity, jid_, profile)
-            for feature in result.features:
-                self.memory.addServerFeature(feature, entity, profile)
+    def findFeaturesSet(self, *args, **kwargs):
+        return self.memory.disco.findFeaturesSet(*args, **kwargs)
 
-        def _errback(result, entity, jid_, profile):
-            warning(_("Can't get information on identity [%(entity)s] for profile [%(profile)s]") % {'entity': entity, 'profile': profile})
-
-        defer_list = []
-        for item in disco_result._items:
-            if item.entity.full().count('.') == 1:  # XXX: workaround for a bug on jabberfr, tmp
-                warning(_('Using jabberfr workaround, be sure your domain has at least two levels (e.g. "example.tld", not "example" alone)'))
-                continue
-            args = [item.entity, jid_, profile]
-            defer_list.append(disco_client.requestInfo(item.entity).addCallbacks(_check_entity_cb, _errback, args, None, args))
-        if initialized:
-            defer.DeferredList(defer_list).chainDeferred(initialized)
 
     ## Generic HMI ##