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
|
|
|
|
2022-04-23 20:32:32 +02:00
|
|
|
def send(self, data, sorting=False):
|
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):
|
2022-01-25 07:47:40 +01:00
|
|
|
try:
|
2022-04-23 20:32:32 +02:00
|
|
|
if sorting:
|
|
|
|
try:
|
|
|
|
data['data'].sort(key=lambda x: x.get('name').upper())
|
|
|
|
except:
|
|
|
|
pass
|
2022-01-25 07:47:40 +01:00
|
|
|
await ws.send_json(data=data, dumps=json_dumps)
|
|
|
|
except Exception as e:
|
|
|
|
self.logger.error("Error with client %s: %s" % (ws, str(e)))
|
|
|
|
|
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):
|
2021-01-09 15:20:56 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
2018-11-01 19:50:04 +01:00
|
|
|
ws = web.WebSocketResponse()
|
|
|
|
await ws.prepare(request)
|
|
|
|
self._clients.add(ws)
|
2021-01-09 15:20:56 +01:00
|
|
|
try:
|
|
|
|
peername = request.transport.get_extra_info('peername')
|
|
|
|
if peername is not None:
|
2021-02-16 20:37:51 +01:00
|
|
|
|
2021-01-09 15:20:56 +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
|
2021-01-09 15:20:56 +01:00
|
|
|
|
|
|
|
|
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")
|
|
|
|
|
2021-01-09 15:20:56 +01:00
|
|
|
return ws
|
2022-01-25 07:47:40 +01:00
|
|
|
|