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 import process_callable_attribute
from pydase.data_service.data_service_observer import DataServiceObserver 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.helpers import get_object_attr_from_path_list
from pydase.utils.logging import SocketIOHandler from pydase.utils.logging import SocketIOHandler
from pydase.utils.serializer import dump from pydase.utils.serializer import dump
@ -89,64 +90,37 @@ class UpdateWebSettingsDict(TypedDict):
value: Any value: Any
class SioServerWrapper: def setup_sio_server(
def __init__(
self,
observer: DataServiceObserver, observer: DataServiceObserver,
enable_cors: bool, enable_cors: bool,
loop: asyncio.AbstractEventLoop, loop: asyncio.AbstractEventLoop,
) -> None: ) -> socketio.AsyncServer:
self._loop = loop """
self._enable_cors = enable_cors Sets up and configures a Socket.IO asynchronous server.
self._observer = observer
self._state_manager = self._observer.state_manager
self._service = self._state_manager.service
self._setup_sio() Args:
self._setup_logging_handler() 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: Returns:
logger = logging.getLogger() socketio.AsyncServer: The configured Socket.IO asynchronous server.
logger.addHandler(SocketIOHandler(self.sio)) """
def _setup_sio(self) -> None: state_manager = observer.state_manager
if self._enable_cors:
self.sio = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins="*") if enable_cors:
sio = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins="*")
else: else:
self.sio = socketio.AsyncServer(async_mode="asgi") sio = socketio.AsyncServer(async_mode="asgi")
@self.sio.event setup_sio_events(sio, state_manager)
def set_attribute(sid: str, data: UpdateDict) -> Any: setup_logging_handler(sio)
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"]
)
@self.sio.event # Add notification callback to observer
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:
def sio_callback( def sio_callback(
full_access_path: str, value: Any, cached_value_dict: dict[str, Any] full_access_path: str, value: Any, cached_value_dict: dict[str, Any]
) -> None: ) -> None:
@ -159,7 +133,7 @@ class SioServerWrapper:
async def notify() -> None: async def notify() -> None:
try: try:
await self.sio.emit( await sio.emit(
"notify", "notify",
{ {
"data": { "data": {
@ -171,6 +145,43 @@ class SioServerWrapper:
except Exception as e: except Exception as e:
logger.warning("Failed to send notification: %s", 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 fastapi.staticfiles import StaticFiles
from pydase.data_service.data_service_observer import DataServiceObserver 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__ from pydase.version import __version__
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -77,7 +79,7 @@ class WebServer:
await self.web_server.serve() await self.web_server.serve()
def _setup_socketio(self) -> None: 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) self.__sio_app = socketio.ASGIApp(self._sio)
def _setup_fastapi_app(self) -> None: def _setup_fastapi_app(self) -> None: