globals.py 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. from __future__ import annotations
  2. import asyncio
  3. import inspect
  4. import logging
  5. from contextlib import contextmanager
  6. from enum import Enum
  7. from pathlib import Path
  8. from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict, Iterator, List, Literal, Optional, Set, Union
  9. from socketio import AsyncServer
  10. from uvicorn import Server
  11. from . import background_tasks
  12. if TYPE_CHECKING:
  13. from .air import Air
  14. from .app import App
  15. from .client import Client
  16. from .language import Language
  17. from .slot import Slot
  18. class State(Enum):
  19. STOPPED = 0
  20. STARTING = 1
  21. STARTED = 2
  22. STOPPING = 3
  23. app: App
  24. sio: AsyncServer
  25. server: Server
  26. loop: Optional[asyncio.AbstractEventLoop] = None
  27. log: logging.Logger = logging.getLogger('nicegui')
  28. state: State = State.STOPPED
  29. ui_run_has_been_called: bool = False
  30. optional_features: Set[str] = set()
  31. reload: bool
  32. title: str
  33. viewport: str
  34. favicon: Optional[Union[str, Path]]
  35. storage_path: Path
  36. dark: Optional[bool]
  37. language: Language
  38. binding_refresh_interval: float
  39. tailwind: bool
  40. prod_js: bool
  41. endpoint_documentation: Literal['none', 'internal', 'page', 'all'] = 'none'
  42. air: Optional[Air] = None
  43. socket_io_js_query_params: Dict = {}
  44. socket_io_js_extra_headers: Dict = {}
  45. # NOTE we favor websocket over polling
  46. socket_io_js_transports: List[Literal['websocket', 'polling']] = ['websocket', 'polling']
  47. _socket_id: Optional[str] = None
  48. slot_stacks: Dict[int, List[Slot]] = {}
  49. clients: Dict[str, Client] = {}
  50. index_client: Client
  51. quasar_config: Dict = {
  52. 'brand': {
  53. 'primary': '#5898d4',
  54. },
  55. 'loadingBar': {
  56. 'color': 'primary',
  57. 'skipHijack': False,
  58. },
  59. }
  60. page_routes: Dict[Callable[..., Any], str] = {}
  61. startup_handlers: List[Union[Callable[..., Any], Awaitable]] = []
  62. shutdown_handlers: List[Union[Callable[..., Any], Awaitable]] = []
  63. connect_handlers: List[Union[Callable[..., Any], Awaitable]] = []
  64. disconnect_handlers: List[Union[Callable[..., Any], Awaitable]] = []
  65. exception_handlers: List[Callable[..., Any]] = [log.exception]
  66. def get_task_id() -> int:
  67. try:
  68. return id(asyncio.current_task())
  69. except RuntimeError:
  70. return 0
  71. def get_slot_stack() -> List[Slot]:
  72. task_id = get_task_id()
  73. if task_id not in slot_stacks:
  74. slot_stacks[task_id] = []
  75. return slot_stacks[task_id]
  76. def prune_slot_stack() -> None:
  77. task_id = get_task_id()
  78. if not slot_stacks[task_id]:
  79. del slot_stacks[task_id]
  80. def get_slot() -> Slot:
  81. return get_slot_stack()[-1]
  82. def get_client() -> Client:
  83. return get_slot().parent.client
  84. @contextmanager
  85. def socket_id(id: str) -> Iterator[None]:
  86. global _socket_id
  87. _socket_id = id
  88. yield
  89. _socket_id = None
  90. def handle_exception(exception: Exception) -> None:
  91. for handler in exception_handlers:
  92. result = handler() if not inspect.signature(handler).parameters else handler(exception)
  93. if isinstance(result, Awaitable):
  94. background_tasks.create(result)