Refactored Pushbullet backend to remove the dependency from websocket-client and rely only on websockets

This commit is contained in:
Fabio Manganiello 2018-12-18 19:01:51 +01:00
parent 6a9ddb9e53
commit 186ade8f18
3 changed files with 91 additions and 57 deletions

View file

@ -1,9 +1,11 @@
import asyncio
import json import json
import requests import requests
import time import time
import websocket import websockets
from platypush.config import Config from platypush.config import Config
from platypush.context import get_or_create_event_loop
from platypush.message import Message from platypush.message import Message
from platypush.message.event.pushbullet import PushbulletEvent from platypush.message.event.pushbullet import PushbulletEvent
@ -26,7 +28,7 @@ class PushbulletBackend(Backend):
Requires: Requires:
* **requests** (``pip install requests``) * **requests** (``pip install requests``)
* **websocket-client** (``pip install websocket-client``) * **websockets** (``pip install websockets``)
""" """
def __init__(self, token, device='Platypush', **kwargs): def __init__(self, token, device='Platypush', **kwargs):
@ -43,6 +45,7 @@ class PushbulletBackend(Backend):
self.token = token self.token = token
self.device_name = device self.device_name = device
self.pb_device_id = self.get_device_id() self.pb_device_id = self.get_device_id()
self.ws = None
self._last_received_msg = { self._last_received_msg = {
'request' : { 'body': None, 'time': None }, 'request' : { 'body': None, 'time': None },
@ -94,12 +97,11 @@ class PushbulletBackend(Backend):
return is_duplicate return is_duplicate
def on_push(self): def on_push(self, ws, data):
def _f(ws, data):
try: try:
# Parse the push # Parse the push
try: try:
data = json.loads(data) if isinstance(data, str) else push data = json.loads(data) if isinstance(data, str) else data
except Exception as e: except Exception as e:
self.logger.exception(e) self.logger.exception(e)
return return
@ -129,22 +131,44 @@ class PushbulletBackend(Backend):
self.logger.exception(e) self.logger.exception(e)
return return
return _f def on_error(self, ws, e):
def on_error(self):
def _f(ws, e):
self.logger.exception(e) self.logger.exception(e)
self.logger.info('Restarting PushBullet backend') self.logger.info('Restarting PushBullet backend')
ws.close() ws.close()
self._init_socket() self._init_socket()
return _f
def _init_socket(self): def _init_socket(self):
self.ws = websocket.WebSocketApp( async def pushbullet_client():
'wss://stream.pushbullet.com/websocket/' + self.token, async with websockets.connect('wss://stream.pushbullet.com/websocket/'
on_message = self.on_push(), + self.token) as self.ws:
on_error = self.on_error()) while True:
try:
push = await self.ws.recv()
except Exception as e:
self.on_error(ws, e)
break
self.on_push(self.ws, push)
self.close()
loop = get_or_create_event_loop()
loop.run_until_complete(pushbullet_client())
loop.run_forever()
def create_device(self, name):
return requests.post(
u'https://api.pushbullet.com/v2/devices',
headers = { 'Access-Token': self.token },
json = {
'nickname': name,
'model': 'Platypush virtual device',
'manufactorer': 'platypush',
'app_version': 8623,
'icon': 'system',
}
).json()
def get_device_id(self): def get_device_id(self):
response = requests.get( response = requests.get(
@ -155,12 +179,22 @@ class PushbulletBackend(Backend):
devices = [dev for dev in response['devices'] if 'nickname' in dev devices = [dev for dev in response['devices'] if 'nickname' in dev
and dev['nickname'] == self.device_name] and dev['nickname'] == self.device_name]
if not devices: if devices:
raise RuntimeError('No such Pushbullet device: {}'
.format(self.device_name))
return devices[0]['iden'] return devices[0]['iden']
try:
response = self.create_device(self.device_name)
if 'iden' not in response:
raise RuntimeError()
self.logger.info('Created Pushbullet device {}'.format(
self.device_name))
return response['iden']
except Exception as e:
self.logger.error('Unable to create Pushbillet device {}'.
format(self.device_name))
def send_message(self, msg): def send_message(self, msg):
requests.post( requests.post(
u'https://api.pushbullet.com/v2/pushes', u'https://api.pushbullet.com/v2/pushes',
@ -172,17 +206,19 @@ class PushbulletBackend(Backend):
} }
).json() ).json()
def on_stop(self): def close(self):
if self.ws:
self.ws.close() self.ws.close()
def on_stop(self):
return self.close()
def run(self): def run(self):
super().run() super().run()
self._init_socket()
self.logger.info('Initialized Pushbullet backend - device_id: {}' self.logger.info('Initialized Pushbullet backend - device_id: {}'
.format(self.device_name)) .format(self.device_name))
self._init_socket()
self.ws.run_forever()
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et:

View file

@ -11,9 +11,6 @@ pyyaml
# Apache Kafka backend support # Apache Kafka backend support
kafka-python kafka-python
# PushBullet backend support
websocket-client
# HTTP backend support # HTTP backend support
flask flask
websockets websockets

View file

@ -61,11 +61,12 @@ setup(
install_requires = [ install_requires = [
'pyyaml', 'pyyaml',
'redis', 'redis',
'requests',
], ],
extras_require = { extras_require = {
'Support for Apache Kafka backend': ['kafka-python'], 'Support for Apache Kafka backend': ['kafka-python'],
'Support for Pushbullet backend': ['requests', 'websocket-client'], 'Support for Pushbullet backend': ['requests', 'websockets'],
'Support for HTTP backend': ['flask','websockets'], 'Support for HTTP backend': ['flask','websockets', 'python-dateutil'],
'Support for HTTP poll backend': ['frozendict'], 'Support for HTTP poll backend': ['frozendict'],
'Support for database plugin': ['sqlalchemy'], 'Support for database plugin': ['sqlalchemy'],
'Support for RSS feeds': ['feedparser'], 'Support for RSS feeds': ['feedparser'],
@ -93,7 +94,7 @@ setup(
'Support for Chromecast plugin': ['pychromecast'], 'Support for Chromecast plugin': ['pychromecast'],
'Support for sound devices': ['sounddevice', 'soundfile', 'numpy'], 'Support for sound devices': ['sounddevice', 'soundfile', 'numpy'],
# 'Support for Leap Motion backend': ['git+ssh://git@github.com:BlackLight/leap-sdk-python3.git'], # 'Support for Leap Motion backend': ['git+ssh://git@github.com:BlackLight/leap-sdk-python3.git'],
# 'Support for Flic buttons': ['git+ssh://git@github.com/50ButtonsEach/fliclib-linux-hci'] # 'Support for Flic buttons': ['git+https://@github.com/50ButtonsEach/fliclib-linux-hci.git']
}, },
) )