124 lines
4.3 KiB
Python
124 lines
4.3 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
from threading import Thread
|
|
from typing import Any, Self, Sequence, Optional
|
|
from Abstracts.WebSocketServersAbstract import WebSocketServersAbstract
|
|
from Abstracts.ModelAbstract import ModelAbstract
|
|
from websockets.sync.server import serve as server_serve
|
|
from websockets import Server as WebSocketServer, ClientConnection as WebSocketClient
|
|
from Interfaces.Application.AnPInterface import AnPInterface
|
|
from Utils.Checks import Check
|
|
|
|
class WebSocketServerDriver(WebSocketServersAbstract, ModelAbstract):
|
|
|
|
def __init__(self:Self, anp:AnPInterface, key:str, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None:
|
|
super().__init__(anp, key, inputs)
|
|
|
|
self.__server:WebSocketServer
|
|
self.__clients:dict[str, WebSocketClient] = {}
|
|
self.__thread:Thread = None
|
|
|
|
anp.settings.get(("web_socket_server_autostart", "autostart"), inputs, True) and self.start()
|
|
|
|
def __run(self:Self) -> None:
|
|
self.__server = server_serve(self.__handler, self.host, self.port)
|
|
self.__server.serve_forever()
|
|
|
|
def start(self:Self) -> None:
|
|
self.__thread = Thread(target = self.__run)
|
|
self.__thread.start()
|
|
|
|
def close(self:Self) -> None:
|
|
|
|
id:str
|
|
|
|
for id in tuple(self.__clients.keys()):
|
|
self.close_client(id)
|
|
|
|
self.__server.shutdown()
|
|
|
|
def close_client(self:Self, ids:Optional[str|list[str]] = None) -> None:
|
|
|
|
id:str
|
|
|
|
for id in (
|
|
ids if Check.is_array(ids) else
|
|
list(self.__clients.keys()) if ids is None else
|
|
[ids] if Check.is_string(ids) else
|
|
[]):
|
|
if id in self.__clients:
|
|
try:
|
|
self.__clients[id].close()
|
|
except Exception as exception:
|
|
self.anp.exception(exception, "web_socket_server_client_close_exception", {
|
|
"id": id,
|
|
"port": self.port,
|
|
"host": self.host
|
|
})
|
|
|
|
def __handler(self:Self, client:WebSocketClient) -> None:
|
|
|
|
id:str = self.anp.unique_keys.get()
|
|
|
|
self.__clients[id] = client
|
|
self.on_new_client.execute(id)
|
|
|
|
self.anp.print("info", "web_socket_server_client_connected", {
|
|
"id": id,
|
|
"port": self.port,
|
|
"host": self.host,
|
|
"client_host" : client.remote_address[0],
|
|
"client_port" : client.remote_address[1]
|
|
})
|
|
|
|
self.send("web_socket_client", "set_id", id, id)
|
|
|
|
try:
|
|
while self.anp.working():
|
|
message:str = client.recv()
|
|
if message is None:
|
|
break
|
|
self.on_message.execute(id, message)
|
|
except Exception as exception:
|
|
self.anp.working() and self.anp.exception(exception, "web_socket_server_client_exception", {
|
|
"id": id,
|
|
"port": self.port,
|
|
"host": self.host
|
|
})
|
|
self.on_error.execute(id, exception)
|
|
finally:
|
|
try:
|
|
self.__clients[id].close()
|
|
except Exception as _:
|
|
pass
|
|
del self.__clients[id]
|
|
self.anp.unique_keys.remove(id)
|
|
self.on_close.execute(id)
|
|
self.anp.print("info", "web_socket_server_client_disconnected", {
|
|
"id": id,
|
|
"port": self.port,
|
|
"host": self.host
|
|
})
|
|
|
|
def send(self:Self, controller:str, action:str, data:str, ids:Optional[str|Sequence[str]] = None, code:int = 200) -> bool:
|
|
|
|
success:bool = True
|
|
id:str
|
|
|
|
for id in (
|
|
list(self.__clients.keys()) if ids is None else
|
|
ids if Check.is_array(ids) else
|
|
[ids]):
|
|
if id in self.__clients:
|
|
try:
|
|
self.__clients[id].send(self.format_data(controller, action, data, id, code))
|
|
except Exception as exception:
|
|
self.anp.exception(exception, "web_socket_server_client_send_exception", {
|
|
"id": id,
|
|
"port": self.port,
|
|
"host": self.host
|
|
})
|
|
success = False
|
|
|
|
return success |