craftbeerpi4-pione/cbpi/websocket.py

88 lines
2.8 KiB
Python
Raw Normal View History

2018-11-01 19:50:04 +01:00
import logging
import weakref
from collections import defaultdict
2019-01-04 09:29:09 +01:00
2018-11-01 19:50:04 +01:00
import aiohttp
from aiohttp import web
2019-01-04 09:29:09 +01:00
from voluptuous import Schema
2019-01-05 20:43:48 +01:00
from cbpi.utils import json_dumps
2018-12-03 22:16:03 +01:00
2018-11-01 19:50:04 +01:00
2019-01-01 15:35:35 +01:00
class CBPiWebSocket:
2018-11-01 21:25:42 +01:00
def __init__(self, cbpi) -> None:
self.cbpi = cbpi
2018-11-01 19:50:04 +01:00
self._callbacks = defaultdict(set)
self._clients = weakref.WeakSet()
self.logger = logging.getLogger(__name__)
2018-11-01 21:25:42 +01:00
self.cbpi.app.add_routes([web.get('/ws', self.websocket_handler)])
2019-01-01 15:35:35 +01:00
self.cbpi.bus.register_object(self)
2018-11-01 19:50:04 +01:00
2019-01-14 07:33:59 +01:00
#if self.cbpi.config.static.get("ws_push_all", False):
2019-01-17 22:11:55 +01:00
self.cbpi.bus.register("#", self.listen)
2019-01-14 07:33:59 +01:00
2018-12-03 22:16:03 +01:00
async def listen(self, topic, **kwargs):
2019-01-04 09:29:09 +01:00
data = dict(topic=topic, data=dict(**kwargs))
2019-01-05 20:43:48 +01:00
self.logger.debug("PUSH %s " % data)
2018-12-29 00:27:19 +01:00
self.send(data)
2018-12-03 22:16:03 +01:00
2019-01-14 07:33:59 +01:00
2018-11-16 20:35:59 +01:00
def send(self, data):
2019-01-04 09:29:09 +01:00
self.logger.debug("broadcast to ws clients. Data: %s" % data)
2018-11-16 20:35:59 +01:00
for ws in self._clients:
async def send_data(ws, data):
2019-01-04 09:29:09 +01:00
await ws.send_json(data=data, dumps=json_dumps)
2018-11-16 20:35:59 +01:00
self.cbpi.app.loop.create_task(send_data(ws, data))
2018-11-01 19:50:04 +01:00
async def websocket_handler(self, request):
2018-11-01 19:50:04 +01:00
ws = web.WebSocketResponse()
await ws.prepare(request)
self._clients.add(ws)
try:
peername = request.transport.get_extra_info('peername')
if peername is not None:
2021-02-16 20:37:51 +01:00
host = peername[0]
port = peername[1]
else:
host, port = "Unknowen"
self.logger.info("Client Connected - Host: %s Port: %s - client count: %s " % (host, port, len(self._clients)))
except Exception as e:
2021-02-16 20:37:51 +01:00
pass
2018-11-01 19:50:04 +01:00
try:
2019-01-04 09:29:09 +01:00
await ws.send_json(data=dict(topic="connection/success"))
2018-11-01 19:50:04 +01:00
async for msg in ws:
if msg.type == aiohttp.WSMsgType.TEXT:
2019-01-04 09:29:09 +01:00
msg_obj = msg.json()
schema = Schema({"topic": str, "data": dict})
schema(msg_obj)
topic = msg_obj.get("topic")
data = msg_obj.get("data")
if topic == "close":
2018-11-01 19:50:04 +01:00
await ws.close()
else:
2019-01-04 09:29:09 +01:00
if data is not None:
await self.cbpi.bus.fire(topic=topic, **data)
else:
await self.cbpi.bus.fire(topic=topic)
2018-11-01 19:50:04 +01:00
elif msg.type == aiohttp.WSMsgType.ERROR:
self.logger.error('ws connection closed with exception %s' % ws.exception())
2019-01-04 09:29:09 +01:00
except Exception as e:
self.logger.error("%s - Received Data %s" % (str(e), msg.data))
2018-11-01 19:50:04 +01:00
finally:
self._clients.discard(ws)
self.logger.info("Web Socket Close")
return ws