Rework fsm_update API

This commit is contained in:
Kristóf Tóth 2018-07-24 17:16:57 +02:00
parent d718b6425e
commit a6b7fa04ab
3 changed files with 33 additions and 17 deletions

View File

@ -25,7 +25,7 @@ class FSMManagingEventHandler(EventHandlerBase):
try: try:
message = self.command_handlers[message['data']['command']](message) message = self.command_handlers[message['data']['command']](message)
if 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, message)
sign_message(self.auth_key, fsm_update_message) sign_message(self.auth_key, fsm_update_message)
self.server_connector.broadcast(fsm_update_message) self.server_connector.broadcast(fsm_update_message)
@ -52,23 +52,24 @@ class FSMUpdater:
def __init__(self, fsm): def __init__(self, fsm):
self.fsm = fsm self.fsm = fsm
def generate_fsm_update(self): @property
def fsm_update(self):
return { return {
'key': 'fsm_update', 'key': 'fsm_update',
'data': self.get_fsm_state_and_transitions() 'data': self.fsm_update_data
} }
def get_fsm_state_and_transitions(self): @property
state = self.fsm.state def fsm_update_data(self):
valid_transitions = [ valid_transitions = [
{'trigger': trigger} {'trigger': trigger}
for trigger in self.fsm.get_triggers(self.fsm.state) for trigger in self.fsm.get_triggers(self.fsm.state)
] ]
last_trigger = self.fsm.trigger_history[-1] if self.fsm.trigger_history else None last_fsm_event = self.fsm.event_log[-1]
in_accepted_state = state in self.fsm.accepted_states last_fsm_event['timestamp'] = last_fsm_event['timestamp'].isoformat()
return { return {
'current_state': state, 'current_state': self.fsm.state,
'valid_transitions': valid_transitions, 'valid_transitions': valid_transitions,
'last_trigger': last_trigger, 'in_accepted_state': self.fsm.in_accepted_state,
'in_accepted_state': in_accepted_state 'last_event': last_fsm_event
} }

View File

@ -109,7 +109,7 @@ class EventHandlerBase(ABC):
class FSMAware: class FSMAware:
def __init__(self): def __init__(self):
self.fsm_state = None self.fsm_state = None
self.in_accepted_state = False self.fsm_in_accepted_state = False
self._auth_key = KeyManager().auth_key self._auth_key = KeyManager().auth_key
def update_fsm_data(self, message): def update_fsm_data(self, message):
@ -121,17 +121,18 @@ class FSMAware:
def _handle_fsm_update(self, message): def _handle_fsm_update(self, message):
try: try:
new_state = message['data']['current_state'] new_state = message['data']['current_state']
trigger = message['data']['last_trigger']
if self.fsm_state != new_state: 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.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: except KeyError:
LOG.error('Invalid fsm_update message received!') 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. Called in case the TFW FSM has stepped.
:param kwargs: fsm_update 'data' field
""" """
pass pass

View File

@ -2,6 +2,7 @@
# All Rights Reserved. See LICENSE file for details. # All Rights Reserved. See LICENSE file for details.
from collections import defaultdict from collections import defaultdict
from datetime import datetime
from transitions import Machine, MachineError from transitions import Machine, MachineError
@ -24,7 +25,7 @@ class FSMBase(Machine, CallbackMixin):
def __init__(self, initial=None, accepted_states=None): def __init__(self, initial=None, accepted_states=None):
self.accepted_states = accepted_states or [self.states[-1].name] self.accepted_states = accepted_states or [self.states[-1].name]
self.trigger_predicates = defaultdict(list) self.trigger_predicates = defaultdict(list)
self.trigger_history = [] self.event_log = []
Machine.__init__( Machine.__init__(
self, self,
@ -60,9 +61,22 @@ class FSMBase(Machine, CallbackMixin):
if all(predicate_results): if all(predicate_results):
try: try:
from_state = self.state
self.trigger(trigger) self.trigger(trigger)
self.trigger_history.append(trigger) self.update_event_log(from_state, trigger)
return True return True
except (AttributeError, MachineError): except (AttributeError, MachineError):
LOG.debug('FSM failed to execute nonexistent trigger: "%s"', trigger) LOG.debug('FSM failed to execute nonexistent trigger: "%s"', trigger)
return False 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