From a6b7fa04ab0dea2e2fe70d66b49006aeb795e502 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krist=C3=B3f=20T=C3=B3th?= Date: Tue, 24 Jul 2018 17:16:57 +0200 Subject: [PATCH] Rework fsm_update API --- .../components/fsm_managing_event_handler.py | 21 ++++++++++--------- lib/tfw/event_handler_base.py | 11 +++++----- lib/tfw/fsm/fsm_base.py | 18 ++++++++++++++-- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/lib/tfw/components/fsm_managing_event_handler.py b/lib/tfw/components/fsm_managing_event_handler.py index 47761a0..39ec3ae 100644 --- a/lib/tfw/components/fsm_managing_event_handler.py +++ b/lib/tfw/components/fsm_managing_event_handler.py @@ -25,7 +25,7 @@ class FSMManagingEventHandler(EventHandlerBase): try: message = self.command_handlers[message['data']['command']](message) if message: - fsm_update_message = self._fsm_updater.generate_fsm_update() + fsm_update_message = self._fsm_updater.fsm_update sign_message(self.auth_key, message) sign_message(self.auth_key, fsm_update_message) self.server_connector.broadcast(fsm_update_message) @@ -52,23 +52,24 @@ class FSMUpdater: def __init__(self, fsm): self.fsm = fsm - def generate_fsm_update(self): + @property + def fsm_update(self): return { 'key': 'fsm_update', - 'data': self.get_fsm_state_and_transitions() + 'data': self.fsm_update_data } - def get_fsm_state_and_transitions(self): - state = self.fsm.state + @property + def fsm_update_data(self): valid_transitions = [ {'trigger': trigger} for trigger in self.fsm.get_triggers(self.fsm.state) ] - last_trigger = self.fsm.trigger_history[-1] if self.fsm.trigger_history else None - in_accepted_state = state in self.fsm.accepted_states + last_fsm_event = self.fsm.event_log[-1] + last_fsm_event['timestamp'] = last_fsm_event['timestamp'].isoformat() return { - 'current_state': state, + 'current_state': self.fsm.state, 'valid_transitions': valid_transitions, - 'last_trigger': last_trigger, - 'in_accepted_state': in_accepted_state + 'in_accepted_state': self.fsm.in_accepted_state, + 'last_event': last_fsm_event } diff --git a/lib/tfw/event_handler_base.py b/lib/tfw/event_handler_base.py index de170f0..4c7ad06 100644 --- a/lib/tfw/event_handler_base.py +++ b/lib/tfw/event_handler_base.py @@ -109,7 +109,7 @@ class EventHandlerBase(ABC): class FSMAware: def __init__(self): self.fsm_state = None - self.in_accepted_state = False + self.fsm_in_accepted_state = False self._auth_key = KeyManager().auth_key def update_fsm_data(self, message): @@ -121,17 +121,18 @@ class FSMAware: def _handle_fsm_update(self, message): try: new_state = message['data']['current_state'] - trigger = message['data']['last_trigger'] if self.fsm_state != new_state: - self.handle_fsm_step(self.fsm_state, new_state, trigger) + self.handle_fsm_step(**(message['data'])) self.fsm_state = new_state - self.in_accepted_state = message['data']['in_accepted_state'] + self.fsm_in_accepted_state = message['data']['in_accepted_state'] except KeyError: LOG.error('Invalid fsm_update message received!') - def handle_fsm_step(self, from_state, to_state, trigger): + def handle_fsm_step(self, **kwargs): """ Called in case the TFW FSM has stepped. + + :param kwargs: fsm_update 'data' field """ pass diff --git a/lib/tfw/fsm/fsm_base.py b/lib/tfw/fsm/fsm_base.py index 7ae8157..e33ae33 100644 --- a/lib/tfw/fsm/fsm_base.py +++ b/lib/tfw/fsm/fsm_base.py @@ -2,6 +2,7 @@ # All Rights Reserved. See LICENSE file for details. from collections import defaultdict +from datetime import datetime from transitions import Machine, MachineError @@ -24,7 +25,7 @@ class FSMBase(Machine, CallbackMixin): def __init__(self, initial=None, accepted_states=None): self.accepted_states = accepted_states or [self.states[-1].name] self.trigger_predicates = defaultdict(list) - self.trigger_history = [] + self.event_log = [] Machine.__init__( self, @@ -60,9 +61,22 @@ class FSMBase(Machine, CallbackMixin): if all(predicate_results): try: + from_state = self.state self.trigger(trigger) - self.trigger_history.append(trigger) + self.update_event_log(from_state, trigger) return True except (AttributeError, MachineError): LOG.debug('FSM failed to execute nonexistent trigger: "%s"', trigger) return False + + def update_event_log(self, from_state, trigger): + self.event_log.append({ + 'from_state': from_state, + 'to_state': self.state, + 'trigger': trigger, + 'timestamp': datetime.utcnow() + }) + + @property + def in_accepted_state(self): + return self.state in self.accepted_states