mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-14 17:22:56 -07:00
Bump websocket-client from 1.3.2 to 1.4.2 (#1886)
* Bump websocket-client from 1.3.2 to 1.4.2 Bumps [websocket-client](https://github.com/websocket-client/websocket-client) from 1.3.2 to 1.4.2. - [Release notes](https://github.com/websocket-client/websocket-client/releases) - [Changelog](https://github.com/websocket-client/websocket-client/blob/master/ChangeLog) - [Commits](https://github.com/websocket-client/websocket-client/compare/v1.3.2...v1.4.2) --- updated-dependencies: - dependency-name: websocket-client dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * Update websocket-client==1.4.2 Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: JonnyWong16 <9099342+JonnyWong16@users.noreply.github.com> [skip ci]
This commit is contained in:
parent
a5ccc9a1a3
commit
3af08f0d07
10 changed files with 177 additions and 101 deletions
|
@ -1,9 +1,11 @@
|
|||
import inspect
|
||||
import selectors
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
import traceback
|
||||
from ._abnf import ABNF
|
||||
from ._url import parse_url
|
||||
from ._core import WebSocket, getdefaulttimeout
|
||||
from ._exceptions import *
|
||||
from . import _logging
|
||||
|
@ -29,15 +31,40 @@ limitations under the License.
|
|||
|
||||
__all__ = ["WebSocketApp"]
|
||||
|
||||
RECONNECT = 0
|
||||
|
||||
class Dispatcher:
|
||||
|
||||
def setReconnect(reconnectInterval):
|
||||
global RECONNECT
|
||||
RECONNECT = reconnectInterval
|
||||
|
||||
|
||||
class DispatcherBase:
|
||||
"""
|
||||
Dispatcher
|
||||
DispatcherBase
|
||||
"""
|
||||
def __init__(self, app, ping_timeout):
|
||||
self.app = app
|
||||
self.ping_timeout = ping_timeout
|
||||
|
||||
def timeout(self, seconds, callback):
|
||||
time.sleep(seconds)
|
||||
callback()
|
||||
|
||||
def reconnect(self, seconds, reconnector):
|
||||
try:
|
||||
while True:
|
||||
_logging.info("reconnect() - retrying in %s seconds [%s frames in stack]" % (seconds, len(inspect.stack())))
|
||||
time.sleep(seconds)
|
||||
reconnector(reconnecting=True)
|
||||
except KeyboardInterrupt as e:
|
||||
_logging.info("User exited %s" % (e,))
|
||||
|
||||
|
||||
class Dispatcher(DispatcherBase):
|
||||
"""
|
||||
Dispatcher
|
||||
"""
|
||||
def read(self, sock, read_callback, check_callback):
|
||||
while self.app.keep_running:
|
||||
sel = selectors.DefaultSelector()
|
||||
|
@ -51,14 +78,10 @@ class Dispatcher:
|
|||
sel.close()
|
||||
|
||||
|
||||
class SSLDispatcher:
|
||||
class SSLDispatcher(DispatcherBase):
|
||||
"""
|
||||
SSLDispatcher
|
||||
"""
|
||||
def __init__(self, app, ping_timeout):
|
||||
self.app = app
|
||||
self.ping_timeout = ping_timeout
|
||||
|
||||
def read(self, sock, read_callback, check_callback):
|
||||
while self.app.keep_running:
|
||||
r = self.select()
|
||||
|
@ -90,10 +113,17 @@ class WrappedDispatcher:
|
|||
self.app = app
|
||||
self.ping_timeout = ping_timeout
|
||||
self.dispatcher = dispatcher
|
||||
dispatcher.signal(2, dispatcher.abort) # keyboard interrupt
|
||||
|
||||
def read(self, sock, read_callback, check_callback):
|
||||
self.dispatcher.read(sock, read_callback)
|
||||
self.ping_timeout and self.dispatcher.timeout(self.ping_timeout, check_callback)
|
||||
self.ping_timeout and self.timeout(self.ping_timeout, check_callback)
|
||||
|
||||
def timeout(self, seconds, callback):
|
||||
self.dispatcher.timeout(seconds, callback)
|
||||
|
||||
def reconnect(self, seconds, reconnector):
|
||||
self.timeout(seconds, reconnector)
|
||||
|
||||
|
||||
class WebSocketApp:
|
||||
|
@ -186,6 +216,7 @@ class WebSocketApp:
|
|||
self.last_pong_tm = 0
|
||||
self.subprotocols = subprotocols
|
||||
self.prepared_socket = socket
|
||||
self.has_errored = False
|
||||
|
||||
def send(self, data, opcode=ABNF.OPCODE_TEXT):
|
||||
"""
|
||||
|
@ -228,9 +259,10 @@ class WebSocketApp:
|
|||
ping_payload="",
|
||||
http_proxy_host=None, http_proxy_port=None,
|
||||
http_no_proxy=None, http_proxy_auth=None,
|
||||
http_proxy_timeout=None,
|
||||
skip_utf8_validation=False,
|
||||
host=None, origin=None, dispatcher=None,
|
||||
suppress_origin=False, proxy_type=None):
|
||||
suppress_origin=False, proxy_type=None, reconnect=None):
|
||||
"""
|
||||
Run event loop for WebSocket framework.
|
||||
|
||||
|
@ -258,6 +290,10 @@ class WebSocketApp:
|
|||
HTTP proxy port. If not set, set to 80.
|
||||
http_no_proxy: list
|
||||
Whitelisted host names that don't use the proxy.
|
||||
http_proxy_timeout: int or float
|
||||
HTTP proxy timeout, default is 60 sec as per python-socks.
|
||||
http_proxy_auth: tuple
|
||||
HTTP proxy auth information. tuple of username and password. Default is None.
|
||||
skip_utf8_validation: bool
|
||||
skip utf8 validation.
|
||||
host: str
|
||||
|
@ -268,6 +304,10 @@ class WebSocketApp:
|
|||
customize reading data from socket.
|
||||
suppress_origin: bool
|
||||
suppress outputting origin header.
|
||||
proxy_type: str
|
||||
type of proxy from: http, socks4, socks4a, socks5, socks5h
|
||||
reconnect: int
|
||||
delay interval when reconnecting
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
@ -276,6 +316,9 @@ class WebSocketApp:
|
|||
True if any other exception was raised during a loop.
|
||||
"""
|
||||
|
||||
if reconnect is None:
|
||||
reconnect = RECONNECT
|
||||
|
||||
if ping_timeout is not None and ping_timeout <= 0:
|
||||
raise WebSocketException("Ensure ping_timeout > 0")
|
||||
if ping_interval is not None and ping_interval < 0:
|
||||
|
@ -317,84 +360,105 @@ class WebSocketApp:
|
|||
# Finally call the callback AFTER all teardown is complete
|
||||
self._callback(self.on_close, close_status_code, close_reason)
|
||||
|
||||
try:
|
||||
def setSock(reconnecting=False):
|
||||
self.sock = WebSocket(
|
||||
self.get_mask_key, sockopt=sockopt, sslopt=sslopt,
|
||||
fire_cont_frame=self.on_cont_message is not None,
|
||||
skip_utf8_validation=skip_utf8_validation,
|
||||
enable_multithread=True)
|
||||
self.sock.settimeout(getdefaulttimeout())
|
||||
self.sock.connect(
|
||||
self.url, header=self.header, cookie=self.cookie,
|
||||
http_proxy_host=http_proxy_host,
|
||||
http_proxy_port=http_proxy_port, http_no_proxy=http_no_proxy,
|
||||
http_proxy_auth=http_proxy_auth, subprotocols=self.subprotocols,
|
||||
host=host, origin=origin, suppress_origin=suppress_origin,
|
||||
proxy_type=proxy_type, socket=self.prepared_socket)
|
||||
dispatcher = self.create_dispatcher(ping_timeout, dispatcher)
|
||||
try:
|
||||
self.sock.connect(
|
||||
self.url, header=self.header, cookie=self.cookie,
|
||||
http_proxy_host=http_proxy_host,
|
||||
http_proxy_port=http_proxy_port, http_no_proxy=http_no_proxy,
|
||||
http_proxy_auth=http_proxy_auth, http_proxy_timeout=http_proxy_timeout,
|
||||
subprotocols=self.subprotocols,
|
||||
host=host, origin=origin, suppress_origin=suppress_origin,
|
||||
proxy_type=proxy_type, socket=self.prepared_socket)
|
||||
|
||||
self._callback(self.on_open)
|
||||
self._callback(self.on_open)
|
||||
|
||||
if ping_interval:
|
||||
event = threading.Event()
|
||||
thread = threading.Thread(
|
||||
target=self._send_ping, args=(ping_interval, event, ping_payload))
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
_logging.warning("websocket connected")
|
||||
dispatcher.read(self.sock.sock, read, check)
|
||||
except (WebSocketConnectionClosedException, ConnectionRefusedError, KeyboardInterrupt, SystemExit, Exception) as e:
|
||||
_logging.error("%s - %s" % (e, reconnect and "reconnecting" or "goodbye"))
|
||||
reconnecting or handleDisconnect(e)
|
||||
|
||||
def read():
|
||||
if not self.keep_running:
|
||||
return teardown()
|
||||
def read():
|
||||
if not self.keep_running:
|
||||
return teardown()
|
||||
|
||||
try:
|
||||
op_code, frame = self.sock.recv_data_frame(True)
|
||||
if op_code == ABNF.OPCODE_CLOSE:
|
||||
return teardown(frame)
|
||||
elif op_code == ABNF.OPCODE_PING:
|
||||
self._callback(self.on_ping, frame.data)
|
||||
elif op_code == ABNF.OPCODE_PONG:
|
||||
self.last_pong_tm = time.time()
|
||||
self._callback(self.on_pong, frame.data)
|
||||
elif op_code == ABNF.OPCODE_CONT and self.on_cont_message:
|
||||
self._callback(self.on_data, frame.data,
|
||||
frame.opcode, frame.fin)
|
||||
self._callback(self.on_cont_message,
|
||||
frame.data, frame.fin)
|
||||
except (WebSocketConnectionClosedException, KeyboardInterrupt) as e:
|
||||
if custom_dispatcher:
|
||||
return handleDisconnect(e)
|
||||
else:
|
||||
data = frame.data
|
||||
if op_code == ABNF.OPCODE_TEXT:
|
||||
data = data.decode("utf-8")
|
||||
self._callback(self.on_data, data, frame.opcode, True)
|
||||
self._callback(self.on_message, data)
|
||||
raise e
|
||||
if op_code == ABNF.OPCODE_CLOSE:
|
||||
return teardown(frame)
|
||||
elif op_code == ABNF.OPCODE_PING:
|
||||
self._callback(self.on_ping, frame.data)
|
||||
elif op_code == ABNF.OPCODE_PONG:
|
||||
self.last_pong_tm = time.time()
|
||||
self._callback(self.on_pong, frame.data)
|
||||
elif op_code == ABNF.OPCODE_CONT and self.on_cont_message:
|
||||
self._callback(self.on_data, frame.data,
|
||||
frame.opcode, frame.fin)
|
||||
self._callback(self.on_cont_message,
|
||||
frame.data, frame.fin)
|
||||
else:
|
||||
data = frame.data
|
||||
if op_code == ABNF.OPCODE_TEXT:
|
||||
data = data.decode("utf-8")
|
||||
self._callback(self.on_data, data, frame.opcode, True)
|
||||
self._callback(self.on_message, data)
|
||||
|
||||
return True
|
||||
return True
|
||||
|
||||
def check():
|
||||
if (ping_timeout):
|
||||
has_timeout_expired = time.time() - self.last_ping_tm > ping_timeout
|
||||
has_pong_not_arrived_after_last_ping = self.last_pong_tm - self.last_ping_tm < 0
|
||||
has_pong_arrived_too_late = self.last_pong_tm - self.last_ping_tm > ping_timeout
|
||||
def check():
|
||||
if (ping_timeout):
|
||||
has_timeout_expired = time.time() - self.last_ping_tm > ping_timeout
|
||||
has_pong_not_arrived_after_last_ping = self.last_pong_tm - self.last_ping_tm < 0
|
||||
has_pong_arrived_too_late = self.last_pong_tm - self.last_ping_tm > ping_timeout
|
||||
|
||||
if (self.last_ping_tm and
|
||||
has_timeout_expired and
|
||||
(has_pong_not_arrived_after_last_ping or has_pong_arrived_too_late)):
|
||||
raise WebSocketTimeoutException("ping/pong timed out")
|
||||
return True
|
||||
if (self.last_ping_tm and
|
||||
has_timeout_expired and
|
||||
(has_pong_not_arrived_after_last_ping or has_pong_arrived_too_late)):
|
||||
raise WebSocketTimeoutException("ping/pong timed out")
|
||||
return True
|
||||
|
||||
dispatcher.read(self.sock.sock, read, check)
|
||||
return False
|
||||
except (Exception, KeyboardInterrupt, SystemExit) as e:
|
||||
def handleDisconnect(e):
|
||||
self.has_errored = True
|
||||
self._callback(self.on_error, e)
|
||||
if isinstance(e, SystemExit):
|
||||
# propagate SystemExit further
|
||||
raise
|
||||
teardown()
|
||||
return not isinstance(e, KeyboardInterrupt)
|
||||
if reconnect and not isinstance(e, KeyboardInterrupt):
|
||||
_logging.info("websocket disconnected (retrying in %s seconds) [%s frames in stack]" % (reconnect, len(inspect.stack())))
|
||||
dispatcher.reconnect(reconnect, setSock)
|
||||
else:
|
||||
teardown()
|
||||
|
||||
def create_dispatcher(self, ping_timeout, dispatcher=None):
|
||||
custom_dispatcher = bool(dispatcher)
|
||||
dispatcher = self.create_dispatcher(ping_timeout, dispatcher, parse_url(self.url)[3])
|
||||
|
||||
if ping_interval:
|
||||
event = threading.Event()
|
||||
thread = threading.Thread(
|
||||
target=self._send_ping, args=(ping_interval, event, ping_payload))
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
|
||||
setSock()
|
||||
return self.has_errored
|
||||
|
||||
def create_dispatcher(self, ping_timeout, dispatcher=None, is_ssl=False):
|
||||
if dispatcher: # If custom dispatcher is set, use WrappedDispatcher
|
||||
return WrappedDispatcher(self, ping_timeout, dispatcher)
|
||||
timeout = ping_timeout or 10
|
||||
if self.sock.is_ssl():
|
||||
if is_ssl:
|
||||
return SSLDispatcher(self, timeout)
|
||||
|
||||
return Dispatcher(self, timeout)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue