changeset 2534:7da86e1633a5

core: new discoFindFeatures method which return all server services/roster entities implementing a set of features.
author Goffi <goffi@goffi.org>
date Sat, 24 Mar 2018 10:46:09 +0100
parents 8d82a62fa098
children a19b2c43e719
files frontends/src/bridge/dbus_bridge.py src/bridge/bridge_constructor/bridge_template.ini src/bridge/dbus_bridge.py src/core/sat_main.py
diffstat 4 files changed, 91 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/frontends/src/bridge/dbus_bridge.py	Sat Mar 24 10:44:37 2018 +0100
+++ b/frontends/src/bridge/dbus_bridge.py	Sat Mar 24 10:46:09 2018 +0100
@@ -209,6 +209,15 @@
             error_handler = lambda err:errback(dbus_to_bridge_exception(err))
         return self.db_core_iface.delContact(entity_jid, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler)
 
+    def discoFindByFeatures(self, namespaces, service=True, roster=True, own_jid=True, profile_key=u"@DEFAULT@", callback=None, errback=None):
+        if callback is None:
+            error_handler = None
+        else:
+            if errback is None:
+                errback = log.error
+            error_handler = lambda err:errback(dbus_to_bridge_exception(err))
+        return self.db_core_iface.discoFindByFeatures(namespaces, service, roster, own_jid, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler)
+
     def discoInfos(self, entity_jid, node=u'', use_cache=True, profile_key=u"@DEFAULT@", callback=None, errback=None):
         if callback is None:
             error_handler = None
--- a/src/bridge/bridge_constructor/bridge_template.ini	Sat Mar 24 10:44:37 2018 +0100
+++ b/src/bridge/bridge_constructor/bridge_template.ini	Sat Mar 24 10:46:09 2018 +0100
@@ -734,6 +734,27 @@
 doc_param_3=%(doc_profile_key)s
 doc_return=array of tuple (entity, node identifier, name)
 
+[discoFindByFeatures]
+async=
+type=method
+category=core
+sig_in=asbbbs
+sig_out=(a{sa(sss)}a{sa(sss)}a{sa(sss)})
+param_1_default=True
+param_2_default=True
+param_3_default=True
+param_4_default=u"@DEFAULT@"
+doc=Discover items of an entity
+doc_param_0=namespaces: namespaces of the features to check
+doc_param_1=service: True to check server's services
+doc_param_2=roster: True to check connected devices from people in roster
+doc_param_3=own_jid: True to check profile's jid
+doc_param_4=%(doc_profile_key)s
+doc_return=tuple of maps of found entities full jids to their identities. Maps are in this order:
+ - services entities
+ - own entities (i.e. entities linked to profile's jid)
+ - roster entities
+
 [saveParamsTemplate]
 type=method
 category=core
--- a/src/bridge/dbus_bridge.py	Sat Mar 24 10:44:37 2018 +0100
+++ b/src/bridge/dbus_bridge.py	Sat Mar 24 10:46:09 2018 +0100
@@ -234,6 +234,12 @@
         return self._callback("delContact", unicode(entity_jid), unicode(profile_key), callback=callback, errback=errback)
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
+                         in_signature='asbbbs', out_signature='(a{sa(sss)}a{sa(sss)}a{sa(sss)})',
+                         async_callbacks=('callback', 'errback'))
+    def discoFindByFeatures(self, namespaces, service=True, roster=True, own_jid=True, profile_key=u"@DEFAULT@", callback=None, errback=None):
+        return self._callback("discoFindByFeatures", namespaces, service, roster, own_jid, unicode(profile_key), callback=callback, errback=errback)
+
+    @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='ssbs', out_signature='(asa(sss)a{sa(a{ss}as)})',
                          async_callbacks=('callback', 'errback'))
     def discoInfos(self, entity_jid, node=u'', use_cache=True, profile_key=u"@DEFAULT@", callback=None, errback=None):
--- a/src/core/sat_main.py	Sat Mar 24 10:44:37 2018 +0100
+++ b/src/core/sat_main.py	Sat Mar 24 10:46:09 2018 +0100
@@ -118,6 +118,7 @@
         self.bridge.register_method("menuLaunch", self._launchMenu)
         self.bridge.register_method("discoInfos", self.memory.disco._discoInfos)
         self.bridge.register_method("discoItems", self.memory.disco._discoItems)
+        self.bridge.register_method("discoFindByFeatures", self._findByFeatures)
         self.bridge.register_method("saveParamsTemplate", self.memory.save_xml)
         self.bridge.register_method("loadParamsTemplate", self.memory.load_xml)
         self.bridge.register_method("sessionInfosGet", self.getSessionInfos)
@@ -670,6 +671,60 @@
     def findFeaturesSet(self, *args, **kwargs):
         return self.memory.disco.findFeaturesSet(*args, **kwargs)
 
+    def _findByFeatures(self, namespace, service, roster, own_jid, profile_key):
+        client = self.getClient(profile_key)
+        return self.findByFeatures(client, namespace, service, roster, own_jid)
+
+    @defer.inlineCallbacks
+    def findByFeatures(self, client, namespaces, service, roster, own_jid):
+        """retrieve all services or contacts managing a set a features
+
+        @param namespaces(list[unicode]): features which must be handled
+        @param service(bool): if True return service from our roster
+        @param roster(bool): if True, return entities in roster
+            full jid of all matching resources available will be returned
+        @param own_jid(bool): if True, return profile's jid resources
+        @return (tuple(dict[jid.JID(), tuple[unicode, unicode, unicode]]*3)): found entities in a tuple with:
+            - service entities
+            - own entities
+            - roster entities
+        """
+        if not namespaces:
+            raise exceptions.DataError("namespaces must not be empty")
+        found_service = {}
+        found_own = {}
+        found_roster = {}
+        if service:
+            services_jids = yield self.findFeaturesSet(client, namespaces)
+            for service_jid in services_jids:
+                infos = yield self.getDiscoInfos(client, service_jid)
+                identities = [(cat, type_, name or u'') for (cat, type_), name in infos.identities.iteritems()]
+                found_service[service_jid.full()] = identities
+
+        jids = []
+        if roster:
+            jids.extend(client.roster.getJids())
+        if own_jid:
+            jids.append(client.jid.userhostJID())
+
+        for found, jids in ((found_own, [client.jid.userhostJID()]),
+                            (found_roster, client.roster.getJids())):
+            for jid_ in jids:
+                if jid_.resource:
+                    resources = [jid_.resource]
+                else:
+                    try:
+                        resources = self.memory.getAllResources(client, jid_)
+                    except exceptions.UnknownEntityError:
+                        continue
+                for resource in resources:
+                    full_jid = jid.JID(tuple=(jid_.user, jid_.host, resource))
+                    infos = yield self.getDiscoInfos(client, full_jid)
+                    if infos.features.issuperset(namespaces):
+                        identities = [(cat, type_, name or u'') for (cat, type_), name in infos.identities.iteritems()]
+                        found[full_jid.full()] = identities
+
+        defer.returnValue((found_service, found_own, found_roster))
 
     ## Generic HMI ##