Skip to content

Commit 3c3cc34

Browse files
cspencer404auvipy
andauthored
Non-blocking read option on socket (#278)
* Adds sock_timeout property to WebSocket to allow non-blocking reads Also adds test: test_run for WebSocket.py * Update ws4py/websocket.py Signed-off-by: Asif Saif Uddin <[email protected]> * Update test/test_websocket.py Signed-off-by: Asif Saif Uddin <[email protected]> --------- Signed-off-by: Asif Saif Uddin <[email protected]> Co-authored-by: Asif Saif Uddin <[email protected]>
1 parent b833d0d commit 3c3cc34

File tree

2 files changed

+38
-3
lines changed

2 files changed

+38
-3
lines changed

test/test_websocket.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,28 @@ def test_sending_ping(self):
181181
m.sendall.assert_called_once_with(tm)
182182

183183

184+
@patch("ws4py.websocket.Heartbeat")
185+
def test_run(self, mocker):
186+
mocked_sock = MagicMock()
187+
mocked_opened = MagicMock()
188+
mocked_once = MagicMock(return_value=False) # False to break the loop
189+
mocked_terminate = MagicMock()
190+
191+
ws = WebSocket(sock=mocked_sock)
192+
assert ws.sock_timeout is None
193+
194+
with patch.multiple(ws,
195+
opened=mocked_opened,
196+
once=mocked_once,
197+
terminate=mocked_terminate,
198+
stream=MagicMock(),
199+
):
200+
ws.run()
201+
mocked_sock.settimeout.assert_called_with(None)
202+
mocked_opened.assert_called()
203+
mocked_once.assert_called()
204+
mocked_terminate.assert_called()
205+
184206
if __name__ == '__main__':
185207
suite = unittest.TestSuite()
186208
loader = unittest.TestLoader()

ws4py/websocket.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,17 @@ def __init__(self, sock, protocols=None, extensions=None, environ=None, heartbea
141141
"Internal buffer to get around SSL problems"
142142
self.buf = b''
143143

144+
self.sock_timeout = None
145+
"""
146+
Used to set socket.settimeout(value):
147+
From: https://docs.python.org/3.11/library/socket.html#socket.socket.settimeout
148+
The value argument can be a nonnegative floating point number expressing seconds, or None.
149+
If a non-zero value is given, subsequent socket operations will raise a timeout exception
150+
if the timeout period value has elapsed before the operation has completed.
151+
If zero is given, the socket is put in non-blocking mode.
152+
If None is given, the socket is put in blocking mode.
153+
"""
154+
144155
self._local_address = None
145156
self._peer_address = None
146157

@@ -515,10 +526,12 @@ def run(self):
515526
we initiate the closing of the connection with the
516527
appropiate error code.
517528
518-
This method is blocking and should likely be run
519-
in a thread.
529+
The self.sock_timeout determines whether this method
530+
is blocking, or can timeout on reads. If a timeout
531+
occurs, the unhandled_error function will be called
532+
It should likely be run in a thread.
520533
"""
521-
self.sock.setblocking(True)
534+
self.sock.settimeout(self.sock_timeout)
522535
with Heartbeat(self, frequency=self.heartbeat_freq):
523536
s = self.stream
524537

0 commit comments

Comments
 (0)