浏览代码

move context manager for individual targets to Client

Falko Schindler 1 年之前
父节点
当前提交
f443933bab
共有 3 个文件被更改,包括 18 次插入16 次删除
  1. 15 2
      nicegui/client.py
  2. 2 2
      nicegui/elements/scene.py
  3. 1 12
      nicegui/globals.py

+ 15 - 2
nicegui/client.py

@@ -3,8 +3,9 @@ from __future__ import annotations
 import asyncio
 import time
 import uuid
+from contextlib import contextmanager
 from pathlib import Path
-from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict, Iterable, List, Optional, Union
+from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict, Iterable, Iterator, List, Optional, Union
 
 from fastapi import Request
 from fastapi.responses import Response
@@ -59,6 +60,8 @@ class Client:
         self.connect_handlers: List[Union[Callable[..., Any], Awaitable]] = []
         self.disconnect_handlers: List[Union[Callable[..., Any], Awaitable]] = []
 
+        self._temporary_socket_id: Optional[str] = None
+
     @property
     def ip(self) -> Optional[str]:
         """Return the IP address of the client, or None if the client is not connected."""
@@ -147,7 +150,7 @@ class Client:
                              'Please remove the "respond=False" argument and call the method without awaiting.')
 
         request_id = str(uuid.uuid4())
-        target_id = globals._socket_id or self.id  # pylint: disable=protected-access
+        target_id = self._temporary_socket_id or self.id
 
         def send_and_forget():
             outbox.enqueue_message('run_javascript', {'code': code}, target_id)
@@ -194,3 +197,13 @@ class Client:
     def remove_all_elements(self) -> None:
         """Remove all elements from the client."""
         self.remove_elements(self.elements.values())
+
+    @contextmanager
+    def individual_target(self, socket_id: str) -> Iterator[None]:
+        """Use individual socket ID while in this context.
+
+        This context is useful for limiting messages from the shared auto-index page to a single client.
+        """
+        self._temporary_socket_id = socket_id
+        yield
+        self._temporary_socket_id = None

+ 2 - 2
nicegui/elements/scene.py

@@ -3,7 +3,7 @@ from typing import Any, Callable, Dict, List, Optional, Union
 
 from typing_extensions import Self
 
-from .. import binding, globals  # pylint: disable=redefined-builtin
+from .. import binding
 from ..awaitable_response import AwaitableResponse
 from ..dataclasses import KWONLY_SLOTS
 from ..element import Element
@@ -112,7 +112,7 @@ class Scene(Element,
 
     def _handle_init(self, e: GenericEventArguments) -> None:
         self.is_initialized = True
-        with globals.socket_id(e.args['socket_id']):
+        with self.client.individual_target(e.args['socket_id']):
             self.move_camera(duration=0)
             for obj in self.objects.values():
                 obj.send()

+ 1 - 12
nicegui/globals.py

@@ -2,9 +2,8 @@ from __future__ import annotations
 
 import asyncio
 import os
-from contextlib import contextmanager
 from pathlib import Path
-from typing import TYPE_CHECKING, Dict, Iterator, List, Literal, Optional, Set, Union
+from typing import TYPE_CHECKING, Dict, List, Literal, Optional, Set, Union
 
 from socketio import AsyncServer
 from uvicorn import Server
@@ -39,7 +38,6 @@ storage_path: Path = Path(os.environ.get('NICEGUI_STORAGE_PATH', '.nicegui')).re
 socket_io_js_query_params: Dict = {}
 socket_io_js_extra_headers: Dict = {}
 socket_io_js_transports: List[Literal['websocket', 'polling']] = ['websocket', 'polling']  # NOTE: we favor websocket
-_socket_id: Optional[str] = None
 slot_stacks: Dict[int, List[Slot]] = {}
 clients: Dict[str, Client] = {}
 index_client: Client
@@ -85,12 +83,3 @@ def get_slot() -> Slot:
 def get_client() -> Client:
     """Return the current client."""
     return get_slot().parent.client
-
-
-@contextmanager
-def socket_id(id_: str) -> Iterator[None]:
-    """Enter a context with a specific socket ID."""
-    global _socket_id  # pylint: disable=global-statement
-    _socket_id = id_
-    yield
-    _socket_id = None