comparison libervia/backend/tools/trigger.py @ 4182:4dc00e848961

core (tools/trigger): new `add_with_check` method: this method add a wrapper which will skip the trigger is the plugin is not available in the session (e.g. a component which doesn't use the plugin).
author Goffi <goffi@goffi.org>
date Sat, 09 Dec 2023 19:19:26 +0100
parents 4b842c1fb686
children 0d7bb4df2343
comparison
equal deleted inserted replaced
4181:bc898879af34 4182:4dc00e848961
17 # You should have received a copy of the GNU Affero General Public License 17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. 18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 19
20 """Misc usefull classes""" 20 """Misc usefull classes"""
21 21
22 import inspect
23 from typing import Callable
22 from libervia.backend.core.i18n import _ 24 from libervia.backend.core.i18n import _
23 from libervia.backend.core.log import getLogger 25 from libervia.backend.core.log import getLogger
26 from libervia.backend.core.core_types import SatXMPPEntity
24 27
25 log = getLogger(__name__) 28 log = getLogger(__name__)
26 29
27 30
28 class TriggerException(Exception): 31 class TriggerException(Exception):
47 MAX_PRIORITY = Number.POSITIVE_INFINITY 50 MAX_PRIORITY = Number.POSITIVE_INFINITY
48 51
49 def __init__(self): 52 def __init__(self):
50 self.__triggers = {} 53 self.__triggers = {}
51 54
52 def add(self, point_name, callback, priority=0): 55 def is_available(self, args: list):
56 """Check if plugin used in a client context, and if it's available"""
57 if not args or not isinstance(args[0], SatXMPPEntity):
58 # we are not in the context of a client
59 return True
60 client = args[0]
61 if not client.is_component:
62 # plugins are always avaialble for normal clients
63 return True
64
65
66 def add(self, point_name, callback: Callable, priority=0):
53 """Add a trigger to a point 67 """Add a trigger to a point
54 68
55 @param point_name: name of the point when the trigger should be run 69 @param point_name: name of the point when the trigger should be run
56 @param callback: method to call at the trigger point 70 @param callback: method to call at the trigger point
57 @param priority: callback will be called in priority order, biggest 71 @param priority: callback will be called in priority order, biggest
71 ) 85 )
72 self.__triggers[point_name].append((priority, callback)) 86 self.__triggers[point_name].append((priority, callback))
73 self.__triggers[point_name].sort( 87 self.__triggers[point_name].sort(
74 key=lambda trigger_tuple: trigger_tuple[0], reverse=True 88 key=lambda trigger_tuple: trigger_tuple[0], reverse=True
75 ) 89 )
90
91 def add_with_check(
92 self,
93 point_name: str,
94 plugin,
95 callback: Callable,
96 priority: int=0
97 ) -> None:
98 """Like [Add], but check session before running the trigger
99
100 This method is to be used for triggers which can run in components and are
101 expecting a ``client``: as all plugins are not run for component, a check will be
102 added before running the trigger, if the plugin is not valid for this component,
103 the trigger is ignored. ``client`` must be the first positional argument.
104
105 @param point_name: name of the trigger point
106 @param plugin: instance of the plugin using this trigger. This is necessary to
107 check if the plugin is available in the session.
108 @param callback: method to call at the trigger point
109 @param priority: callback will be called in priority order, biggest first
110 """
111 if inspect.iscoroutinefunction(callback):
112 async def async_wrapper(client: SatXMPPEntity, *args, **kwargs):
113 if client.is_component and plugin not in client.plugins:
114 log.debug(f"Ignoring {callback} as parent plugin is not available")
115 return True
116 else:
117 return await callback(client, *args, **kwargs)
118 self.add(point_name, async_wrapper, priority)
119 else:
120 def sync_wrapper(client: SatXMPPEntity, *args, **kwargs):
121 if client.is_component and plugin not in client.plugins:
122 log.debug(f"Ignoring {callback} as parent plugin is not available")
123 return True
124 else:
125 return callback(client, *args, **kwargs)
126 self.add(point_name, sync_wrapper, priority)
76 127
77 def remove(self, point_name, callback): 128 def remove(self, point_name, callback):
78 """Remove a trigger from a point 129 """Remove a trigger from a point
79 130
80 @param point_name: name of the point when the trigger should be run 131 @param point_name: name of the point when the trigger should be run