# Copyright (C) 2018 Avatao.com Innovative Learning Kft. # All Rights Reserved. See LICENSE file for details. from tfw import EventHandlerBase from tfw.crypto import KeyManager, sign_message, verify_message from tfw.config.logs import logging LOG = logging.getLogger(__name__) class FSMManagingEventHandler(EventHandlerBase): def __init__(self, key, fsm_type, require_signature=False): super().__init__(key) self.fsm = fsm_type() self._fsm_updater = FSMUpdater(self.fsm) self.auth_key = KeyManager().auth_key self._require_signature = require_signature self.command_handlers = { 'trigger': self.handle_trigger, 'update': self.handle_update } def handle_event(self, message): try: message = self.command_handlers[message['data']['command']](message) if message: 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) return message except KeyError: LOG.error('IGNORING MESSAGE: Invalid message received: %s', message) def handle_trigger(self, message): trigger = message['data']['value'] if self._require_signature: if not verify_message(self.auth_key, message): LOG.error('Ignoring unsigned trigger command: %s', message) return None if self.fsm.step(trigger): return message return None def handle_update(self, message): # pylint: disable=no-self-use return message class FSMUpdater: def __init__(self, fsm): self.fsm = fsm @property def fsm_update(self): return { 'key': 'fsm_update', 'data': self.fsm_update_data } @property def fsm_update_data(self): valid_transitions = [ {'trigger': trigger} for trigger in self.fsm.get_triggers(self.fsm.state) ] last_fsm_event = self.fsm.event_log[-1] last_fsm_event['timestamp'] = last_fsm_event['timestamp'].isoformat() return { 'current_state': self.fsm.state, 'valid_transitions': valid_transitions, 'in_accepted_state': self.fsm.in_accepted_state, 'last_event': last_fsm_event }