vici: Add decorators to Python bindings to simplify listening for events
This commit is contained in:
@@ -7,8 +7,8 @@ side implementation of the VICI protocol, well suited to script automated tasks
|
|||||||
in a reliable way.
|
in a reliable way.
|
||||||
|
|
||||||
|
|
||||||
Example Usage
|
Basic Usage
|
||||||
-------------
|
-----------
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
@@ -22,3 +22,26 @@ Example Usage
|
|||||||
>>> s.get_pools()
|
>>> s.get_pools()
|
||||||
OrderedDict([('p1', OrderedDict([('base', b'10.0.0.0'), ('size', b'254'),
|
OrderedDict([('p1', OrderedDict([('base', b'10.0.0.0'), ('size', b'254'),
|
||||||
('online', b'0'), ('offline', b'0')]))])
|
('online', b'0'), ('offline', b'0')]))])
|
||||||
|
|
||||||
|
Event Handling
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Either use the convenient decorators provided by EventListener or directly call
|
||||||
|
listen() on a Session object to loop over received events and dispatch them
|
||||||
|
manually.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
>>> import vici
|
||||||
|
>>> s = vici.Session()
|
||||||
|
>>> l = vici.EventListener(s)
|
||||||
|
>>> @l.on_events(['ike-updown', 'ike-rekey'])
|
||||||
|
... def ike_events(name, data):
|
||||||
|
... """Handle event with given 'name' and 'data'."""
|
||||||
|
... print(name, data)
|
||||||
|
...
|
||||||
|
>>> @l.on_events(['child-updown', 'child-rekey'])
|
||||||
|
... def child_events(name, data):
|
||||||
|
... print(name, data)
|
||||||
|
...
|
||||||
|
>>> l.listen()
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
|
from .event_listener import EventListener
|
||||||
from .session import Session
|
from .session import Session
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
from functools import wraps
|
||||||
|
|
||||||
|
|
||||||
|
class EventListener(object):
|
||||||
|
def __init__(self, session=None):
|
||||||
|
"""Create an event listener instance, which provides decorator methods
|
||||||
|
to make listening for events and the disconnection of the vici session
|
||||||
|
more convenient.
|
||||||
|
|
||||||
|
The session is optional here, but one must be set via
|
||||||
|
:func:`~set_session()` before calling :func:`~listen()`.
|
||||||
|
|
||||||
|
:param session: optional vici session to use
|
||||||
|
:type session: :class:`~vici.session.Session` or None
|
||||||
|
"""
|
||||||
|
self.event_map = {}
|
||||||
|
self.disconnect_list = []
|
||||||
|
self.session = session
|
||||||
|
|
||||||
|
def set_session(self, session):
|
||||||
|
"""Set the session that's used to listen for events. Only has an effect
|
||||||
|
when set before calling :func:`~listen()`.
|
||||||
|
|
||||||
|
:param session: vici session to use
|
||||||
|
:type session: :class:`~vici.session.Session`
|
||||||
|
"""
|
||||||
|
self.session = session
|
||||||
|
|
||||||
|
def on_events(self, events):
|
||||||
|
"""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.
|
||||||
|
|
||||||
|
:param events: events to register and call decorated function for
|
||||||
|
:type events: list
|
||||||
|
:return: decorator function
|
||||||
|
:rtype: any
|
||||||
|
"""
|
||||||
|
def decorator(func):
|
||||||
|
self.event_map.update({event: func for event in events})
|
||||||
|
|
||||||
|
@wraps(func)
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
return func(*args, **kwargs)
|
||||||
|
return wrapper
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
:return: decorator function
|
||||||
|
:rtype: any
|
||||||
|
"""
|
||||||
|
def decorator(func):
|
||||||
|
self.disconnect_list.append(func)
|
||||||
|
|
||||||
|
@wraps(func)
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
return func(*args, **kwargs)
|
||||||
|
return wrapper
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
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:
|
||||||
|
for func in self.disconnect_list:
|
||||||
|
func(self)
|
||||||
Reference in New Issue
Block a user