2021-02-26 15:39:35 +00:00
|
|
|
import json
|
2021-04-03 17:36:01 +00:00
|
|
|
import logging
|
2021-02-26 15:39:35 +00:00
|
|
|
|
2023-08-09 21:47:53 +00:00
|
|
|
from app.classes.shared.singleton import Singleton
|
2022-04-12 01:34:46 +00:00
|
|
|
from app.classes.shared.console import Console
|
2023-08-09 21:47:53 +00:00
|
|
|
from app.classes.models.users import HelperUsers
|
2022-04-12 01:34:46 +00:00
|
|
|
|
2021-04-03 17:36:01 +00:00
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
2022-03-23 02:50:12 +00:00
|
|
|
|
2023-08-09 21:47:53 +00:00
|
|
|
class WebSocketManager(metaclass=Singleton):
|
|
|
|
def __init__(self):
|
2023-09-05 21:00:52 +00:00
|
|
|
self.clients = set()
|
2021-02-26 15:39:35 +00:00
|
|
|
|
2021-08-10 20:17:56 +00:00
|
|
|
def add_client(self, client):
|
2023-09-05 21:00:52 +00:00
|
|
|
self.clients.add(client)
|
2022-01-26 01:45:30 +00:00
|
|
|
|
2021-08-10 20:17:56 +00:00
|
|
|
def remove_client(self, client):
|
2023-09-05 21:00:52 +00:00
|
|
|
if client in self.clients:
|
|
|
|
self.clients.remove(client)
|
|
|
|
else:
|
|
|
|
logger.exception("Error caught while removing unknown WebSocket client")
|
2021-02-26 15:39:35 +00:00
|
|
|
|
2021-08-10 20:17:56 +00:00
|
|
|
def broadcast(self, event_type: str, data):
|
2022-03-23 02:50:12 +00:00
|
|
|
logger.debug(
|
2023-09-05 21:00:52 +00:00
|
|
|
f"Sending to {len(self.clients)} clients: "
|
2022-03-23 06:06:13 +00:00
|
|
|
f"{json.dumps({'event': event_type, 'data': data})}"
|
2022-03-23 02:50:12 +00:00
|
|
|
)
|
2023-09-05 21:00:52 +00:00
|
|
|
for client in self.clients:
|
2021-02-26 15:39:35 +00:00
|
|
|
try:
|
2023-08-09 21:47:53 +00:00
|
|
|
client.send_message(event_type, data)
|
2021-08-11 20:29:31 +00:00
|
|
|
except Exception as e:
|
2022-03-23 02:50:12 +00:00
|
|
|
logger.exception(
|
2022-03-23 06:06:13 +00:00
|
|
|
f"Error caught while sending WebSocket message to "
|
|
|
|
f"{client.get_remote_ip()} {e}"
|
2022-03-23 02:50:12 +00:00
|
|
|
)
|
2021-08-10 20:17:56 +00:00
|
|
|
|
2023-08-09 21:47:53 +00:00
|
|
|
def broadcast_to_admins(self, event_type: str, data):
|
|
|
|
def filter_fn(client):
|
|
|
|
if client.get_user_id in HelperUsers.get_super_user_list():
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
self.broadcast_with_fn(filter_fn, event_type, data)
|
|
|
|
|
2021-08-10 20:17:56 +00:00
|
|
|
def broadcast_page(self, page: str, event_type: str, data):
|
|
|
|
def filter_fn(client):
|
2023-09-05 21:08:40 +00:00
|
|
|
return client.page == page
|
2021-08-10 20:17:56 +00:00
|
|
|
|
2021-11-27 22:10:43 +00:00
|
|
|
self.broadcast_with_fn(filter_fn, event_type, data)
|
2021-08-10 20:17:56 +00:00
|
|
|
|
2021-11-27 22:10:43 +00:00
|
|
|
def broadcast_user(self, user_id: str, event_type: str, data):
|
|
|
|
def filter_fn(client):
|
|
|
|
return client.get_user_id() == user_id
|
2021-08-10 20:17:56 +00:00
|
|
|
|
2021-11-27 22:10:43 +00:00
|
|
|
self.broadcast_with_fn(filter_fn, event_type, data)
|
|
|
|
|
|
|
|
def broadcast_user_page(self, page: str, user_id: str, event_type: str, data):
|
|
|
|
def filter_fn(client):
|
|
|
|
if client.get_user_id() != user_id:
|
|
|
|
return False
|
|
|
|
if client.page != page:
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
|
|
self.broadcast_with_fn(filter_fn, event_type, data)
|
|
|
|
|
2022-03-23 02:50:12 +00:00
|
|
|
def broadcast_user_page_params(
|
|
|
|
self, page: str, params: dict, user_id: str, event_type: str, data
|
|
|
|
):
|
2021-11-27 22:10:43 +00:00
|
|
|
def filter_fn(client):
|
|
|
|
if client.get_user_id() != user_id:
|
|
|
|
return False
|
|
|
|
if client.page != page:
|
|
|
|
return False
|
|
|
|
for key, param in params.items():
|
|
|
|
if param != client.page_query_params.get(key, None):
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
|
|
|
|
self.broadcast_with_fn(filter_fn, event_type, data)
|
2022-01-26 01:45:30 +00:00
|
|
|
|
2021-08-10 20:17:56 +00:00
|
|
|
def broadcast_page_params(self, page: str, params: dict, event_type: str, data):
|
|
|
|
def filter_fn(client):
|
|
|
|
if client.page != page:
|
|
|
|
return False
|
|
|
|
for key, param in params.items():
|
|
|
|
if param != client.page_query_params.get(key, None):
|
|
|
|
return False
|
|
|
|
return True
|
|
|
|
|
2021-11-27 22:10:43 +00:00
|
|
|
self.broadcast_with_fn(filter_fn, event_type, data)
|
|
|
|
|
|
|
|
def broadcast_with_fn(self, filter_fn, event_type: str, data):
|
2022-10-02 18:29:36 +00:00
|
|
|
# assign self.clients to a static variable here so hopefully
|
|
|
|
# the set size won't change
|
2023-09-05 21:00:52 +00:00
|
|
|
static_clients = self.clients
|
2022-10-02 18:29:36 +00:00
|
|
|
clients = list(filter(filter_fn, static_clients))
|
2022-03-23 02:50:12 +00:00
|
|
|
logger.debug(
|
2023-08-27 12:10:20 +00:00
|
|
|
f"Sending to {len(clients)} \
|
2023-09-05 21:00:52 +00:00
|
|
|
out of {len(self.clients)} "
|
2022-03-23 06:06:13 +00:00
|
|
|
f"clients: {json.dumps({'event': event_type, 'data': data})}"
|
2022-03-23 02:50:12 +00:00
|
|
|
)
|
2021-08-10 20:17:56 +00:00
|
|
|
|
2022-09-16 17:09:10 +00:00
|
|
|
for client in clients[:]:
|
2021-08-10 20:17:56 +00:00
|
|
|
try:
|
2023-08-09 21:47:53 +00:00
|
|
|
client.send_message(event_type, data)
|
2021-08-11 20:29:31 +00:00
|
|
|
except Exception as e:
|
2022-03-23 02:50:12 +00:00
|
|
|
logger.exception(
|
2022-03-23 06:06:13 +00:00
|
|
|
f"Error catched while sending WebSocket message to "
|
|
|
|
f"{client.get_remote_ip()} {e}"
|
2022-03-23 02:50:12 +00:00
|
|
|
)
|
2022-01-26 01:45:30 +00:00
|
|
|
|
2021-02-26 15:39:35 +00:00
|
|
|
def disconnect_all(self):
|
2022-04-12 01:34:46 +00:00
|
|
|
Console.info("Disconnecting WebSocket clients")
|
2023-09-05 21:00:52 +00:00
|
|
|
for client in self.clients:
|
2021-02-26 15:39:35 +00:00
|
|
|
client.close()
|
2022-04-12 01:34:46 +00:00
|
|
|
Console.info("Disconnected WebSocket clients")
|