replaces SioServerWrapper with setup function

This commit is contained in:
Mose Müller 2023-12-19 12:57:30 +01:00
parent f64b5c35ab
commit c7d63f5139
2 changed files with 88 additions and 75 deletions

View File

@ -6,6 +6,7 @@ import socketio # type: ignore[import-untyped]
from pydase.data_service.data_service import process_callable_attribute
from pydase.data_service.data_service_observer import DataServiceObserver
from pydase.data_service.state_manager import StateManager
from pydase.utils.helpers import get_object_attr_from_path_list
from pydase.utils.logging import SocketIOHandler
from pydase.utils.serializer import dump
@ -89,64 +90,37 @@ class UpdateWebSettingsDict(TypedDict):
value: Any
class SioServerWrapper:
def __init__(
self,
def setup_sio_server(
observer: DataServiceObserver,
enable_cors: bool,
loop: asyncio.AbstractEventLoop,
) -> None:
self._loop = loop
self._enable_cors = enable_cors
self._observer = observer
self._state_manager = self._observer.state_manager
self._service = self._state_manager.service
) -> socketio.AsyncServer:
"""
Sets up and configures a Socket.IO asynchronous server.
self._setup_sio()
self._setup_logging_handler()
Args:
observer (DataServiceObserver):
The observer managing state updates and communication.
enable_cors (bool):
Flag indicating whether CORS should be enabled for the server.
loop (asyncio.AbstractEventLoop):
The event loop in which the server will run.
def _setup_logging_handler(self) -> None:
logger = logging.getLogger()
logger.addHandler(SocketIOHandler(self.sio))
Returns:
socketio.AsyncServer: The configured Socket.IO asynchronous server.
"""
def _setup_sio(self) -> None:
if self._enable_cors:
self.sio = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins="*")
state_manager = observer.state_manager
if enable_cors:
sio = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins="*")
else:
self.sio = socketio.AsyncServer(async_mode="asgi")
sio = socketio.AsyncServer(async_mode="asgi")
@self.sio.event
def set_attribute(sid: str, data: UpdateDict) -> Any:
logger.debug("Received frontend update: %s", data)
path_list = [*data["parent_path"].split("."), data["name"]]
path_list.remove("DataService") # always at the start, does not do anything
path = ".".join(path_list)
return self._state_manager.set_service_attribute_value_by_path(
path=path, value=data["value"]
)
setup_sio_events(sio, state_manager)
setup_logging_handler(sio)
@self.sio.event
def run_method(sid: str, data: RunMethodDict) -> Any:
logger.debug("Running method: %s", data)
path_list = [*data["parent_path"].split("."), data["name"]]
path_list.remove("DataService") # always at the start, does not do anything
method = get_object_attr_from_path_list(self._service, path_list)
return process_callable_attribute(method, data["kwargs"])
@self.sio.event
def web_settings(sid: str, data: UpdateWebSettingsDict) -> Any:
logger.debug("Received web settings update: %s", data)
path_list, config_option, value = (
data["access_path"].split("."),
data["config_option"],
data["value"],
)
path_list.pop(0) # remove first entry (specifies root object, not needed)
# write to web-settings.json file
self._add_notification_callback_to_observer()
def _add_notification_callback_to_observer(self) -> None:
# Add notification callback to observer
def sio_callback(
full_access_path: str, value: Any, cached_value_dict: dict[str, Any]
) -> None:
@ -159,7 +133,7 @@ class SioServerWrapper:
async def notify() -> None:
try:
await self.sio.emit(
await sio.emit(
"notify",
{
"data": {
@ -171,6 +145,43 @@ class SioServerWrapper:
except Exception as e:
logger.warning("Failed to send notification: %s", e)
self._loop.create_task(notify())
loop.create_task(notify())
self._observer.add_notification_callback(sio_callback)
observer.add_notification_callback(sio_callback)
return sio
def setup_sio_events(sio: socketio.AsyncServer, state_manager: StateManager) -> None:
@sio.event
def set_attribute(sid: str, data: UpdateDict) -> Any:
logger.debug("Received frontend update: %s", data)
path_list = [*data["parent_path"].split("."), data["name"]]
path_list.remove("DataService") # always at the start, does not do anything
path = ".".join(path_list)
return state_manager.set_service_attribute_value_by_path(
path=path, value=data["value"]
)
@sio.event
def run_method(sid: str, data: RunMethodDict) -> Any:
logger.debug("Running method: %s", data)
path_list = [*data["parent_path"].split("."), data["name"]]
path_list.remove("DataService") # always at the start, does not do anything
method = get_object_attr_from_path_list(state_manager.service, path_list)
return process_callable_attribute(method, data["kwargs"])
@sio.event
def web_settings(sid: str, data: UpdateWebSettingsDict) -> Any:
logger.debug("Received web settings update: %s", data)
path_list, config_option, value = (
data["access_path"].split("."),
data["config_option"],
data["value"],
)
path_list.pop(0) # remove first entry (specifies root object, not needed)
def setup_logging_handler(sio: socketio.AsyncServer) -> None:
logger = logging.getLogger()
logger.addHandler(SocketIOHandler(sio))

View File

@ -11,7 +11,9 @@ from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles
from pydase.data_service.data_service_observer import DataServiceObserver
from pydase.server.web_server.sio_server_wrapper import SioServerWrapper
from pydase.server.web_server.sio_server import (
setup_sio_server,
)
from pydase.version import __version__
logger = logging.getLogger(__name__)
@ -77,7 +79,7 @@ class WebServer:
await self.web_server.serve()
def _setup_socketio(self) -> None:
self._sio = SioServerWrapper(self.observer, self.enable_cors, self._loop).sio
self._sio = setup_sio_server(self.observer, self.enable_cors, self._loop)
self.__sio_app = socketio.ASGIApp(self._sio)
def _setup_fastapi_app(self) -> None: