From 0f379891e35c8a4c2db964dce16cdad58b9ba602 Mon Sep 17 00:00:00 2001 From: "R. Richard" Date: Fri, 23 Aug 2019 16:15:27 +0200 Subject: [PATCH] Move message queue logic to backend --- tfw/components/frontend/__init__.py | 3 +- .../frontend/frontend_proxy_handler.py | 2 +- .../message_queue_handler/__init__.py | 1 + .../message_queue_handler.py | 50 ++++++++++++++ .../test_message_queue.py | 67 +++++++++++++++++++ tfw/components/frontend/message_sender.py | 8 --- tfw/components/frontend/message_storage.py | 4 -- 7 files changed, 121 insertions(+), 14 deletions(-) create mode 100644 tfw/components/frontend/message_queue_handler/__init__.py create mode 100644 tfw/components/frontend/message_queue_handler/message_queue_handler.py create mode 100644 tfw/components/frontend/message_queue_handler/test_message_queue.py diff --git a/tfw/components/frontend/__init__.py b/tfw/components/frontend/__init__.py index 2300690..3dab104 100644 --- a/tfw/components/frontend/__init__.py +++ b/tfw/components/frontend/__init__.py @@ -1,3 +1,4 @@ -from .frontend_proxy_handler import FrontendProxyHandler from .console_logs_handler import ConsoleLogsHandler +from .frontend_proxy_handler import FrontendProxyHandler +from .message_queue_handler import MessageQueueHandler from .message_sender import MessageSender diff --git a/tfw/components/frontend/frontend_proxy_handler.py b/tfw/components/frontend/frontend_proxy_handler.py index a46f015..e7c7b06 100644 --- a/tfw/components/frontend/frontend_proxy_handler.py +++ b/tfw/components/frontend/frontend_proxy_handler.py @@ -22,7 +22,7 @@ class FrontendProxyHandler: @staticmethod def _filter_message(message): - return not message['key'].startswith('ide') + return not message['key'].startswith(('ide', 'message.queue')) def recover_frontend(self): for message in self._frontend_message_storage.messages: diff --git a/tfw/components/frontend/message_queue_handler/__init__.py b/tfw/components/frontend/message_queue_handler/__init__.py new file mode 100644 index 0000000..0eb2a68 --- /dev/null +++ b/tfw/components/frontend/message_queue_handler/__init__.py @@ -0,0 +1 @@ +from .message_queue_handler import MessageQueueHandler diff --git a/tfw/components/frontend/message_queue_handler/message_queue_handler.py b/tfw/components/frontend/message_queue_handler/message_queue_handler.py new file mode 100644 index 0000000..80493b2 --- /dev/null +++ b/tfw/components/frontend/message_queue_handler/message_queue_handler.py @@ -0,0 +1,50 @@ +from time import sleep +from queue import Queue +from threading import Thread + + +class MessageQueueHandler: + keys = ['message.queue'] + + def __init__(self, wpm): + self.connector = None + self._wpm, self._cps = None, None + self.wpm = wpm + self._queue = Queue() + self._thread = Thread(target=self.dispatch_messages) + + @property + def wpm(self): + return self._wpm + + @wpm.setter + def wpm(self, wpm): + self._wpm = wpm + self._cps = 5*wpm/60 + + def dispatch_messages(self): + for message in iter(self._queue.get, None): + sleep(len(message['message'])/self._cps) + self.connector.send_message(message) + + def handle_event(self, message, _): + for unpacked in self.generate_messages_from_queue(message): + self._queue.put(unpacked) + + @staticmethod + def generate_messages_from_queue(queue_message): + last = queue_message['value'][-1] + for message in queue_message['value']: + yield { + 'key': 'message.send', + 'typing': message is not last, + **message + } + + def start(self): + self._thread.start() + + def cleanup(self): + self._queue.queue.clear() + self._queue.put(None) + self._thread.join() diff --git a/tfw/components/frontend/message_queue_handler/test_message_queue.py b/tfw/components/frontend/message_queue_handler/test_message_queue.py new file mode 100644 index 0000000..ae09b24 --- /dev/null +++ b/tfw/components/frontend/message_queue_handler/test_message_queue.py @@ -0,0 +1,67 @@ +# pylint: disable=redefined-outer-name +from math import inf +from time import sleep +from os import urandom +from random import randint + +import pytest + +from .message_queue_handler import MessageQueueHandler + + +class MockConnector: + def __init__(self): + self.callback = None + self.messages = [] + + def raise_event(self, message): + self.callback(message, self) + sleep(0.01) + + def send_message(self, message): + self.messages.append(message) + + +@pytest.fixture +def handler(): + connector = MockConnector() + handler = MessageQueueHandler(inf) + handler.connector = connector + connector.callback = handler.handle_event + handler.start() + yield handler + handler.cleanup() + + +@pytest.fixture +def queue(): + yield { + 'key': 'message.queue', + 'value': [ + {'originator': urandom(4).hex(), 'message': urandom(16).hex()} + for _ in range(randint(5, 10)) + ] + } + + +def test_message_order(handler, queue): + handler.connector.raise_event(queue) + old_list = queue['value'] + new_list = handler.connector.messages + length = len(old_list) + assert len(new_list) == length + for i in range(length): + unpacked = new_list[i] + assert unpacked['key'] == 'message.send' + assert unpacked['originator'] == old_list[i]['originator'] + assert unpacked['typing'] == (i < length-1) + + +def test_wpm(handler, queue): + handler.wpm = 10000 + handler.connector.raise_event(queue) + assert not handler.connector.messages + handler.wpm = 100000000 + handler.connector.raise_event(queue) + sleep(0.25) + assert len(handler.connector.messages) == 2*len(queue['value']) diff --git a/tfw/components/frontend/message_sender.py b/tfw/components/frontend/message_sender.py index 93826df..0f4f249 100644 --- a/tfw/components/frontend/message_sender.py +++ b/tfw/components/frontend/message_sender.py @@ -28,11 +28,3 @@ class MessageSender: 'key': 'message.config', 'originator': originator }) - - @staticmethod - def generate_messages_from_queue(queue_message): - for message in queue_message['value']: - yield { - 'key': 'message.send', - **message - } diff --git a/tfw/components/frontend/message_storage.py b/tfw/components/frontend/message_storage.py index 78bba26..b9ea946 100644 --- a/tfw/components/frontend/message_storage.py +++ b/tfw/components/frontend/message_storage.py @@ -1,8 +1,6 @@ from abc import ABC, abstractmethod from contextlib import suppress -from .message_sender import MessageSender - class MessageStorage(ABC): def __init__(self): @@ -36,13 +34,11 @@ class FrontendMessageStorage(MessageStorage): 'dashboard.terminalMenuItem', 'message.config', 'message.send', - 'message.queue', 'ide.read' )) def _transform_message(self, message): transformations = { - 'message.queue': MessageSender.generate_messages_from_queue, 'ide.read': self._delete_ide_content } if message['key'] in transformations: