class FlaskHttpListenerClient(ListenerClient): """Flask client to receive messages from customer app.""" def __init__(self, config: dict): # pragma: no cover """ Use a flask server as the listener. Configuration keys: PORT HOST """ self.port = int(config['PORT']) if 'PORT' in config else None self.host = config.get('HOST', DEFAULT_HOST) self.on_message_received = None self.t_flask = None self.logger = Logger() def run_flask_server(self): # pragma: no cover """Run the flask server.""" app = Flask(__name__) @app.route("/", methods=["POST"]) def on_input(): # pylint: disable=unused-variable msg = str(request.data, 'utf-8', 'ignore') if self.on_message_received(msg): return 'msg: %s' % msg print( 'Error: The callback failed to process the message, returning 500' ) return 'Error: The callback failed to process the message', 500 app.run(host=self.host, port=self.port, debug=False, use_reloader=False, threaded=True) def start(self, on_message_received): # pragma: no cover self.on_message_received = on_message_received self.t_flask = threading.Thread(name='agogosml', target=self.run_flask_server) self.t_flask.setDaemon(True) self.logger.event('flask.server.start', { 'port': str(self.port), 'host': self.host }) self.t_flask.start() def stop(self): # pragma: no cover try: func = request.environ.get('werkzeug.server.shutdown') if func is None: raise RuntimeError('Not running with the Werkzeug Server') func() except Exception as ex: print('error while shutting down flask server: %s' % ex)
class OutputWriter: """OutputWriter class.""" def __init__(self, streaming_client: AbstractStreamingClient, listener: ListenerClient): """Accept incoming messages and route them to a configured output.""" self.messaging_client = streaming_client self.listener = listener self.logger = Logger() def on_message_received(self, message: str) -> bool: """Send messages onwards to a streaming client.""" success = self.messaging_client.send(message) self.logger.event('output.message.received', {'success': str(success)}) return success def start_incoming_messages(self, callback: Optional[Callable[[str], bool]] = None): """Start accepting messages.""" self.logger.event('output.lifecycle.start') self.listener.start(callback or self.on_message_received) def stop_incoming_messages(self): """Stop accepting messages.""" self.listener.stop() self.logger.event('output.lifecycle.stop')
class InputReader: """InputReader.""" def __init__(self, streaming_client: AbstractStreamingClient, message_sender: MessageSender): """Accept an incoming message and route them to a configured output.""" self.message_sender = message_sender self.messaging_client = streaming_client self.logger = Logger() def start_receiving_messages(self): """Start receiving messages from streaming endpoint.""" self.logger.event('input.lifecycle.start') self.messaging_client.start_receiving(self.on_message_received) def stop_incoming_messages(self): """Stop incoming messages from streaming endpoint.""" self.messaging_client.stop() self.logger.event('input.lifecycle.stop') def on_message_received(self, message: str) -> bool: """Send messages onwards.""" result = self.message_sender.send(message) if result: success = True else: success = False self.handle_send_failure(message) self.logger.event('input.message.received', {'success': str(success)}) return success def handle_send_failure(self, message: str): """Handle message send failure.""" self.logger.error('Error while sending message to App %s', message)