mirror of
https://github.com/lowobservable/oec.git
synced 2026-02-27 09:09:56 +00:00
Use selectors instead of select
This commit is contained in:
@@ -5,7 +5,7 @@ oec.controller
|
||||
|
||||
import time
|
||||
import logging
|
||||
from select import select
|
||||
import selectors
|
||||
from coax import poll, poll_ack, load_control_register, get_features, PollAction, \
|
||||
KeystrokePollResponse, TerminalType, ReceiveTimeout, \
|
||||
ReceiveError, ProtocolError
|
||||
@@ -29,6 +29,8 @@ class Controller:
|
||||
self.terminal = None
|
||||
self.session = None
|
||||
|
||||
self.session_selector = None
|
||||
|
||||
# Target time between POLL commands in seconds when a terminal is connected or
|
||||
# no terminal is connected.
|
||||
#
|
||||
@@ -45,11 +47,17 @@ class Controller:
|
||||
"""Run the controller."""
|
||||
self.running = True
|
||||
|
||||
self.session_selector = selectors.DefaultSelector()
|
||||
|
||||
while self.running:
|
||||
self._run_loop()
|
||||
|
||||
self._terminate_session()
|
||||
|
||||
self.session_selector.close()
|
||||
|
||||
self.session_selector = None
|
||||
|
||||
if self.terminal:
|
||||
self.terminal = None
|
||||
|
||||
@@ -139,7 +147,7 @@ class Controller:
|
||||
def _handle_session_disconnected(self):
|
||||
self.logger.info('Session disconnected')
|
||||
|
||||
self.session = None
|
||||
self._terminate_session()
|
||||
|
||||
# Restart the session.
|
||||
self._start_session()
|
||||
@@ -149,10 +157,14 @@ class Controller:
|
||||
|
||||
self.session.start()
|
||||
|
||||
self.session_selector.register(self.session, selectors.EVENT_READ)
|
||||
|
||||
def _terminate_session(self):
|
||||
if not self.session:
|
||||
return
|
||||
|
||||
self.session_selector.unregister(self.session)
|
||||
|
||||
self.session.terminate()
|
||||
|
||||
self.session = None
|
||||
@@ -161,10 +173,15 @@ class Controller:
|
||||
while duration > 0:
|
||||
start_time = time.perf_counter()
|
||||
|
||||
if self.session not in select([self.session], [], [], duration)[0]:
|
||||
selected = self.session_selector.select(duration)
|
||||
|
||||
if not selected:
|
||||
break
|
||||
|
||||
self.session.handle_host()
|
||||
for (key, events) in selected:
|
||||
session = key.fileobj
|
||||
|
||||
session.handle_host()
|
||||
|
||||
duration -= (time.perf_counter() - start_time)
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ ptyprocess==0.7.0
|
||||
pycoax==0.6.0
|
||||
pyserial==3.5
|
||||
pyte==0.8.0
|
||||
pytn3270==0.9.0
|
||||
pytn3270==0.9.1
|
||||
sliplib==0.6.2
|
||||
sortedcontainers==2.3.0
|
||||
wcwidth==0.2.5
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import selectors
|
||||
import unittest
|
||||
from unittest.mock import Mock, PropertyMock, patch
|
||||
from coax import PollAction, PowerOnResetCompletePollResponse, KeystrokePollResponse, ReceiveTimeout
|
||||
@@ -26,6 +27,8 @@ class RunLoopTestCase(unittest.TestCase):
|
||||
|
||||
self.controller.connected_poll_period = 1
|
||||
|
||||
self.controller.session_selector = Mock()
|
||||
|
||||
self.controller._update_session = Mock()
|
||||
|
||||
patcher = patch('oec.controller.poll')
|
||||
@@ -257,14 +260,12 @@ class UpdateSessionTestCase(unittest.TestCase):
|
||||
|
||||
self.controller.session = Mock()
|
||||
|
||||
self.controller.session_selector = Mock()
|
||||
|
||||
patcher = patch('oec.controller.time.perf_counter')
|
||||
|
||||
self.perf_counter_mock = patcher.start()
|
||||
|
||||
patcher = patch('oec.controller.select')
|
||||
|
||||
self.select_mock = patcher.start()
|
||||
|
||||
def test_zero_duration(self):
|
||||
# Act
|
||||
self.controller._update_session(0)
|
||||
@@ -272,11 +273,11 @@ class UpdateSessionTestCase(unittest.TestCase):
|
||||
# Assert
|
||||
self.controller.session.handle_host.assert_not_called()
|
||||
|
||||
self.select_mock.assert_not_called()
|
||||
self.controller.session_selector.select.assert_not_called()
|
||||
|
||||
def test_select_timeout(self):
|
||||
# Arrange
|
||||
self.select_mock.return_value = ([], [], [])
|
||||
self.controller.session_selector.select.return_value = []
|
||||
|
||||
# Act
|
||||
self.controller._update_session(1)
|
||||
@@ -284,13 +285,15 @@ class UpdateSessionTestCase(unittest.TestCase):
|
||||
# Assert
|
||||
self.controller.session.handle_host.assert_not_called()
|
||||
|
||||
self.select_mock.assert_called_once()
|
||||
self.controller.session_selector.select.assert_called_once()
|
||||
|
||||
def test_select_available(self):
|
||||
# Arrange
|
||||
self.perf_counter_mock.side_effect = [0, 0.75, 0.75]
|
||||
|
||||
self.select_mock.side_effect = [([self.controller.session], [], []), ([], [], [])]
|
||||
selector_key = Mock(fileobj=self.controller.session)
|
||||
|
||||
self.controller.session_selector.select.side_effect = [[(selector_key, selectors.EVENT_READ)], []]
|
||||
|
||||
# Act
|
||||
self.controller._update_session(1)
|
||||
@@ -298,7 +301,9 @@ class UpdateSessionTestCase(unittest.TestCase):
|
||||
# Assert
|
||||
self.controller.session.handle_host.assert_called_once()
|
||||
|
||||
self.assertEqual(self.select_mock.call_count, 2)
|
||||
self.assertEqual(self.controller.session_selector.select.call_count, 2)
|
||||
|
||||
self.assertEqual(self.select_mock.call_args_list[0][0][3], 1)
|
||||
self.assertEqual(self.select_mock.call_args_list[1][0][3], 0.25)
|
||||
call_args_list = self.controller.session_selector.select.call_args_list
|
||||
|
||||
self.assertEqual(call_args_list[0][0][0], 1)
|
||||
self.assertEqual(call_args_list[1][0][0], 0.25)
|
||||
|
||||
Reference in New Issue
Block a user