From c21ac3af16d5442c066e9fa8779e79d34161285e Mon Sep 17 00:00:00 2001 From: Goffi Date: Mon, 23 Feb 2026 13:07:59 +0100 Subject: [PATCH] plugin XEP-0060: `add_managed_node` now do strict matching by default: `add_managed_node` now match node when they are exactly the same by default, but if the new `strict_match` argument is set to `False`, the old behaviour of matching all node which start with the given `node` argument is used. rel 475 --- .../backend/plugins/plugin_exp_pubsub_hook.py | 2 +- .../backend/plugins/plugin_pubsub_cache.py | 1 + libervia/backend/plugins/plugin_xep_0060.py | 48 ++++++++++++------- libervia/backend/plugins/plugin_xep_0277.py | 5 +- 4 files changed, 37 insertions(+), 19 deletions(-) diff --git a/libervia/backend/plugins/plugin_exp_pubsub_hook.py b/libervia/backend/plugins/plugin_exp_pubsub_hook.py index 69ae0fbe..0340d0ae 100644 --- a/libervia/backend/plugins/plugin_exp_pubsub_hook.py +++ b/libervia/backend/plugins/plugin_exp_pubsub_hook.py @@ -97,7 +97,7 @@ class PubsubHook(object): else: # first hook on this node self.host.plugins["XEP-0060"].add_managed_node( - node, items_cb=self._items_received + node, strict_match=False, items_cb=self._items_received ) self.node_hooks[node] = 0 log.info(_("node manager installed on {node}").format(node=node)) diff --git a/libervia/backend/plugins/plugin_pubsub_cache.py b/libervia/backend/plugins/plugin_pubsub_cache.py index dfe6696c..c765158b 100644 --- a/libervia/backend/plugins/plugin_pubsub_cache.py +++ b/libervia/backend/plugins/plugin_pubsub_cache.py @@ -81,6 +81,7 @@ class PubsubCache: self.host.trigger.add("XEP-0060_getItems", self._get_items_trigger) self._p.add_managed_node( "", + strict_match=False, items_cb=self.on_items_event, delete_cb=self.on_delete_event, purge_db=self.on_purge_event, diff --git a/libervia/backend/plugins/plugin_xep_0060.py b/libervia/backend/plugins/plugin_xep_0060.py index 8860fc55..97b9f203 100644 --- a/libervia/backend/plugins/plugin_xep_0060.py +++ b/libervia/backend/plugins/plugin_xep_0060.py @@ -18,6 +18,7 @@ from collections import namedtuple +from dataclasses import dataclass, field from functools import reduce from typing import ( Any, @@ -58,7 +59,6 @@ from libervia.backend.tools import sat_defer from libervia.backend.tools import xml_tools from libervia.backend.tools.common import data_format - log = getLogger(__name__) PLUGIN_INFO = { @@ -225,6 +225,12 @@ class NodeMetadata(BaseModel): return self.to_data_form().toElement() +@dataclass +class NodeMonitorData: + strict_match: bool = True + callbacks: dict[str, list[tuple[Callable, int]]] = field(default_factory=dict) + + class XEP_0060: OPT_ACCESS_MODEL = "pubsub#access_model" OPT_PERSIST_ITEMS = "pubsub#persist_items" @@ -260,9 +266,7 @@ class XEP_0060: self.host = host self._rsm = host.plugins.get("XEP-0059") self._mam = host.plugins.get("XEP-0313") - self._node_cb = ( - {} - ) # dictionnary of callbacks for node (key: node, value: list of callbacks) + self._node_cb: dict[str, NodeMonitorData] = {} self.rt_sessions = sat_defer.RTDeferredSessions() host.bridge.add_method( "ps_node_create", @@ -576,13 +580,17 @@ class XEP_0060: return Extra(rsm_request, extra) - def add_managed_node(self, node: str, priority: int = 0, **kwargs: Callable): + def add_managed_node( + self, node: str, priority: int = 0, strict_match=True, **kwargs: Callable + ): """Add a handler for a node @param node: node to monitor all node *prefixed* with this one will be triggered @param priority: priority of the callback. Callbacks with higher priority will be called first. + @param strict_match: if True, will match exactly "node". Otherwise, will match all + nodes which start with "node" @param **kwargs: method(s) to call when the node is found the method must be named after PubSub constants in lower case and suffixed with "_cb" @@ -591,11 +599,13 @@ class XEP_0060: """ assert node is not None assert kwargs - callbacks = self._node_cb.setdefault(node, {}) + monitor_data = self._node_cb.setdefault( + node, NodeMonitorData(strict_match=strict_match) + ) for event, cb in kwargs.items(): event_name = event[:-3] assert event_name in C.PS_EVENTS - cb_list = callbacks.setdefault(event_name, []) + cb_list = monitor_data.callbacks.setdefault(event_name, []) cb_list.append((cb, priority)) cb_list.sort(key=lambda c: c[1], reverse=True) @@ -607,13 +617,13 @@ class XEP_0060: """ assert args try: - registred_cb = self._node_cb[node] + monitor_data = self._node_cb[node] except KeyError: pass else: removed = False for callback in args: - for event, cb_list in registred_cb.items(): + for event, cb_list in monitor_data.callbacks.items(): to_remove = [] for cb in cb_list: if cb[0] == callback: @@ -621,8 +631,8 @@ class XEP_0060: for cb in to_remove: cb_list.remove(cb) if not cb_list: - del registred_cb[event] - if not registred_cb: + del monitor_data[event] + if not monitor_data: del self._node_cb[node] removed = True break @@ -850,7 +860,7 @@ class XEP_0060: try: return [ item["id"] - for item in iq_result.pubsub.publish.elements(pubsub.NS_PUBSUB, "item", extra=extra) + for item in iq_result.pubsub.publish.elements(pubsub.NS_PUBSUB, "item") ] except AttributeError: return [] @@ -988,7 +998,10 @@ class XEP_0060: # possible with XEP-0059's plugin RSMRequest, and convert to Wokkel # rsm.RSMRequest only when we need to work with wokkel directly. if isinstance(rsm_request, rsm.RSMRequest): - log.warning("Use for rsm.RSMRequest is deprecated") + log.warning( + "Use of rsm.RSMRequest is deprecated, use plugin_xep_0059.RSMRequest " + "instead." + ) else: rsm_request = rsm_request.to_wokkel_request() if item_ids and max_items is not None: @@ -1966,11 +1979,14 @@ class SatPubSubClient(rsm.PubSubClient): @param event(unicode): one of C.PS_ITEMS, C.PS_RETRACT, C.PS_DELETE @return (iterator[callable]): callbacks for this node/event """ - for registered_node, callbacks_dict in self.parent_plugin._node_cb.items(): - if not node.startswith(registered_node): + for registered_node, monitor_data in self.parent_plugin._node_cb.items(): + if monitor_data.strict_match: + if node != registered_node: + continue + elif not node.startswith(registered_node): continue try: - for callback_data in callbacks_dict[event]: + for callback_data in monitor_data.callbacks[event]: yield callback_data[0] except KeyError: continue diff --git a/libervia/backend/plugins/plugin_xep_0277.py b/libervia/backend/plugins/plugin_xep_0277.py index 509e4c5c..ca99ad80 100644 --- a/libervia/backend/plugins/plugin_xep_0277.py +++ b/libervia/backend/plugins/plugin_xep_0277.py @@ -56,7 +56,6 @@ from libervia.backend.tools.common import data_format from libervia.backend.tools.common import uri as xmpp_uri from libervia.backend.tools.common import regex - log = getLogger(__name__) @@ -761,7 +760,9 @@ class XEP_0277: } ) self.rt_sessions = sat_defer.RTDeferredSessions() - self._p.add_managed_node(NS_MICROBLOG, items_cb=self._items_received) + self._p.add_managed_node( + NS_MICROBLOG, strict_match=False, items_cb=self._items_received + ) host.bridge.add_method( "mb_send",