mirror of
https://github.com/tiqi-group/pydase.git
synced 2025-04-21 00:40:01 +02:00
replaces SioServerWrapper with setup function
This commit is contained in:
parent
f64b5c35ab
commit
c7d63f5139
@ -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,88 +90,98 @@ class UpdateWebSettingsDict(TypedDict):
|
|||||||
value: Any
|
value: Any
|
||||||
|
|
||||||
|
|
||||||
class SioServerWrapper:
|
def setup_sio_server(
|
||||||
def __init__(
|
observer: DataServiceObserver,
|
||||||
self,
|
enable_cors: bool,
|
||||||
observer: DataServiceObserver,
|
loop: asyncio.AbstractEventLoop,
|
||||||
enable_cors: bool,
|
) -> socketio.AsyncServer:
|
||||||
loop: asyncio.AbstractEventLoop,
|
"""
|
||||||
|
Sets up and configures a Socket.IO asynchronous server.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
socketio.AsyncServer: The configured Socket.IO asynchronous server.
|
||||||
|
"""
|
||||||
|
|
||||||
|
state_manager = observer.state_manager
|
||||||
|
|
||||||
|
if enable_cors:
|
||||||
|
sio = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins="*")
|
||||||
|
else:
|
||||||
|
sio = socketio.AsyncServer(async_mode="asgi")
|
||||||
|
|
||||||
|
setup_sio_events(sio, state_manager)
|
||||||
|
setup_logging_handler(sio)
|
||||||
|
|
||||||
|
# Add notification callback to observer
|
||||||
|
def sio_callback(
|
||||||
|
full_access_path: str, value: Any, cached_value_dict: dict[str, Any]
|
||||||
) -> None:
|
) -> None:
|
||||||
self._loop = loop
|
if cached_value_dict != {}:
|
||||||
self._enable_cors = enable_cors
|
serialized_value = dump(value)
|
||||||
self._observer = observer
|
if cached_value_dict["type"] != "method":
|
||||||
self._state_manager = self._observer.state_manager
|
cached_value_dict["type"] = serialized_value["type"]
|
||||||
self._service = self._state_manager.service
|
|
||||||
|
|
||||||
self._setup_sio()
|
cached_value_dict["value"] = serialized_value["value"]
|
||||||
self._setup_logging_handler()
|
|
||||||
|
|
||||||
def _setup_logging_handler(self) -> None:
|
async def notify() -> None:
|
||||||
logger = logging.getLogger()
|
try:
|
||||||
logger.addHandler(SocketIOHandler(self.sio))
|
await sio.emit(
|
||||||
|
"notify",
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"full_access_path": full_access_path,
|
||||||
|
"value": cached_value_dict,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning("Failed to send notification: %s", e)
|
||||||
|
|
||||||
def _setup_sio(self) -> None:
|
loop.create_task(notify())
|
||||||
if self._enable_cors:
|
|
||||||
self.sio = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins="*")
|
|
||||||
else:
|
|
||||||
self.sio = socketio.AsyncServer(async_mode="asgi")
|
|
||||||
|
|
||||||
@self.sio.event
|
observer.add_notification_callback(sio_callback)
|
||||||
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"]
|
|
||||||
)
|
|
||||||
|
|
||||||
@self.sio.event
|
return sio
|
||||||
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 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"]
|
||||||
|
)
|
||||||
|
|
||||||
def _add_notification_callback_to_observer(self) -> None:
|
@sio.event
|
||||||
def sio_callback(
|
def run_method(sid: str, data: RunMethodDict) -> Any:
|
||||||
full_access_path: str, value: Any, cached_value_dict: dict[str, Any]
|
logger.debug("Running method: %s", data)
|
||||||
) -> None:
|
path_list = [*data["parent_path"].split("."), data["name"]]
|
||||||
if cached_value_dict != {}:
|
path_list.remove("DataService") # always at the start, does not do anything
|
||||||
serialized_value = dump(value)
|
method = get_object_attr_from_path_list(state_manager.service, path_list)
|
||||||
if cached_value_dict["type"] != "method":
|
return process_callable_attribute(method, data["kwargs"])
|
||||||
cached_value_dict["type"] = serialized_value["type"]
|
|
||||||
|
|
||||||
cached_value_dict["value"] = serialized_value["value"]
|
@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)
|
||||||
|
|
||||||
async def notify() -> None:
|
|
||||||
try:
|
|
||||||
await self.sio.emit(
|
|
||||||
"notify",
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"full_access_path": full_access_path,
|
|
||||||
"value": cached_value_dict,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning("Failed to send notification: %s", e)
|
|
||||||
|
|
||||||
self._loop.create_task(notify())
|
def setup_logging_handler(sio: socketio.AsyncServer) -> None:
|
||||||
|
logger = logging.getLogger()
|
||||||
self._observer.add_notification_callback(sio_callback)
|
logger.addHandler(SocketIOHandler(sio))
|
||||||
|
@ -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:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user