diff sat/plugins/plugin_xep_0060.py @ 3756:aa923e6b369f

plugin XEP-0060: better filtering when looking for default pubsub service
author Goffi <goffi@goffi.org>
date Fri, 13 May 2022 18:22:06 +0200
parents 783d6dc87b80
children 5bda9d2e8b35
line wrap: on
line diff
--- a/sat/plugins/plugin_xep_0060.py	Fri May 13 18:19:56 2022 +0200
+++ b/sat/plugins/plugin_xep_0060.py	Fri May 13 18:22:06 2022 +0200
@@ -65,6 +65,12 @@
 # rsm_request is the rsm.RSMRequest build with rsm_ prefixed keys, or None
 # extra is a potentially empty dict
 TIMEOUT = 30
+# minimum features that a pubsub service must have to be selectable as default
+DEFAULT_PUBSUB_MIN_FEAT = {
+ 'http://jabber.org/protocol/pubsub#persistent-items',
+ 'http://jabber.org/protocol/pubsub#publish',
+ 'http://jabber.org/protocol/pubsub#retract-items',
+}
 
 class XEP_0060(object):
     OPT_ACCESS_MODEL = "pubsub#access_model"
@@ -315,8 +321,7 @@
         client.pubsub_client = SatPubSubClient(self.host, self)
         return client.pubsub_client
 
-    @defer.inlineCallbacks
-    def profileConnected(self, client):
+    async def profileConnected(self, client):
         client.pubsub_watching = set()
         try:
             client.pubsub_service = jid.JID(
@@ -325,12 +330,39 @@
         except RuntimeError:
             log.info(
                 _(
-                    "Can't retrieve pubsub_service from conf, we'll use first one that we find"
+                    "Can't retrieve pubsub_service from conf, we'll use first one that "
+                    "we find"
                 )
             )
-            client.pubsub_service = yield self.host.findServiceEntity(
+            pubsub_services = await self.host.findServiceEntities(
                 client, "pubsub", "service"
             )
+            for service_jid in pubsub_services:
+                infos = await self.host.memory.disco.getInfos(client, service_jid)
+                if not DEFAULT_PUBSUB_MIN_FEAT.issubset(infos.features):
+                    continue
+                names = {(n or "").lower() for n in infos.identities.values()}
+                if "libervia pubsub service" in names:
+                    # this is the name of Libervia's side project pubsub service, we know
+                    # that it is a suitable default pubsub service
+                    client.pubsub_service = service_jid
+                    break
+                categories = {(i[0] or "").lower() for i in infos.identities.keys()}
+                if "gateway" in categories or "gateway" in names:
+                    # we don't want to use a gateway as default pubsub service
+                    continue
+                if "jabber:iq:register" in infos.features:
+                    # may be present on gateways, and we don't want a service
+                    # where registration is needed
+                    continue
+                client.pubsub_service = service_jid
+                break
+            else:
+                client.pubsub_service = None
+            pubsub_service_str = (
+                client.pubsub_service.full() if client.pubsub_service else "PEP"
+            )
+            log.info(f"default pubsub service: {pubsub_service_str}")
 
     def getFeatures(self, profile):
         try: