]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
vici: Provide a way to stop listening and re-connect in Python bindings
authorTobias Brunner <tobias@strongswan.org>
Fri, 3 Oct 2025 08:59:03 +0000 (10:59 +0200)
committerTobias Brunner <tobias@strongswan.org>
Fri, 3 Oct 2025 09:43:33 +0000 (11:43 +0200)
This allows re-connecting to a new session in a disconnect listener and
continue listening without having to return from listen().  The exception
can also be used to stop listening after some condition (e.g. to wait
until a specific SA got created and then stop).

src/libcharon/plugins/vici/python/vici/__init__.py
src/libcharon/plugins/vici/python/vici/event_listener.py

index 12f84b36678c0ab49c53ae58264937b96f41661a..3ba21a89b4f1414de2116dd2053973a4af0b3c06 100644 (file)
@@ -1,2 +1,2 @@
-from .event_listener import EventListener
+from .event_listener import EventListener, StopListening
 from .session import Session
index f52ee867114529615ae795e123077a531ab2e24a..8594875aacc2e335afa3bfc9ca1cc5468f53063d 100644 (file)
@@ -1,6 +1,10 @@
 from functools import wraps
 
 
+class StopListening(Exception):
+    """Exception that may be raised to stop listening for events."""
+
+
 class EventListener(object):
     def __init__(self, session=None):
         """Create an event listener instance, which provides decorator methods
@@ -30,7 +34,8 @@ class EventListener(object):
         """Decorator to mark a function as a listener for specific events.
 
         The decorated function is expected to receive the name of the event and
-        the data as arguments.
+        the data as arguments. It may raise :class:`~StopListening` to stop
+        listening and let :func:`~listen()` return.
 
         :param events: events to register and call decorated function for
         :type events: list
@@ -48,8 +53,12 @@ class EventListener(object):
 
     def on_disconnected(self):
         """Decorator to mark a function as a listener for when the daemon
-        disconnects the vici session. This listener instance is passed to the
-        decorated function.
+        disconnects the vici session.
+
+        This listener instance is passed to the decorated function, which may
+        be used to set a new session and continue listening. If no session is
+        set, :func:`~listen()` will return after the decorated function has
+        been called.
 
         :return: decorator function
         :rtype: any
@@ -66,20 +75,27 @@ class EventListener(object):
     def listen(self):
         """Dispatch events registered via decorators of this instance.
 
-        This method does not return unless the daemon disconnects or an
-        exception occurs.
-
         An active session has to be set before calling this. After getting
-        disconnected, a new session may be set via :func:`~set_session()`
-        before calling this again.
+        disconnected, a new session may be set via :func:`~set_session()` in
+        a function decorated with :func:`~on_disconnected()` to resume
+        listening for events.
+
+        This method does not return unless :class:`~StopListening` or an
+        unexpected exception is raised or if the current session is disonnected
+        and no new session is set in a listener.
         """
-        try:
-            if self.session is None:
-                return
-            for label, event in self.session.listen(self.event_map.keys()):
-                name = label.decode()
-                if name in self.event_map:
-                    self.event_map[name](name, event)
-        except IOError as e:
-            for func in self.disconnect_list:
-                func(self)
+        while True:
+            try:
+                if self.session is None:
+                    break
+                for label, event in self.session.listen(self.event_map.keys()):
+                    name = label.decode()
+                    if name in self.event_map:
+                        self.event_map[name](name, event)
+            except IOError as e:
+                self.session = None
+                for func in self.disconnect_list:
+                    func(self)
+                continue
+            except StopListening:
+                break