Fix compatibility with all versions of websocket-client, regardless of the list of arguments required by the callbacks (either ws as a first argument or not)

This commit is contained in:
Fabio Manganiello 2021-04-02 19:27:25 +02:00
parent 641d9c0d41
commit 99831bf0c7
6 changed files with 58 additions and 44 deletions

View file

@ -117,7 +117,8 @@ class MusicMopidyBackend(Backend):
} }
def _on_msg(self): def _on_msg(self):
def hndl(ws, msg): def hndl(*args):
msg = args[1] if len(args) > 1 else args[0]
msg = json.loads(msg) msg = json.loads(msg)
event = msg.get('event') event = msg.get('event')
if not event: if not event:
@ -213,14 +214,17 @@ class MusicMopidyBackend(Backend):
self._reconnect_thread.start() self._reconnect_thread.start()
def _on_error(self): def _on_error(self):
def hndl(ws, error): def hndl(*args):
error = args[1] if len(args) > 1 else args[0]
ws = args[0] if len(args) > 1 else None
self.logger.warning('Mopidy websocket error: {}'.format(error)) self.logger.warning('Mopidy websocket error: {}'.format(error))
if ws:
ws.close() ws.close()
return hndl return hndl
def _on_close(self): def _on_close(self):
def hndl(ws): def hndl(*_):
self._connected_event.clear() self._connected_event.clear()
self._ws = None self._ws = None
self.logger.warning('Mopidy websocket connection closed') self.logger.warning('Mopidy websocket connection closed')
@ -231,7 +235,7 @@ class MusicMopidyBackend(Backend):
return hndl return hndl
def _on_open(self): def _on_open(self):
def hndl(ws): def hndl(*_):
self._connected_event.set() self._connected_event.set()
self.logger.info('Mopidy websocket connected') self.logger.info('Mopidy websocket connected')

View file

@ -50,8 +50,8 @@ class TodoistBackend(Backend):
self._event_handled = False self._event_handled = False
def _on_msg(self): def _on_msg(self):
# noinspection PyUnusedLocal def hndl(*args):
def hndl(ws, msg): msg = args[1] if len(args) > 1 else args[0]
msg = json.loads(msg) msg = json.loads(msg)
if msg.get('type') == 'sync_needed': if msg.get('type') == 'sync_needed':
self._refresh_all() self._refresh_all()
@ -68,15 +68,15 @@ class TodoistBackend(Backend):
time.sleep(10) time.sleep(10)
def _on_error(self): def _on_error(self):
# noinspection PyUnusedLocal def hndl(*args):
def hndl(ws, error): error = args[1] if len(args) > 1 else args[0]
self.logger.warning('Todoist websocket error: {}'.format(error)) self.logger.warning('Todoist websocket error: {}'.format(error))
self._retry_hndl() self._retry_hndl()
return hndl return hndl
def _on_close(self): def _on_close(self):
def hndl(*_, **__): def hndl(*_):
self.logger.info('Todoist websocket closed') self.logger.info('Todoist websocket closed')
self._retry_hndl() self._retry_hndl()

View file

@ -57,7 +57,9 @@ class TrelloBackend(Backend):
for b in boards: for b in boards:
b = self._plugin.get_board(b).board b = self._plugin.get_board(b).board
# noinspection PyUnresolvedReferences
self._boards_by_id[b.id] = b self._boards_by_id[b.id] = b
# noinspection PyUnresolvedReferences
self._boards_by_name[b.name] = b self._boards_by_name[b.name] = b
self.url = self._websocket_url_base.format(token=self.token) self.url = self._websocket_url_base.format(token=self.token)
@ -79,8 +81,13 @@ class TrelloBackend(Backend):
self.logger.info('Trello boards subscribed') self.logger.info('Trello boards subscribed')
def _on_msg(self): def _on_msg(self):
# noinspection PyUnusedLocal def hndl(*args):
def hndl(ws: WebSocketApp, msg): if len(args) < 2:
self.logger.warning('Missing websocket argument - make sure that you are using '
'a version of websocket-client < 0.53.0 or >= 0.58.0')
return
ws, msg = args[:2]
if not msg: if not msg:
# Reply back with an empty message when the server sends an empty message # Reply back with an empty message when the server sends an empty message
ws.send('') ws.send('')
@ -89,8 +96,8 @@ class TrelloBackend(Backend):
# noinspection PyBroadException # noinspection PyBroadException
try: try:
msg = json.loads(msg) msg = json.loads(msg)
except: except Exception as e:
self.logger.warning('Received invalid JSON message from Trello: {}'.format(msg)) self.logger.warning('Received invalid JSON message from Trello: {}: {}'.format(msg, e))
return return
if 'error' in msg: if 'error' in msg:
@ -141,15 +148,14 @@ class TrelloBackend(Backend):
return hndl return hndl
def _on_error(self): def _on_error(self):
# noinspection PyUnusedLocal def hndl(*args):
def hndl(ws: WebSocketApp, error): error = args[1] if len(args) > 1 else args[0]
self.logger.warning('Trello websocket error: {}'.format(error)) self.logger.warning('Trello websocket error: {}'.format(error))
return hndl return hndl
def _on_close(self): def _on_close(self):
# noinspection PyUnusedLocal def hndl(*_):
def hndl(ws: WebSocketApp):
self.logger.warning('Trello websocket connection closed') self.logger.warning('Trello websocket connection closed')
self._connected.clear() self._connected.clear()
self._req_id = 0 self._req_id = 0
@ -166,8 +172,10 @@ class TrelloBackend(Backend):
def _on_open(self): def _on_open(self):
# noinspection PyUnusedLocal # noinspection PyUnusedLocal
def hndl(ws: WebSocketApp): def hndl(*args):
ws = args[0] if args else None
self._connected.set() self._connected.set()
if ws:
self._send(ws, {'type': 'ping'}) self._send(ws, {'type': 'ping'})
self.logger.info('Trello websocket connected') self.logger.info('Trello websocket connected')

View file

@ -100,7 +100,8 @@ class MediaKodiPlugin(MediaPlugin):
bus.post(evt_type(player=self.host, plugin='media.kodi', **evt)) bus.post(evt_type(player=self.host, plugin='media.kodi', **evt))
def _on_ws_msg(self): def _on_ws_msg(self):
def hndl(ws, msg): def hndl(*args):
msg = args[1] if len(args) > 1 else args[0]
self.logger.info("Received Kodi message: {}".format(msg)) self.logger.info("Received Kodi message: {}".format(msg))
msg = json.loads(msg) msg = json.loads(msg)
method = msg.get('method') method = msg.get('method')
@ -129,12 +130,13 @@ class MediaKodiPlugin(MediaPlugin):
return hndl return hndl
def _on_ws_error(self): def _on_ws_error(self):
def hndl(ws, error): def hndl(*args):
error = args[1] if len(args) > 1 else args[0]
self.logger.warning("Kodi websocket connection error: {}".format(error)) self.logger.warning("Kodi websocket connection error: {}".format(error))
return hndl return hndl
def _on_ws_close(self): def _on_ws_close(self):
def hndl(ws): def hndl(*_):
self._ws = None self._ws = None
self.logger.warning("Kodi websocket connection closed") self.logger.warning("Kodi websocket connection closed")
time.sleep(5) time.sleep(5)

View file

@ -1,6 +1,4 @@
import asyncio
import json import json
import os
import websockets import websockets
from platypush.context import get_or_create_event_loop from platypush.context import get_or_create_event_loop
@ -18,30 +16,30 @@ class WebsocketPlugin(Plugin):
* **websockets** (``pip install websockets``) * **websockets** (``pip install websockets``)
""" """
def __init__(self, *args, **kwargs): def __init__(self, **kwargs):
super().__init__(*args, **kwargs) super().__init__(**kwargs)
@action @action
def send(self, url, msg, ssl_cert=None, ssl_key=None, ssl_cafile=None, def send(self, url, msg, ssl_cert=None, ssl_key=None, ssl_cafile=None, ssl_capath=None):
ssl_capath=None, *args, **kwargs):
""" """
Sends a message to a websocket. Sends a message to a websocket.
:param url: Websocket URL, e.g. ws://localhost:8765 or wss://localhost:8765 :param url: Websocket URL, e.g. ws://localhost:8765 or wss://localhost:8765
:type topic: str :type url: str
:param msg: Message to be sent. It can be a list, a dict, or a Message object :param msg: Message to be sent. It can be a list, a dict, or a Message object
:param ssl_cert: Path to the SSL certificate to be used, if the SSL connection requires client authentication as well (default: None) :param ssl_cert: Path to the SSL certificate to be used, if the SSL connection requires client authentication
:type ssl_cert: str as well (default: None) :type ssl_cert: str
:param ssl_key: Path to the SSL key to be used, if the SSL connection requires client authentication as well (default: None) :param ssl_key: Path to the SSL key to be used, if the SSL connection requires client authentication as well
:type ssl_key: str (default: None) :type ssl_key: str
:param ssl_cafile: Path to the certificate authority file if required by the SSL configuration (default: None) :param ssl_cafile: Path to the certificate authority file if required by the SSL configuration (default: None)
:type ssl_cafile: str :type ssl_cafile: str
:param ssl_capath: Path to the certificate authority directory if required by the SSL configuration (default: None) :param ssl_capath: Path to the certificate authority directory if required by the SSL configuration
(default: None)
:type ssl_capath: str :type ssl_capath: str
""" """
@ -56,19 +54,21 @@ class WebsocketPlugin(Plugin):
async with websockets.connect(url, **websocket_args) as websocket: async with websockets.connect(url, **websocket_args) as websocket:
try: try:
await websocket.send(str(msg)) await websocket.send(str(msg))
except websockets.exceptions.ConnectionClosed: except websockets.exceptions.ConnectionClosed as err:
self.logger.warning('Error on websocket {}: {}'. self.logger.warning('Error on websocket {}: {}'.
format(url, e)) format(url, err))
try: msg = json.dumps(msg) try:
except: pass msg = json.dumps(msg)
except Exception as e:
self.logger.debug(e)
try: msg = Message.build(json.loads(msg)) try:
except: pass msg = Message.build(json.loads(msg))
except Exception as e:
self.logger.debug(e)
loop = get_or_create_event_loop() loop = get_or_create_event_loop()
loop.run_until_complete(send()) loop.run_until_complete(send())
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et:

View file

@ -74,7 +74,7 @@ setup(
# Support for Kafka backend and plugin # Support for Kafka backend and plugin
'kafka': ['kafka-python'], 'kafka': ['kafka-python'],
# Support for Pushbullet backend and plugin # Support for Pushbullet backend and plugin
'pushbullet': ['pushbullet.py @ https://github.com/rbrcsk/pushbullet.py/tarball/master'], 'pushbullet': ['pushbullet.py @ https://github.com/BlackLight/pushbullet.py/tarball/master'],
# Support for HTTP backend # Support for HTTP backend
'http': ['flask', 'frozendict', 'bcrypt'], 'http': ['flask', 'frozendict', 'bcrypt'],
# Support for uWSGI HTTP backend # Support for uWSGI HTTP backend