diff --git a/libervia/backend/plugins/plugin_xep_0115.py b/libervia/backend/plugins/plugin_xep_0115.py index 402b12a2..68f4e241 100644 --- a/libervia/backend/plugins/plugin_xep_0115.py +++ b/libervia/backend/plugins/plugin_xep_0115.py @@ -415,8 +415,47 @@ class XEP_0115_handler(XMPPHandler): def client(self) -> SatXMPPEntity: return self.parent # type: ignore[return-value] + def _caps_node_cb(self, disco_infos, ver): + """Callback for caps node query.""" + G.host.memory.disco.hashes[ver] = disco_infos + log.debug(f"Cached disco info for caps hash {ver}") + + def _caps_node_eb(self, failure_, server_jid, ver): + """Errback for caps node query.""" + log.warning( + f"Failed to query caps node for {server_jid} (ver={ver}): {failure_}" + ) + def connectionInitialized(self) -> None: assert self.xmlstream is not None + # Check if server advertised caps in stream features (XEP-0115 §6.3) + # xmlstream.features is a dict mapping (ns, name) to element + caps_key = (NS_ENTITY_CAPABILITY, "c") + if caps_key in self.xmlstream.features: + c_elt = self.xmlstream.features[caps_key] + ver = c_elt.getAttribute("ver") + node = c_elt.getAttribute("node") + if ver: + server_jid = self.client.server_jid + G.host.memory.update_entity_data( + self.client, server_jid, C.ENTITY_CAP_HASH, ver + ) + + # If we already have the disco info, we're done + if ver in G.host.memory.disco.hashes: + log.debug( + f"Cached server caps from stream feature: {server_jid} ver={ver}" + ) + else: + # Query the caps node to get disco info (XEP-0115 §6.2) + caps_node = f"{node}#{ver}" if node else ver + log.debug( + f"Querying caps node {caps_node} for server {server_jid}" + ) + d = self.client.disco.requestInfo(server_jid, nodeIdentifier=caps_node) + d.addCallback(self._caps_node_cb, ver) + d.addErrback(self._caps_node_eb, server_jid, ver) + self.xmlstream.addObserver( CAPABILITY_UPDATE, self.plugin_parent._update, client=self.client )