cengal.parallel_execution.coroutines.integrations.nicegui.versions.v_0.nicegui
Module Docstring Docstrings: http://www.python.org/dev/peps/pep-0257/
1#!/usr/bin/env python 2# coding=utf-8 3 4# Copyright © 2012-2024 ButenkoMS. All rights reserved. Contacts: <gtalk@butenkoms.space> 5# 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17 18""" 19Module Docstring 20Docstrings: http://www.python.org/dev/peps/pep-0257/ 21""" 22 23__author__ = "ButenkoMS <gtalk@butenkoms.space>" 24__copyright__ = "Copyright © 2012-2024 ButenkoMS. All rights reserved. Contacts: <gtalk@butenkoms.space>" 25__credits__ = ["ButenkoMS <gtalk@butenkoms.space>", ] 26__license__ = "Apache License, Version 2.0" 27__version__ = "4.4.1" 28__maintainer__ = "ButenkoMS <gtalk@butenkoms.space>" 29__email__ = "gtalk@butenkoms.space" 30# __status__ = "Prototype" 31__status__ = "Development" 32# __status__ = "Production" 33 34 35__all__ = ['ClientHandlers', 'PageItems', 'nicegui_page_sync_coro', 'sync_like_page', 36 'sl_page', 'nicegui_page_async_coro', 'async_page', 'apage', 37 'nicegui_page_class_async_coro', 'async_page_class', 'apage_class', 38 'nicegui_event_handler_func_async_coro', 'async_event_handler_func', 39 'aevent_handler_func', 'nicegui_event_handler_method_async_coro', 40 'async_event_handler_method', 'aevent_handler_method', 'PageContextBase', 41 'run'] 42 43 44import asyncio 45 46 47class CurrentTask: 48 def __init__(self, original) -> None: 49 self.original = original 50 self.new = original 51 52 def patch(self, new): 53 self.new = new 54 55 def restore(self): 56 self.new = self.original 57 58 def __call__(self, *args, **kwds): 59 return self.new(*args, **kwds) 60 61 62current_task = CurrentTask(asyncio.current_task) 63asyncio.current_task = current_task 64 65 66from cengal.parallel_execution.coroutines.integrations.uvloop import uvloop_install 67uvloop_install() 68 69 70from cengal.parallel_execution.asyncio.init_loop import init_loop 71init_loop() 72 73 74if True: 75 # increasing max decode packets to be able to transfer images 76 # see https://github.com/miguelgrinberg/python-engineio/issues/142 77 from engineio.payload import Payload 78 Payload.max_decode_packets = 500 79 80 81import inspect 82from time import perf_counter 83from typing import Set, Tuple, Optional, Union, Dict, Callable, Any, Hashable, cast, List, Coroutine 84import warnings 85from cengal.parallel_execution.asyncio.atasks import create_task 86from cengal.parallel_execution.coroutines.coro_scheduler import Interface, AnyWorker, cs_acoro 87from cengal.parallel_execution.coroutines.coro_standard_services.async_event_bus import (AsyncEventBus, 88 AsyncEventBusRequest) 89from cengal.parallel_execution.coroutines.coro_standard_services.put_coro import PutCoro, put_coro_to 90from cengal.parallel_execution.coroutines.coro_standard_services.run_coro import RunCoro, arun_coro_fast, run_coro_fast 91from cengal.parallel_execution.coroutines.coro_standard_services.db import Db, DbRequest, EnvId, EnvInfo 92from cengal.parallel_execution.coroutines.coro_standard_services.simple_yield import Yield 93from cengal.parallel_execution.coroutines.coro_standard_services.sleep import Sleep 94from cengal.parallel_execution.coroutines.coro_standard_services.asyncio_loop import AsyncioLoop, AsyncioLoopRequest 95from cengal.parallel_execution.coroutines.coro_standard_services.shutdown_loop import ShutdownLoop 96from cengal.parallel_execution.coroutines.coro_standard_services.shutdown_on_keyboard_interrupt import ShutdownOnKeyboardInterrupt 97from cengal.parallel_execution.coroutines.coro_standard_services.simple_yield import Yield 98from cengal.parallel_execution.coroutines.coro_standard_services.instance import Instance, InstanceRequest, afast_wait, fast_get_explicit, fast_set_explicit 99from cengal.parallel_execution.coroutines.coro_standard_services.loop_yield import agly_patched 100from cengal.parallel_execution.coroutines.coro_standard_services.log import LogRequest 101from cengal.parallel_execution.coroutines.coro_tools.await_coro import await_coro_prim 102from cengal.parallel_execution.coroutines.coro_tools.run_in_loop import (arun_in_fast_loop, arun_in_loop, run_in_loop) 103from cengal.parallel_execution.coroutines.coro_tools.lock import Lock 104from cengal.code_flow_control.args_manager import args_kwargs, EntityArgsHolder, EntityArgsHolderExplicit 105from cengal.io.serve_free_ports import simple_port_search 106from uuid import uuid4 107from inspect import signature, Signature, isclass 108from cengal.parallel_execution.coroutines.coro_scheduler import * 109from cengal.data_manipulation.conversion.reinterpret_cast import \ 110 reinterpret_cast 111from cengal.parallel_execution.coroutines.coro_scheduler import ( 112 CoroWrapperAsyncAwait, Interface) 113from cengal.parallel_execution.coroutines.coro_tools.await_coro import \ 114 await_coro_prim 115from cengal.parallel_execution.coroutines.coro_tools.wait_coro import sync_coro_param 116from cengal.parallel_execution.asyncio.atasks import create_task 117 118 119from nicegui import app, ui, Client 120# from nicegui.binding import loop 121# agly_patched(loop) 122from cengal.parallel_execution.asyncio.timed_yield import TimedYield 123import nicegui.binding 124original__propagate = nicegui.binding.propagate 125class PropagateMock: 126 def __init__(self) -> None: 127 self.ty: TimedYield = TimedYield(0.01) 128 129 def __call__(self, source_obj: Any, source_name: str, visited: Optional[Set[Tuple[int, str]]] = None) -> None: 130 return original__propagate(source_obj, source_name, visited) 131 132 133nicegui.binding.propagate = PropagateMock() 134from nicegui.events import handle_event, GenericEventArguments, UiEventArguments 135from nicegui.dataclasses import KWONLY_SLOTS 136from nicegui.slot import Slot 137from nicegui.globals import slot_stacks 138from fastapi import Request as FastAPIRequest 139from .text_translation import setup_translation, create_translatable_text_element, TextTranslator, \ 140 TranslationLanguageMapper, TranslationLanguageChooser, TranslatableTextElement, TTE, NiceguiTranslatableTextElement, NTTE 141from cengal.parallel_execution.coroutines.coro_tools.await_coro import asyncio_coro 142from cengal.file_system.app_fs_structure.app_dir_path import AppDirPath, AppDirectoryType 143from cengal.file_system.path_manager import RelativePath 144from cengal.web_tools.detect_browsers_host_device_type.by_http_headers import ClientViewType, client_view_type 145from cengal.web_tools.detect_browsers_language.by_http_headers import parse_accept_language, optimize_accept_language, match_langs, normalize_lang 146from cengal.math.numbers import RationalNumber 147from cengal.base.exceptions import CengalError 148from cengal.introspection.inspect import entity_name, entity_repr 149from functools import partial 150from collections import OrderedDict 151from datetime import datetime, timedelta 152from starlette.datastructures import Address, URL 153from starlette.responses import Response, RedirectResponse 154from aioipinfo import IPInfoClient, IPInfoError, IPInfoResponse 155from dataclasses import dataclass 156from contextlib import nullcontext 157import os 158import hashlib 159import logging 160 161 162DESTROY_CS_EVENT = f'DESTROY_CS_EVENT__{uuid4()}' 163CS_PREPARED_FLAG = f'CS_PREPARED_FLAG' 164CS_DESTROY_TIMEOUT = 3.0 165 166 167text_translator: TextTranslator = None 168translation_language_mapper: TranslationLanguageMapper = None 169session_clients: Dict[Hashable, Set[Hashable]] = dict() 170translatable_text_element_per_session: Dict[Hashable, NiceguiTranslatableTextElement] = dict() 171translatable_text_element_per_client: Dict[Hashable, NiceguiTranslatableTextElement] = dict() 172 173known_translation_param_names: Set[str] = {'_t', '_T', '__'} 174known_page_context_param_names: Set[str] = {'page_context', 'pc', 'self'} 175db_env_id: EnvId = 'cengal_nicegui_db_env' 176db_request__logged_in_clients: DbRequest = DbRequest(db_env_id, 'logged_in_clients') 177db_request__user_clients: DbRequest = DbRequest(db_env_id, 'user_clients') 178db_request__logged_in_sessions: DbRequest = DbRequest(db_env_id, 'logged_in_sessions') 179db_request__user_sessions: DbRequest = DbRequest(db_env_id, 'user_sessions') 180db_request__ip_geolocation: DbRequest = DbRequest(db_env_id, 'ip_geolocation') 181db_request__user_sign_in_info: DbRequest = DbRequest(db_env_id, 'user_sign_in_info') 182db_request__credentials_by_user_id: DbRequest = DbRequest(db_env_id, 'credentials_by_user_id') 183db_request__user_sign_up_info: DbRequest = DbRequest(db_env_id, 'user_sign_up_info') 184signed_in_session_timeout: timedelta = timedelta(days=90) 185ipinfo_io_token: str = os.environ.get('CENGAL_NICEGUI__IPINFO_IO_TOKEN', None) 186 187 188class CengalNiceguiException(CengalError): 189 pass 190 191 192class UserNotFoundError(CengalNiceguiException): 193 pass 194 195 196class PasswordIsNotCorrectError(CengalNiceguiException): 197 pass 198 199 200class CoroWrapperNiceGuiPageAsyncAwait(CoroWrapperAsyncAwait): 201 def reinit_for_nicegui(self): 202 self.subtype = self._setup_subtype() 203 self._current_call_method = self._call_method # type: Callable 204 self.original__current_task = None 205 206 def mock__current_task(self, loop=None): 207 return self.current_asyncio_task 208 209 def patch_asyncio_current_task(self): 210 current_task.patch(self.mock__current_task) 211 212 def unpatch_asyncio_current_task(self): 213 current_task.restore() 214 215 def _init_coroutine(self, *init_args, **init_kwargs): 216 try: 217 self.patch_asyncio_current_task() 218 return super()._init_coroutine(*init_args, **init_kwargs) 219 finally: 220 self.unpatch_asyncio_current_task() 221 222 def _call_coroutine(self, *args, **kwargs): 223 try: 224 self.patch_asyncio_current_task() 225 return super()._call_coroutine(*args, **kwargs) 226 finally: 227 self.unpatch_asyncio_current_task() 228 229 def _throw_coroutine(self, ex_type, ex_value=None, ex_traceback=None): 230 try: 231 self.patch_asyncio_current_task() 232 return super()._throw_coroutine(ex_type, ex_value, ex_traceback) 233 finally: 234 self.unpatch_asyncio_current_task() 235 236 def _close_coroutine(self, *args, **kwargs): 237 try: 238 self.patch_asyncio_current_task() 239 return super()._close_coroutine(*args, **kwargs) 240 finally: 241 self.unpatch_asyncio_current_task() 242 243 244class CoroWrapperNiceGuiPageGreenlet(CoroWrapperGreenlet): 245 def reinit_for_nicegui(self): 246 self.subtype = self._setup_subtype() 247 self._current_call_method = self._call_method # type: Callable 248 self.original__current_task = None 249 250 def mock__current_task(self, loop=None): 251 return self.current_asyncio_task 252 253 def patch_asyncio_current_task(self): 254 current_task.patch(self.mock__current_task) 255 256 def unpatch_asyncio_current_task(self): 257 current_task.restore() 258 259 def _init_coroutine(self, *init_args, **init_kwargs): 260 try: 261 self.patch_asyncio_current_task() 262 return super()._init_coroutine(*init_args, **init_kwargs) 263 finally: 264 self.unpatch_asyncio_current_task() 265 266 def _call_coroutine(self, *args, **kwargs): 267 try: 268 self.patch_asyncio_current_task() 269 return super()._call_coroutine(*args, **kwargs) 270 finally: 271 self.unpatch_asyncio_current_task() 272 273 def _throw_coroutine(self, ex_type, ex_value=None, ex_traceback=None): 274 try: 275 self.patch_asyncio_current_task() 276 return super()._throw_coroutine(ex_type, ex_value, ex_traceback) 277 finally: 278 self.unpatch_asyncio_current_task() 279 280 def _close_coroutine(self, *args, **kwargs): 281 try: 282 self.patch_asyncio_current_task() 283 return super()._close_coroutine(*args, **kwargs) 284 finally: 285 self.unpatch_asyncio_current_task() 286 287 288class ClientHandlers: 289 def __init__(self, client: Optional[Client]) -> None: 290 self.client: Optional[Client] = client 291 self.on_connected_handlers: Set[Callable] = set() 292 self.on_disconnected_handlers: Set[Callable] = set() 293 self.is_connected: bool = False 294 self.is_disconnected: bool = False 295 296 @classmethod 297 def check_args_factory(cls, signature: Signature, args, kwargs) -> Optional['ClientHandlers']: 298 client: Optional[Client] = kwargs.get('client', None) 299 if (client is None) or (not isinstance(client, Client)): 300 return None 301 else: 302 return cls.install(client) 303 304 @classmethod 305 def install(cls, client: Client) -> 'ClientHandlers': 306 client_handlers: ClientHandlers = cls(client) 307 client.handlers = client_handlers 308 client.on_connect(client_handlers._on_connected()) 309 client.on_disconnect(client_handlers._on_disconnected()) 310 return client_handlers 311 312 def add_on_connected_handler(self, handler: Callable): 313 if self.is_connected: 314 handler() 315 else: 316 self.on_connected_handlers.add(handler) 317 318 def remove_on_connected_handler(self, handler: Callable): 319 self.on_connected_handlers.discard(handler) 320 321 async def _on_connected(self): 322 on_connected_handlers_buff = tuple(self.on_connected_handlers) 323 self.on_connected_handlers = set() 324 for index, handler in enumerate(on_connected_handlers_buff): 325 try: 326 handler() 327 except: 328 self.on_connected_handlers.update(on_connected_handlers_buff[index + 1:]) 329 create_task(self._on_connected) 330 raise 331 332 def add_on_disconnected_handler(self, handler: Callable): 333 if self.is_disconnected: 334 handler() 335 else: 336 self.on_disconnected_handlers.add(handler) 337 338 def remove_on_disconnected_handler(self, handler: Callable): 339 self.on_disconnected_handlers.discard(handler) 340 341 async def _on_disconnected(self): 342 on_disconnected_handlers_buff = tuple(self.on_disconnected_handlers) 343 self.on_disconnected_handlers = set() 344 for index, handler in enumerate(on_disconnected_handlers_buff): 345 try: 346 handler() 347 except: 348 self.on_disconnected_handlers.update(on_disconnected_handlers_buff[index + 1:]) 349 create_task(self._on_disconnected) 350 raise 351 352 353class PageItems: 354 def __init__(self, client: Optional[Client]) -> None: 355 self.client: Optional[Client] = client 356 self.items: Set[Any] = set() 357 358 @classmethod 359 def check_args_factory(cls, signature: Signature, args, kwargs) -> Optional['PageItems']: 360 client: Optional[Client] = kwargs.get('client', None) 361 if (client is None) or (not isinstance(client, Client)): 362 return None 363 else: 364 return cls.install(client) 365 366 @classmethod 367 def install(cls, client: Client) -> 'PageItems': 368 page_items: PageItems = cls(client) 369 client.page_items = page_items 370 return page_items 371 372 def add(self, item: Any): 373 self.items.add(item) 374 375 def remove(self, item: Any): 376 self.items.discard(item) 377 378 def __call__(self, item: Any) -> Any: 379 return self.add(item) 380 381 382async def get_ip_geolocation(ipinfo_io_token, host): 383 async with IPInfoClient(ipinfo_io_token) as client: 384 try: 385 ip_geolocation = await client.ipinfo_dict(host) 386 if ip_geolocation is not None: 387 await i(db_request__ip_geolocation.put(host)) 388 except IPInfoError: 389 ip_geolocation = None 390 391 return ip_geolocation 392 393 394def nicegui_event_handler_func_async_coro(coro_worker: Worker): 395 """Decorator. Without arguments. Makes a proper, fully functional async Page from any decorated Cengal coroutine 396 397 Args: 398 coro_worker (Worker): _description_ 399 400 Raises: 401 TypeError: _description_ 402 403 Returns: 404 _type_: _description_ 405 """ 406 coro_worker_0 = coro_worker 407 # async def wrapper(*args, **kwargs): 408 async def wrapper(*args, **kwargs): 409 await await_cs_initiated() 410 coro_worker = coro_worker_0 411 app.cs.logger.debug(f'nicegui_event_handler_async_coro.wrapper - start: {entity_name(coro_worker)}') 412 coro_worker_type: CoroType = find_coro_type(coro_worker) 413 if CoroType.awaitable == coro_worker_type: 414 async def awaitable_coro_wrapper(i: Interface, current_asyncio_task, 415 coro_worker_with_args: EntityArgsHolderExplicit): 416 coro_worker, args, kwargs = coro_worker_with_args.entity_args_kwargs() 417 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.awaitable_coro_wrapper - start: {entity_name(coro_worker)}') 418 await apretent_to_be_asyncio_coro(i, current_asyncio_task) 419 # await i(Instance, InstanceRequest().wait(CS_PREPARED_FLAG)) 420 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.awaitable_coro_wrapper - ready: {entity_name(coro_worker)}') 421 return await coro_worker(i, *args, **kwargs) 422 423 coro_wrapper = awaitable_coro_wrapper 424 elif CoroType.greenlet == coro_worker_type: 425 def greenlet_coro_wrapper(i: Interface, current_asyncio_task, 426 coro_worker_with_args: EntityArgsHolderExplicit): 427 coro_worker, args, kwargs = coro_worker_with_args.entity_args_kwargs() 428 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.greenlet_coro_wrapper - start: {entity_name(coro_worker)}') 429 pretent_to_be_asyncio_coro(i, current_asyncio_task) 430 # i(Instance, InstanceRequest().wait(CS_PREPARED_FLAG)) 431 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.greenlet_coro_wrapper - ready: {entity_name(coro_worker)}') 432 return coro_worker(i, *args, **kwargs) 433 434 coro_wrapper = greenlet_coro_wrapper 435 else: 436 raise TypeError(f'{coro_worker} is neither an awaitable nor a greenlet') 437 438 current_asyncio_task = asyncio.current_task() 439 return await await_coro_prim(coro_wrapper, current_asyncio_task, 440 EntityArgsHolderExplicit(coro_worker, args, kwargs)) 441 442 coro_worker_sign: Signature = signature(coro_worker) 443 wrapper_signature = coro_worker_sign.replace(parameters=tuple(coro_worker_sign.parameters.values())[1:], return_annotation=coro_worker_sign.return_annotation) 444 wrapper.__signature__ = wrapper_signature 445 446 return wrapper 447 448 449async_event_handler_func = nicegui_event_handler_func_async_coro 450aevent_handler_func = nicegui_event_handler_func_async_coro 451 452 453def nicegui_event_handler_method_async_coro(coro_worker: Worker): 454 """Decorator. Without arguments. Makes a proper, fully functional async Page from any decorated Cengal coroutine 455 456 Args: 457 coro_worker (Worker): _description_ 458 459 Raises: 460 TypeError: _description_ 461 462 Returns: 463 _type_: _description_ 464 """ 465 coro_worker_0 = coro_worker 466 # async def wrapper(*args, **kwargs): 467 async def wrapper(self, *args, **kwargs): 468 await await_cs_initiated() 469 coro_worker = coro_worker_0 470 coro_worker_name: str = coro_worker.__name__ 471 unwrapped_coro_worker_name: str = f'_unwrapped_method__{coro_worker_name}' 472 if not hasattr(self, unwrapped_coro_worker_name): 473 bound_coro_worker = coro_worker.__get__(self, self.__class__) 474 setattr(self, unwrapped_coro_worker_name, bound_coro_worker) 475 476 coro_worker = getattr(self, unwrapped_coro_worker_name) 477 app.cs.logger.debug(f'nicegui_event_handler_async_coro.wrapper - start: {entity_name(coro_worker)}') 478 coro_worker_type: CoroType = find_coro_type(coro_worker) 479 if CoroType.awaitable == coro_worker_type: 480 async def awaitable_coro_wrapper(i: Interface, current_asyncio_task, 481 coro_worker_with_args: EntityArgsHolderExplicit): 482 coro_worker, args, kwargs = coro_worker_with_args.entity_args_kwargs() 483 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.awaitable_coro_wrapper - start: {entity_name(coro_worker)}') 484 await apretent_to_be_asyncio_coro(i, current_asyncio_task) 485 # await i(Instance, InstanceRequest().wait(CS_PREPARED_FLAG)) 486 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.awaitable_coro_wrapper - ready: {entity_name(coro_worker)}') 487 i.log.debug(f'{entity_repr(coro_worker)}') 488 return await coro_worker(i, *args, **kwargs) 489 490 coro_wrapper = awaitable_coro_wrapper 491 elif CoroType.greenlet == coro_worker_type: 492 def greenlet_coro_wrapper(i: Interface, current_asyncio_task, 493 coro_worker_with_args: EntityArgsHolderExplicit): 494 coro_worker, args, kwargs = coro_worker_with_args.entity_args_kwargs() 495 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.greenlet_coro_wrapper - start: {entity_name(coro_worker)}') 496 pretent_to_be_asyncio_coro(i, current_asyncio_task) 497 # i(Instance, InstanceRequest().wait(CS_PREPARED_FLAG)) 498 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.greenlet_coro_wrapper - ready: {entity_name(coro_worker)}') 499 return coro_worker(i, *args, **kwargs) 500 501 coro_wrapper = greenlet_coro_wrapper 502 else: 503 raise TypeError(f'{coro_worker} is neither an awaitable nor a greenlet') 504 505 current_asyncio_task = asyncio.current_task() 506 return await await_coro_prim(coro_wrapper, current_asyncio_task, 507 EntityArgsHolderExplicit(coro_worker, args, kwargs)) 508 509 coro_worker_sign: Signature = signature(coro_worker) 510 new_parameters = list(coro_worker_sign.parameters.values()) 511 del new_parameters[1] 512 wrapper_signature = coro_worker_sign.replace(parameters=tuple(new_parameters), return_annotation=coro_worker_sign.return_annotation) 513 wrapper.__signature__ = wrapper_signature 514 515 return wrapper 516 517 518async_event_handler_method = nicegui_event_handler_method_async_coro 519aevent_handler_method = nicegui_event_handler_method_async_coro 520 521 522def get_task_slot_stack(task_id) -> List[Slot]: 523 if task_id not in slot_stacks: 524 slot_stacks[task_id] = [] 525 return slot_stacks[task_id] 526 527 528class FakeElementForEvents: 529 def __init__(self, task_id) -> None: 530 self.is_ignoring_events: bool = False 531 self.parent_slot: Union[Slot, nullcontext] = nullcontext() 532 slot_stack = get_task_slot_stack(task_id) 533 if slot_stack: 534 self.parent_slot = slot_stack[-1] 535 536 537@dataclass(**KWONLY_SLOTS) 538class OnSignInEventArguments(UiEventArguments): 539 user_id: Hashable 540 user_sign_in_info: Union[Dict, Tuple, List] 541 542 543@dataclass(**KWONLY_SLOTS) 544class OnSignOutEventArguments(UiEventArguments): 545 user_id: Hashable 546 547 548class PageContextBase: 549 def __init__(self, client: Client, request: FastAPIRequest, _t: NTTE, current_asyncio_task) -> None: 550 self.client: Client = client 551 self.request: FastAPIRequest = request 552 self.client_host_port: Address = self.request.client 553 self.client_id: Hashable = client.id 554 self.session_id: Hashable = client.session_id 555 self.user_id: Hashable = None 556 self._t: NTTE = _t 557 self.current_asyncio_task = current_asyncio_task 558 self.current_asyncio_task_id = id(current_asyncio_task) 559 self.client_view_type: ClientViewType = self._determine_client_view_type() 560 self.better_lang: str = None 561 self.featured_langs: OrderedDict[str, RationalNumber] = None 562 self.langs: OrderedDict[str, RationalNumber] = None 563 self.better_lang, self.featured_langs, self.langs = self._determine_client_languages() 564 self._t.text_translation_language_chooser.lang = self.better_lang 565 566 def _init(self, i: Interface): 567 self.register_session_page(i) 568 i(PutCoro, self._arequest_ip_geolocation, self.client_host_port[0]) 569 if self._find_user(i): 570 i.log.debug(f'{self.session_id}, {self.client_id}: logged in') 571 else: 572 i.log.debug(f'{self.session_id}, {self.client_id}: logged out') 573 574 async def _ainit(self, i: Interface): 575 self.register_session_page(i) 576 await i(PutCoro, self._arequest_ip_geolocation, self.client_host_port[0]) 577 if await self._afind_user(i): 578 i.log.debug(f'{self.session_id}, {self.client_id}: logged in') 579 else: 580 i.log.debug(f'{self.session_id}, {self.client_id}: logged out') 581 582 async def _arequest_ip_geolocation(self, i: Interface, host: str): 583 ip_geolocation: Optional[Dict] = None 584 need_to_request: bool = True 585 try: 586 ip_geolocation = await i(db_request__ip_geolocation.get(host)) 587 need_to_request = False 588 except KeyError: 589 pass 590 591 if need_to_request: 592 ip_geolocation = await i(AsyncioLoop, AsyncioLoopRequest().wait(get_ip_geolocation(ipinfo_io_token, host))) 593 594 await self.on_ip_geolocation_ready(i, ip_geolocation) 595 596 def register_session_page(self, i: Interface): 597 session_pages: Dict[Hashable, Set[PageContextBase]] = fast_get_explicit(i, 'cengal_nicegui__session_pages') 598 if self.session_id not in session_pages: 599 session_pages[self.session_id] = set() 600 601 session_pages[self.session_id].add(self) 602 603 def _determine_client_view_type(self) -> ClientViewType: 604 return client_view_type(self.request.headers) 605 606 def _determine_client_languages(self): 607 parsed_accept_language: Optional[OrderedDict[str, RationalNumber]] = optimize_accept_language(parse_accept_language(self.request.headers)) 608 translation_data: Dict = self._t.text_translator.decoded_data 609 return match_langs( 610 translation_data['default_language'], 611 set(translation_data['featured_languages']), 612 set(translation_data['supported_languages']), 613 translation_data['translation_language_map'], 614 parsed_accept_language, 615 ) 616 617 def _find_user(self, i: Interface) -> bool: 618 if self.session_id is None: 619 return False 620 621 try: 622 user_id, sign_in_date_time = i(db_request__logged_in_sessions.get(self.session_id)) 623 sign_in_date_time = datetime.fromisoformat(sign_in_date_time) 624 if (datetime.now() - sign_in_date_time) > signed_in_session_timeout: 625 i(db_request__logged_in_sessions.delete(self.session_id)) 626 return False 627 628 self.user_id = user_id 629 return True 630 except KeyError: 631 return False 632 633 async def _afind_user(self, i: Interface) -> bool: 634 if self.session_id is None: 635 return False 636 637 try: 638 user_id, sign_in_date_time = await i(db_request__logged_in_sessions.get(self.session_id)) 639 sign_in_date_time = datetime.fromisoformat(sign_in_date_time) 640 if (datetime.now() - sign_in_date_time) > signed_in_session_timeout: 641 await i(db_request__logged_in_sessions.delete(self.session_id)) 642 return False 643 644 self.user_id = user_id 645 return True 646 except KeyError: 647 return False 648 649 # def find_user(self, i: Interface, client_connection_check_interval: RationalNumber = 0.01) -> bool: 650 # if not self.client.has_socket_connection: 651 # if not self.client.is_waiting_for_connection: 652 # i(AsyncioLoop, AsyncioLoopRequest().wait(self.client.connected())) 653 654 # while self.client.is_waiting_for_connection: 655 # i(Sleep, client_connection_check_interval) 656 657 # return self._find_user(i) 658 659 # async def afind_user(self, i: Interface, client_connection_check_interval: RationalNumber = 0.01) -> bool: 660 # if not self.client.has_socket_connection: 661 # if not self.client.is_waiting_for_connection: 662 # await i(AsyncioLoop, AsyncioLoopRequest().wait(self.client.connected())) 663 664 # while self.client.is_waiting_for_connection: 665 # await i(Sleep, client_connection_check_interval) 666 667 # return await self._afind_user(i) 668 669 def try_sign_in(self, i: Interface, credentials: Union[Dict, Tuple, List, str, bytes, int, float]) -> Optional[Union[Dict, Tuple, List]]: 670 user_data: Union[Dict, Tuple, List] = None 671 672 try: 673 user_data = i(db_request__user_sign_in_info.get(credentials)) 674 except KeyError: 675 pass 676 677 if user_data is None: 678 return None 679 680 user_id = user_data[0] 681 if self.session_id is None: 682 i(db_request__logged_in_clients.put(self.client_id, (user_id, datetime.now()))) 683 user_clients_lock: Lock = fast_get_explicit(i, 'cengal_nicegui__user_clients_lock') 684 with user_clients_lock: 685 try: 686 user_clients: Set[Hashable] = set(i(db_request__user_clients.get(user_id))) 687 except KeyError: 688 user_clients = set() 689 690 user_clients.add(self.client_id) 691 i(db_request__user_sessions.put(user_id, user_clients)) 692 693 i(PutCoro, self._on_signed_in, user_id) 694 else: 695 i(db_request__logged_in_sessions.put(self.session_id, (user_id, datetime.now()))) 696 user_sessions_lock: Lock = fast_get_explicit(i, 'cengal_nicegui__user_sessions_lock') 697 with user_sessions_lock: 698 try: 699 user_sessions: Set[Hashable] = set(i(db_request__user_sessions.get(user_id))) 700 except KeyError: 701 user_sessions = set() 702 703 user_sessions.add(self.session_id) 704 i(db_request__user_sessions.put(user_id, user_sessions)) 705 706 session_pages: Dict[Hashable, Set[PageContextBase]] = fast_get_explicit(i, 'cengal_nicegui__session_pages') 707 current_session_pages: Set[PageContextBase] = session_pages.get(self.session_id, set()) 708 for session_page in current_session_pages: 709 i(PutCoro, session_page._on_signed_in, user_id, user_data) 710 711 return user_data 712 713 async def atry_sign_in(self, i: Interface, credentials: Union[Dict, Tuple, List, str, bytes, int, float]) -> Optional[Union[Dict, Tuple, List]]: 714 user_data: Union[Dict, Tuple, List] = None 715 716 try: 717 user_data = await i(db_request__user_sign_in_info.get(credentials)) 718 except KeyError: 719 pass 720 721 if user_data is None: 722 return None 723 724 user_id = user_data[0] 725 if self.session_id is None: 726 await i(db_request__logged_in_clients.put(self.client_id, (user_id, datetime.now()))) 727 user_clients_lock: Lock = fast_get_explicit(i, 'cengal_nicegui__user_clients_lock') 728 async with user_clients_lock: 729 try: 730 user_clients: Set[Hashable] = set(await i(db_request__user_clients.get(user_id))) 731 except KeyError: 732 user_clients = set() 733 734 user_clients.add(self.client_id) 735 await i(db_request__user_sessions.put(user_id, user_clients)) 736 737 await i(PutCoro, self._on_signed_in, user_id) 738 else: 739 await i(db_request__logged_in_sessions.put(self.session_id, (user_id, datetime.now()))) 740 user_sessions_lock: Lock = fast_get_explicit(i, 'cengal_nicegui__user_sessions_lock') 741 async with user_sessions_lock: 742 try: 743 user_sessions: Set[Hashable] = set(await i(db_request__user_sessions.get(user_id))) 744 except KeyError: 745 user_sessions = set() 746 747 user_sessions.add(self.session_id) 748 await i(db_request__user_sessions.put(user_id, user_sessions)) 749 750 session_pages: Dict[Hashable, Set[PageContextBase]] = fast_get_explicit(i, 'cengal_nicegui__session_pages') 751 current_session_pages: Set[PageContextBase] = set(session_pages.get(self.session_id, set())) # TODO: robust fix needed for `RuntimeError: Set changed size during iteration` 752 for session_page in current_session_pages: 753 await i(PutCoro, session_page._on_signed_in, user_id, user_data) 754 755 return user_data 756 757 def user_signed_up(self, i: Interface, credentials: Union[Dict, Tuple, List, str, bytes, int, float], 758 user_sign_in_info: Union[Dict, Tuple, List]): 759 i(db_request__user_sign_in_info.put(credentials, user_sign_in_info)) 760 761 async def auser_signed_up(self, i: Interface, credentials: Union[Dict, Tuple, List, str, bytes, int, float], 762 user_sign_in_info: Union[Dict, Tuple, List]): 763 await i(db_request__user_sign_in_info.put(credentials, user_sign_in_info)) 764 765 def sign_out(self, i: Interface) -> bool: 766 user_id = self.user_id 767 if user_id is None: 768 return False 769 770 if self.session_id is None: 771 try: 772 i(db_request__logged_in_clients.delete(self.client_id)) 773 except KeyError: 774 pass 775 776 i(PutCoro, self._on_signed_out) 777 return True 778 else: 779 try: 780 i(db_request__logged_in_sessions.delete(self.session_id)) 781 except KeyError: 782 pass 783 784 session_pages: Dict[Hashable, Set[PageContextBase]] = fast_get_explicit(i, 'cengal_nicegui__session_pages') 785 current_session_pages: Set[PageContextBase] = session_pages.get(self.session_id, set()) 786 for session_page in current_session_pages: 787 i(PutCoro, session_page._on_signed_out) 788 789 return True 790 791 async def asign_out(self, i: Interface) -> bool: 792 user_id = self.user_id 793 if user_id is None: 794 return False 795 796 if self.session_id is None: 797 try: 798 await i(db_request__logged_in_clients.delete(self.client_id)) 799 except KeyError: 800 pass 801 802 user_clients_lock: Lock = fast_get_explicit(i, 'cengal_nicegui__user_clients_lock') 803 async with user_clients_lock: 804 try: 805 user_clients: Set[Hashable] = set(await i(db_request__user_clients.get(user_id))) 806 except KeyError: 807 user_clients = set() 808 809 user_clients.discard(self.client_id) 810 await i(db_request__user_sessions.put(user_id, user_clients)) 811 812 await i(PutCoro, self._on_signed_out) 813 return True 814 else: 815 try: 816 await i(db_request__logged_in_sessions.delete(self.session_id)) 817 except KeyError: 818 pass 819 820 user_sessions_lock: Lock = fast_get_explicit(i, 'cengal_nicegui__user_sessions_lock') 821 async with user_sessions_lock: 822 try: 823 user_sessions: Set[Hashable] = set(await i(db_request__user_sessions.get(user_id))) 824 except KeyError: 825 user_sessions = set() 826 827 user_sessions.discard(self.session_id) 828 await i(db_request__user_sessions.put(user_id, user_sessions)) 829 830 session_pages: Dict[Hashable, Set[PageContextBase]] = fast_get_explicit(i, 'cengal_nicegui__session_pages') 831 current_session_pages: Set[PageContextBase] = session_pages.get(self.session_id, set()) 832 for session_page in current_session_pages: 833 await i(PutCoro, session_page._on_signed_out) 834 835 return True 836 837 def try_sign_up__login_password(self, i: Interface, login: str, password: str, 838 user_sign_in_info_maker: Callable[[Interface, str, Hashable, datetime], Union[Dict, Tuple, List]]) -> bool: 839 login_exists: bool = False 840 try: 841 i(db_request__user_sign_up_info.get(login)) 842 login_exists = True 843 except KeyError: 844 pass 845 846 if login_exists: 847 return False 848 849 password_bytes = password.encode('utf-8') 850 salt = os.urandom(16) 851 key_length = 64 852 N = 16384 # CPU/memory cost factor 853 r = 8 # Block size 854 p = 1 # Parallelization factor 855 dk = hashlib.scrypt(password_bytes, salt=salt, n=N, r=r, p=p, dklen=key_length) 856 i(db_request__user_sign_up_info.put(login, (dk, salt, N, r, p, key_length))) 857 user_id: Hashable = uuid4() 858 credentials: Tuple = (login, dk) 859 i(db_request__credentials_by_user_id.put(user_id, credentials)) 860 user_sign_in_info: Union[Dict, Tuple, List] = run_coro_fast(i, user_sign_in_info_maker, login, user_id, datetime.now()) 861 self.user_signed_up(i, credentials, user_sign_in_info) 862 return True 863 864 async def atry_sign_up__login_password(self, i: Interface, login: str, password: str, 865 user_sign_in_info_maker: Callable[[Interface, str, Hashable, datetime], Union[Dict, Tuple, List]]) -> bool: 866 login_exists: bool = False 867 try: 868 await i(db_request__user_sign_up_info.get(login)) 869 login_exists = True 870 except KeyError: 871 pass 872 873 if login_exists: 874 return False 875 876 password_bytes = password.encode('utf-8') 877 salt = os.urandom(16) 878 key_length = 64 879 N = 16384 # CPU/memory cost factor 880 r = 8 # Block size 881 p = 1 # Parallelization factor 882 dk = hashlib.scrypt(password_bytes, salt=salt, n=N, r=r, p=p, dklen=key_length) 883 await i(db_request__user_sign_up_info.put(login, (dk, salt, N, r, p, key_length))) 884 user_id: Hashable = uuid4().bytes 885 credentials: Tuple = (login, dk) 886 await i(db_request__credentials_by_user_id.put(user_id, credentials)) 887 user_sign_in_info: Union[Dict, Tuple, List] = await arun_coro_fast(i, user_sign_in_info_maker, login, user_id, datetime.now()) 888 await self.auser_signed_up(i, credentials, user_sign_in_info) 889 return True 890 891 def try_sign_in__login_password(self, i: Interface, login: str, password: str) -> Union[Dict, Tuple, List]: 892 user_found: bool = False 893 try: 894 dk, salt, N, r, p, key_length = i(db_request__user_sign_up_info.get(login)) 895 user_found = True 896 except KeyError: 897 pass 898 899 if not user_found: 900 raise UserNotFoundError 901 902 password_bytes = password.encode('utf-8') 903 dk_0 = hashlib.scrypt(password_bytes, salt=salt, n=N, r=r, p=p, dklen=key_length) 904 if dk != dk_0: 905 raise PasswordIsNotCorrectError 906 907 credentials: Tuple = (login, dk) 908 return self.try_sign_in(i, credentials) 909 910 async def atry_sign_in__login_password(self, i: Interface, login: str, password: str) -> Union[Dict, Tuple, List]: 911 user_found: bool = False 912 try: 913 dk, salt, N, r, p, key_length = await i(db_request__user_sign_up_info.get(login)) 914 user_found = True 915 except KeyError: 916 pass 917 918 if not user_found: 919 raise UserNotFoundError 920 921 password_bytes = password.encode('utf-8') 922 dk_0 = hashlib.scrypt(password_bytes, salt=salt, n=N, r=r, p=p, dklen=key_length) 923 if dk != dk_0: 924 raise PasswordIsNotCorrectError 925 926 credentials: Tuple = (login, dk) 927 return await self.atry_sign_in(i, credentials) 928 929 def try_sign_up__email_password(self, i: Interface, email: str, password: str) -> bool: 930 raise NotImplementedError 931 932 async def atry_sign_up__email_password(self, i: Interface, email: str, password: str) -> bool: 933 raise NotImplementedError 934 935 async def _on_signed_in(self, i: Interface, user_id: Hashable, user_sign_in_info: Union[Dict, Tuple, List]) -> None: 936 self.user_id = user_id 937 handle_event(self._on_signed_in_impl, OnSignInEventArguments(sender=FakeElementForEvents(self.current_asyncio_task_id), client=self.client, user_id=user_id, user_sign_in_info=user_sign_in_info)) 938 939 @aevent_handler_method 940 async def _on_signed_in_impl(self, i: Interface, arguments: OnSignInEventArguments) -> None: 941 return await self.on_signed_in(i, arguments.user_id, arguments.user_sign_in_info) 942 943 async def on_signed_in(self, i: Interface, user_id: Hashable, user_sign_in_info: Union[Dict, Tuple, List]) -> None: 944 pass 945 946 async def _on_signed_out(self, i: Interface) -> None: 947 user_id = self.user_id 948 self.user_id = None 949 handle_event(self._on_signed_out_impl, OnSignOutEventArguments(sender=FakeElementForEvents(self.current_asyncio_task_id), client=self.client, user_id=user_id)) 950 951 @aevent_handler_method 952 async def _on_signed_out_impl(self, i: Interface, arguments: OnSignOutEventArguments) -> None: 953 return await self.on_signed_out(i, arguments.user_id) 954 955 async def on_signed_out(self, i: Interface, user_id: Hashable) -> None: 956 pass 957 958 async def on_ip_geolocation_ready(self, i: Interface, ip_geolocation: Optional[Dict]) -> None: 959 pass 960 961 def refferer(self) -> Optional[str]: 962 return self.request.headers.get('referer', None) 963 964 def url(self) -> URL: 965 return self.request.url 966 967 def open_page(self, target: Optional[Union[Callable[..., Any], str]] = None, new_tab: bool = False) -> Optional[RedirectResponse]: 968 if target is None: 969 return 970 971 client = self.client 972 if client.has_socket_connection: 973 client.open(target, new_tab) 974 else: 975 return RedirectResponse(target) 976 977 def open_previous_page(self, default_target: Optional[Union[Callable[..., Any], str]] = None, new_tab: bool = False, can_be_current_page: bool = False) -> Optional[RedirectResponse]: 978 target: str = self.refferer() 979 current_url: str = str(self.url()) 980 if (target is None) or (False if can_be_current_page else (target == current_url)): 981 if not isinstance(default_target, str): 982 default_target = globals.page_routes[target] 983 984 target = default_target if default_target is not None else '/' 985 986 client = self.client 987 if client.has_socket_connection: 988 client.open(target, new_tab) 989 else: 990 return self.open_previous_page_http_response(default_target, can_be_current_page) 991 992 def open_previous_page_http_response(self, default_target: Optional[Union[Callable[..., Any], str]] = None, can_be_current_page: bool = False) -> RedirectResponse: 993 refferer: str = self.refferer() 994 current_url: str = str(self.url()) 995 if (refferer is None) or (False if can_be_current_page else (refferer == current_url)): 996 refferer = default_target if default_target is not None else '/' 997 998 return RedirectResponse(refferer) 999 1000 1001def nicegui_page_sync_coro(*dargs, **dkwargs): 1002 """Decorator. With an arguments. Gives ability to execute any decorated Cengal coroutine based page as a sync function. 1003 Can postpone execution to the actual loop when possible if None as an immediate result (no result) is acceptible. 1004 Can start own loop if needed. See sync_coro_param() decorator from cengal/parallel_execution/coroutines/coro_tools/wait_coro for more details 1005 1006 Returns: 1007 _type_: _description_ 1008 """ 1009 dargs_0 = dargs 1010 dkwargs_0 = dkwargs 1011 def nicegui_page_sync_coro_impl(coro_worker: Worker): 1012 coro_worker_0 = coro_worker 1013 dargs_1 = dargs_0 1014 dkwargs_1 = dkwargs_0 1015 def wrapper(*args, **kwargs): 1016 coro_worker = coro_worker_0 1017 dargs = dargs_1 1018 dkwargs = dkwargs_1 1019 sync_coro_decorator = sync_coro_param(*dargs, **dkwargs) 1020 sync_coro_decorator_wrapper = sync_coro_decorator(coro_worker) 1021 ClientHandlers.check_args_factory(wrapper_signature, args, kwargs) 1022 PageItems.check_args_factory(wrapper_signature, args, kwargs) 1023 return sync_coro_decorator_wrapper(*args, **kwargs) 1024 1025 coro_worker_sign: Signature = signature(coro_worker) 1026 wrapper_signature = coro_worker_sign.replace(parameters=tuple(coro_worker_sign.parameters.values())[1:], return_annotation=coro_worker_sign.return_annotation) 1027 wrapper.__signature__ = wrapper_signature 1028 1029 return wrapper 1030 return nicegui_page_sync_coro_impl 1031 1032 1033sync_like_page = nicegui_page_sync_coro 1034sl_page = nicegui_page_sync_coro 1035 1036 1037async def await_cs_initiated(): 1038 while (not hasattr(app, 'cs_initiated')) or (not app.cs_initiated): 1039 await asyncio.sleep(0.01) 1040 1041 1042async def apretent_to_be_asyncio_coro(i: Interface, asyncio_coro): 1043 reinterpret_cast(CoroWrapperNiceGuiPageAsyncAwait, i._coro) 1044 i._coro.current_asyncio_task = asyncio_coro 1045 i._coro.reinit_for_nicegui() 1046 await i(Yield) 1047 1048 1049def pretent_to_be_asyncio_coro(i: Interface, asyncio_coro): 1050 reinterpret_cast(CoroWrapperNiceGuiPageGreenlet, i._coro) 1051 i._coro.current_asyncio_task = asyncio_coro 1052 i._coro.reinit_for_nicegui() 1053 i(Yield) 1054 1055 1056def nicegui_page_async_coro_impl(page_class: Optional[Union[PageContextBase, EntityArgsHolder]], coro_worker: Worker): 1057 """Decorator. Without arguments. Makes a proper, fully functional async Page from any decorated Cengal coroutine 1058 1059 Args: 1060 coro_worker (Worker): _description_ 1061 1062 Raises: 1063 TypeError: _description_ 1064 1065 Returns: 1066 _type_: _description_ 1067 """ 1068 coro_worker_0 = coro_worker 1069 page_class_0 = page_class 1070 # async def wrapper(*args, **kwargs): 1071 async def wrapper(request: FastAPIRequest, client: Client): 1072 await await_cs_initiated() 1073 request.app.cs.logger.debug(f'nicegui_page_async_coro_impl.wrapper - start: {request.url}') 1074 client_id = client.id 1075 session_id = request.session.get('id', None) 1076 client.session_id = session_id 1077 if session_id not in session_clients: 1078 session_clients[session_id] = set() 1079 1080 session_clients[session_id].add(client_id) 1081 1082 if session_id is None: 1083 translatable_text_element: NiceguiTranslatableTextElement = create_translatable_text_element(text_translator, translation_language_mapper) 1084 # translatable_text_element: NiceguiTranslatableTextElement = create_translatable_text_element( 1085 # await asyncio_coro(cs_acoro(afast_wait))('text_translator'), await asyncio_coro(cs_acoro(afast_wait))('translation_language_mapper') 1086 # ) 1087 translatable_text_element_per_client[client_id] = translatable_text_element 1088 else: 1089 if session_id in translatable_text_element_per_session: 1090 translatable_text_element = translatable_text_element_per_session[session_id] 1091 else: 1092 translatable_text_element: NiceguiTranslatableTextElement = create_translatable_text_element(text_translator, translation_language_mapper) 1093 # translatable_text_element: NiceguiTranslatableTextElement = create_translatable_text_element( 1094 # await asyncio_coro(cs_acoro(afast_wait))('text_translator'), await asyncio_coro(cs_acoro(afast_wait))('translation_language_mapper') 1095 # ) 1096 translatable_text_element_per_session[session_id] = translatable_text_element 1097 1098 client.translatable_text_element = translatable_text_element 1099 await asyncio_coro(cs_acoro(translatable_text_element.aregister_on_lang_changed_handler))() 1100 coro_worker = coro_worker_0 1101 coro_worker_type: CoroType = find_coro_type(coro_worker) 1102 if CoroType.awaitable == coro_worker_type: 1103 async def awaitable_coro_wrapper(i: Interface, current_asyncio_task, wrapper_signature, 1104 coro_worker_with_args: EntityArgsHolderExplicit, page_context: PageContextBase): 1105 coro_worker, args, kwargs = coro_worker_with_args.entity_args_kwargs() 1106 i.log.debug(f'awaitable_coro_wrapper - start: {entity_name(coro_worker)}') 1107 await apretent_to_be_asyncio_coro(i, current_asyncio_task) 1108 ClientHandlers.check_args_factory(wrapper_signature, args, kwargs) 1109 PageItems.check_args_factory(wrapper_signature, args, kwargs) 1110 # await i(Instance, InstanceRequest().wait(CS_PREPARED_FLAG)) 1111 await page_context._ainit(i) 1112 i.log.debug(f'awaitable_coro_wrapper - ready: {entity_name(coro_worker)}') 1113 return await coro_worker(i, *args, **kwargs) 1114 1115 coro_wrapper = awaitable_coro_wrapper 1116 elif CoroType.greenlet == coro_worker_type: 1117 def greenlet_coro_wrapper(i: Interface, current_asyncio_task, wrapper_signature, 1118 coro_worker_with_args: EntityArgsHolderExplicit, page_context: PageContextBase): 1119 coro_worker, args, kwargs = coro_worker_with_args.entity_args_kwargs() 1120 i.log.debug(f'greenlet_coro_wrapper - start: {entity_name(coro_worker)}') 1121 pretent_to_be_asyncio_coro(i, current_asyncio_task) 1122 ClientHandlers.check_args_factory(wrapper_signature, args, kwargs) 1123 PageItems.check_args_factory(wrapper_signature, args, kwargs) 1124 # i(Instance, InstanceRequest().wait(CS_PREPARED_FLAG)) 1125 page_context._init(i) 1126 i.log.debug(f'greenlet_coro_wrapper - ready: {entity_name(coro_worker)}') 1127 return coro_worker(i, *args, **kwargs) 1128 1129 coro_wrapper = greenlet_coro_wrapper 1130 else: 1131 raise TypeError(f'{coro_worker} is neither an awaitable nor a greenlet') 1132 1133 current_asyncio_task = asyncio.current_task() 1134 # args_kwargs: Optional[Tuple[Tuple, Dict]] = dict().get('args_kwargs', None) 1135 # if args_kwargs is None: 1136 # args_kwargs = (tuple(), dict()) 1137 1138 args = tuple() 1139 kwargs = dict() 1140 coro_worker_param_names_set: Set[str] = set(inspect.signature(coro_worker).parameters.keys()) 1141 if 'client' in coro_worker_param_names_set: 1142 kwargs['client'] = client 1143 1144 if 'request' in coro_worker_param_names_set: 1145 kwargs['request'] = request 1146 1147 translation_params: Set[str] = known_translation_param_names & coro_worker_param_names_set 1148 if translation_params: 1149 for translation_param in translation_params: 1150 kwargs[translation_param] = translatable_text_element 1151 1152 page_context_params: Set[str] = known_page_context_param_names & coro_worker_param_names_set 1153 if page_context_params: 1154 page_class = page_class_0 1155 if isclass(page_class): 1156 if issubclass(page_class, PageContextBase): 1157 page_context: PageContextBase = page_class(client, request, translatable_text_element, current_asyncio_task) 1158 else: 1159 raise TypeError(f'{page_class} is not a subclass of PageContextBase') 1160 elif isinstance(page_class, EntityArgsHolder): 1161 page_class = cast(EntityArgsHolder, page_class) 1162 page_class, page_class_own_args, page_class_own_kwargs = page_class.entity_args_kwargs() 1163 page_class_own_kwargs.update({ 1164 'client': client, 1165 'request': request, 1166 '_t': translatable_text_element, 1167 'current_asyncio_task': current_asyncio_task, 1168 }) 1169 page_context = page_class(*page_class_own_args, **page_class_own_kwargs) 1170 else: 1171 raise TypeError(f'{page_class} is not a subclass of PageContextBase nor an EntityArgsHolder') 1172 1173 for page_context_param in page_context_params: 1174 kwargs[page_context_param] = page_context 1175 1176 return await await_coro_prim(coro_wrapper, current_asyncio_task, wrapper_signature, 1177 EntityArgsHolderExplicit(coro_worker, args, kwargs), page_context) 1178 1179 wrapper_sign: Signature = signature(wrapper) 1180 coro_worker_sign: Signature = signature(coro_worker) 1181 # wrapper_signature = coro_worker_sign.replace(parameters=tuple(coro_worker_sign.parameters.values())[1:], return_annotation=coro_worker_sign.return_annotation) 1182 wrapper_signature = coro_worker_sign.replace(parameters=wrapper_sign.parameters.values(), return_annotation=coro_worker_sign.return_annotation) 1183 wrapper.__signature__ = wrapper_signature 1184 1185 return wrapper 1186 1187 1188nicegui_page_async_coro = partial(nicegui_page_async_coro_impl, None) 1189 1190 1191async_page = nicegui_page_async_coro 1192apage = nicegui_page_async_coro 1193 1194 1195def nicegui_page_class_async_coro(page_class: Optional[Union[PageContextBase, EntityArgsHolder]] = PageContextBase): 1196 return partial(nicegui_page_async_coro_impl, page_class) 1197 1198 1199async_page_class = nicegui_page_class_async_coro 1200apage_class = nicegui_page_class_async_coro 1201 1202 1203async def init_cs(is_fast_loop: bool = True, main_coro: AnyWorker = None, app_args_kwargs = None): 1204 async def coro(i: Interface, main_coro: AnyWorker = None, app_args_kwargs = None): 1205 set_primary_coro_scheduler(i._loop) 1206 app.cs = i._loop 1207 app.cs_initiated = False 1208 app_name: str = app_args_kwargs[1]['app_name'] 1209 app_name_for_fs: str = app_args_kwargs[1]['app_name_for_fs'] 1210 app_version: str = app_args_kwargs[1]['app_version'] 1211 app_version_str: str = app_args_kwargs[1]['app_version_str'] 1212 1213 await i(Instance, InstanceRequest().set('app_name', app_name)) 1214 await i(Instance, InstanceRequest().set('app_name_for_fs', app_name_for_fs)) 1215 await i(Instance, InstanceRequest().set('app_version', app_version)) 1216 await i(Instance, InstanceRequest().set('app_version_str', app_version_str)) 1217 1218 i.log.setLevel(logging.INFO) 1219 await i(LogRequest().sync()) 1220 i.log.debug('cengal.nicegui.init_cs - start') 1221 await i(AsyncioLoop, AsyncioLoopRequest().inherit_surrounding_loop()) 1222 await i(AsyncioLoop, AsyncioLoopRequest().turn_on_loops_intercommunication(True)) 1223 await i(ShutdownOnKeyboardInterrupt) 1224 await i(Instance, InstanceRequest().set('cengal_nicegui__app', app)) 1225 await i(Instance, InstanceRequest().set('cengal_nicegui__app_args_kwargs', app_args_kwargs)) 1226 1227 db_env_info: EnvInfo = await i(DbRequest().open_db_environment(db_env_id, None, False, max_dbs=20)) 1228 await i(DbRequest(env_id=db_env_id).open_databases({ 1229 'logged_in_clients', 1230 'user_clients', 1231 'logged_in_sessions', 1232 'user_sessions', 1233 'ip_geolocation', 1234 'user_sign_in_info', 1235 'credentials_by_user_id', 1236 'user_sign_up_info', 1237 })) 1238 await i(Instance, InstanceRequest().set('cengal_nicegui__db_env_info', db_env_info)) 1239 await i(Instance, InstanceRequest().set('cengal_nicegui__session_pages', dict())) 1240 await i(Instance, InstanceRequest().set('cengal_nicegui__user_clients_lock', Lock(f'cengal_nicegui__user_clients_lock__{uuid4()}'))) 1241 await i(Instance, InstanceRequest().set('cengal_nicegui__user_sessions_lock', Lock(f'cengal_nicegui__user_sessions_lock__{uuid4()}'))) 1242 1243 # await init_translation(i, app_args_kwargs) 1244 if main_coro is not None: 1245 await i(PutCoro, main_coro, app_args_kwargs) 1246 1247 app.cs_initiated = True 1248 i.log.debug('cengal.nicegui.init_cs - ready') 1249 await i(Instance, InstanceRequest().set(CS_PREPARED_FLAG, True)) 1250 try: 1251 await i(AsyncEventBus, AsyncEventBusRequest().wait(DESTROY_CS_EVENT)) 1252 finally: 1253 await i(DbRequest().close_db_environment(db_env_id)) 1254 i.log.debug('cengal.nicegui.init_cs - shutting down loop') 1255 await i(ShutdownLoop) 1256 1257 if is_fast_loop: 1258 await arun_in_fast_loop(coro, main_coro, app_args_kwargs) 1259 else: 1260 await arun_in_loop(coro, main_coro, app_args_kwargs) 1261 1262 1263# # Async on_destroy handling is currently (08 Feb 2023) broken in NiceGUI: 1264# # they should await for handlers instead of current tasks creation approach 1265# async def destroy_cs(): 1266# async def coro(i: Interface): 1267# await i(AsyncEventBus, AsyncEventBusRequest().send_event(DESTROY_CS_EVENT, None)) 1268# await i(Sleep, CS_DESTROY_TIMEOUT) 1269 1270# await await_coro_prim(coro) 1271 1272 1273# Async on_destroy handling is currently (08 Feb 2023) broken in NiceGUI: 1274# they should await for handlers instead of current tasks creation approach 1275def destroy_cs(): 1276 cs: CoroSchedulerType = get_available_coro_scheduler() 1277 cs_destroy_timeouted: bool = False 1278 if cs and (not cs._destroyed): 1279 async def coro(i: Interface): 1280 await i(AsyncEventBus, AsyncEventBusRequest().send_event(DESTROY_CS_EVENT, None)) 1281 1282 put_coro_to(get_interface_and_loop_with_explicit_loop(cs), coro) 1283 start_time = perf_counter() 1284 while cs.iteration(): 1285 if (perf_counter() - start_time) >= CS_DESTROY_TIMEOUT: 1286 cs_destroy_timeouted = True 1287 break 1288 1289 if cs_destroy_timeouted: 1290 warnings.warn(f'destroy_cs - not finished within timeout of {CS_DESTROY_TIMEOUT} sec.') 1291 1292 1293@asyncio_coro 1294async def on_disconnect_handler(i: Interface, client: Client): 1295 client_id = client.id 1296 if hasattr(client, 'session_id'): 1297 session_id = client.session_id 1298 else: 1299 session_id = None 1300 1301 if session_id is None: 1302 translatable_text_element: NiceguiTranslatableTextElement = translatable_text_element_per_client.pop(client_id, None) 1303 else: 1304 translatable_text_element = translatable_text_element_per_session.pop(session_id, None) 1305 1306 if hasattr(client, 'translatable_text_element'): 1307 if translatable_text_element is None: 1308 translatable_text_element = client.translatable_text_element 1309 1310 delattr(client, 'translatable_text_element') 1311 1312 if translatable_text_element is not None: 1313 await translatable_text_element.aremove_on_lang_changed_handler() 1314 1315 if session_id is not None: 1316 session_clients[session_id].discard(client_id) 1317 if not session_clients[session_id]: 1318 session_clients.pop(session_id, None) 1319 1320 1321async def init_translation(i: Interface, app_args_kwargs: Tuple[Tuple, Dict]): 1322 await i(ShutdownOnKeyboardInterrupt) 1323 app_dir_path: AppDirPath = await i(Instance, InstanceRequest().get(AppDirPath)) 1324 app_data_dir_path_type: str = await i(Instance, InstanceRequest().get('app_data_dir_path_type')) 1325 app_name_for_fs: str = await i(Instance, InstanceRequest().get('app_name_for_fs')) 1326 app_name_for_fs = app_name_for_fs if app_name_for_fs else app_args_kwargs[1]['app_name_for_fs'] 1327 app_data_dir_path_rel: RelativePath = RelativePath(app_dir_path(app_data_dir_path_type, app_name_for_fs)) 1328 global text_translator 1329 global translation_language_mapper 1330 text_translator, translation_language_mapper = setup_translation(app_data_dir_path_rel('text_dictionary.json')) 1331 await i(Instance, InstanceRequest().set('cengal_nicegui__text_translator', text_translator)) 1332 await i(Instance, InstanceRequest().set('cengal_nicegui__translation_language_mapper', translation_language_mapper)) 1333 1334 1335def run(*, 1336 host: str = '0.0.0.0', 1337 port_or_range: Union[int, slice, Tuple[int, int]] = 8080, 1338 main_coro: AnyWorker = None, 1339 is_fast_loop: bool = True, 1340 app_name: str = str(), 1341 app_name_for_fs: str = str(), 1342 app_version: Tuple[int, int, int, Union[int, str]] = tuple(), 1343 app_version_str: str = str(), 1344 **kwargs 1345 ) -> None: 1346 """Prepares and starts NiceGUI. Saves initial args and kwargs parameters (as well as determined free port) into a tuple (Tuple[Tuple, Dict]) within an Instance service awailable by a 'cengal_nicegui__app_args_kwargs' string key 1347 1348 Args: 1349 host (str, optional): _description_. Defaults to '0.0.0.0'. 1350 port_or_range (Union[int, slice, Tuple[int, int]], optional): _description_. Defaults to 8080. 1351 title (str, optional): _description_. Defaults to 'NiceGUI'. 1352 viewport (str, optional): _description_. Defaults to 'width=device-width, initial-scale=1'. 1353 favicon (Optional[str], optional): _description_. Defaults to None. 1354 dark (Optional[bool], optional): _description_. Defaults to False. 1355 binding_refresh_interval (float, optional): _description_. Defaults to 0.1. 1356 show (bool, optional): _description_. Defaults to True. 1357 reload (bool, optional): _description_. Defaults to True. 1358 uvicorn_logging_level (str, optional): _description_. Defaults to 'warning'. 1359 uvicorn_reload_dirs (str, optional): _description_. Defaults to '.'. 1360 uvicorn_reload_includes (str, optional): _description_. Defaults to '*.py'. 1361 uvicorn_reload_excludes (str, optional): _description_. Defaults to '.*, .py[cod], .sw.*, ~*'. 1362 tailwind (bool, optional): _description_. Defaults to True. 1363 is_fast_loop (bool, optional): _description_. Defaults to True. 1364 main_coro (AnyWorker, optional): _description_. Defaults to None. 1365 """ 1366 port = simple_port_search(host, port_or_range) 1367 app_args_kwargs: Tuple[Tuple, Dict] = args_kwargs( 1368 host=host, 1369 port_or_range=port_or_range, 1370 port=port, 1371 main_coro=main_coro, 1372 is_fast_loop=is_fast_loop, 1373 app_name=app_name, 1374 app_name_for_fs=app_name_for_fs, 1375 app_version=app_version, 1376 app_version_str=app_version_str, 1377 **kwargs, 1378 ) 1379 run_in_loop(init_translation, app_args_kwargs) 1380 app.on_startup(init_cs(is_fast_loop, main_coro, app_args_kwargs)) 1381 app.on_shutdown(destroy_cs) 1382 # app.on_connect(on_connect_handler) 1383 app.on_disconnect(on_disconnect_handler) 1384 ui.run( 1385 host=host, 1386 port=port, 1387 **kwargs, 1388 )
289class ClientHandlers: 290 def __init__(self, client: Optional[Client]) -> None: 291 self.client: Optional[Client] = client 292 self.on_connected_handlers: Set[Callable] = set() 293 self.on_disconnected_handlers: Set[Callable] = set() 294 self.is_connected: bool = False 295 self.is_disconnected: bool = False 296 297 @classmethod 298 def check_args_factory(cls, signature: Signature, args, kwargs) -> Optional['ClientHandlers']: 299 client: Optional[Client] = kwargs.get('client', None) 300 if (client is None) or (not isinstance(client, Client)): 301 return None 302 else: 303 return cls.install(client) 304 305 @classmethod 306 def install(cls, client: Client) -> 'ClientHandlers': 307 client_handlers: ClientHandlers = cls(client) 308 client.handlers = client_handlers 309 client.on_connect(client_handlers._on_connected()) 310 client.on_disconnect(client_handlers._on_disconnected()) 311 return client_handlers 312 313 def add_on_connected_handler(self, handler: Callable): 314 if self.is_connected: 315 handler() 316 else: 317 self.on_connected_handlers.add(handler) 318 319 def remove_on_connected_handler(self, handler: Callable): 320 self.on_connected_handlers.discard(handler) 321 322 async def _on_connected(self): 323 on_connected_handlers_buff = tuple(self.on_connected_handlers) 324 self.on_connected_handlers = set() 325 for index, handler in enumerate(on_connected_handlers_buff): 326 try: 327 handler() 328 except: 329 self.on_connected_handlers.update(on_connected_handlers_buff[index + 1:]) 330 create_task(self._on_connected) 331 raise 332 333 def add_on_disconnected_handler(self, handler: Callable): 334 if self.is_disconnected: 335 handler() 336 else: 337 self.on_disconnected_handlers.add(handler) 338 339 def remove_on_disconnected_handler(self, handler: Callable): 340 self.on_disconnected_handlers.discard(handler) 341 342 async def _on_disconnected(self): 343 on_disconnected_handlers_buff = tuple(self.on_disconnected_handlers) 344 self.on_disconnected_handlers = set() 345 for index, handler in enumerate(on_disconnected_handlers_buff): 346 try: 347 handler() 348 except: 349 self.on_disconnected_handlers.update(on_disconnected_handlers_buff[index + 1:]) 350 create_task(self._on_disconnected) 351 raise
305 @classmethod 306 def install(cls, client: Client) -> 'ClientHandlers': 307 client_handlers: ClientHandlers = cls(client) 308 client.handlers = client_handlers 309 client.on_connect(client_handlers._on_connected()) 310 client.on_disconnect(client_handlers._on_disconnected()) 311 return client_handlers
354class PageItems: 355 def __init__(self, client: Optional[Client]) -> None: 356 self.client: Optional[Client] = client 357 self.items: Set[Any] = set() 358 359 @classmethod 360 def check_args_factory(cls, signature: Signature, args, kwargs) -> Optional['PageItems']: 361 client: Optional[Client] = kwargs.get('client', None) 362 if (client is None) or (not isinstance(client, Client)): 363 return None 364 else: 365 return cls.install(client) 366 367 @classmethod 368 def install(cls, client: Client) -> 'PageItems': 369 page_items: PageItems = cls(client) 370 client.page_items = page_items 371 return page_items 372 373 def add(self, item: Any): 374 self.items.add(item) 375 376 def remove(self, item: Any): 377 self.items.discard(item) 378 379 def __call__(self, item: Any) -> Any: 380 return self.add(item)
1002def nicegui_page_sync_coro(*dargs, **dkwargs): 1003 """Decorator. With an arguments. Gives ability to execute any decorated Cengal coroutine based page as a sync function. 1004 Can postpone execution to the actual loop when possible if None as an immediate result (no result) is acceptible. 1005 Can start own loop if needed. See sync_coro_param() decorator from cengal/parallel_execution/coroutines/coro_tools/wait_coro for more details 1006 1007 Returns: 1008 _type_: _description_ 1009 """ 1010 dargs_0 = dargs 1011 dkwargs_0 = dkwargs 1012 def nicegui_page_sync_coro_impl(coro_worker: Worker): 1013 coro_worker_0 = coro_worker 1014 dargs_1 = dargs_0 1015 dkwargs_1 = dkwargs_0 1016 def wrapper(*args, **kwargs): 1017 coro_worker = coro_worker_0 1018 dargs = dargs_1 1019 dkwargs = dkwargs_1 1020 sync_coro_decorator = sync_coro_param(*dargs, **dkwargs) 1021 sync_coro_decorator_wrapper = sync_coro_decorator(coro_worker) 1022 ClientHandlers.check_args_factory(wrapper_signature, args, kwargs) 1023 PageItems.check_args_factory(wrapper_signature, args, kwargs) 1024 return sync_coro_decorator_wrapper(*args, **kwargs) 1025 1026 coro_worker_sign: Signature = signature(coro_worker) 1027 wrapper_signature = coro_worker_sign.replace(parameters=tuple(coro_worker_sign.parameters.values())[1:], return_annotation=coro_worker_sign.return_annotation) 1028 wrapper.__signature__ = wrapper_signature 1029 1030 return wrapper 1031 return nicegui_page_sync_coro_impl
Decorator. With an arguments. Gives ability to execute any decorated Cengal coroutine based page as a sync function. Can postpone execution to the actual loop when possible if None as an immediate result (no result) is acceptible. Can start own loop if needed. See sync_coro_param() decorator from cengal/parallel_execution/coroutines/coro_tools/wait_coro for more details
Returns: _type_: _description_
1002def nicegui_page_sync_coro(*dargs, **dkwargs): 1003 """Decorator. With an arguments. Gives ability to execute any decorated Cengal coroutine based page as a sync function. 1004 Can postpone execution to the actual loop when possible if None as an immediate result (no result) is acceptible. 1005 Can start own loop if needed. See sync_coro_param() decorator from cengal/parallel_execution/coroutines/coro_tools/wait_coro for more details 1006 1007 Returns: 1008 _type_: _description_ 1009 """ 1010 dargs_0 = dargs 1011 dkwargs_0 = dkwargs 1012 def nicegui_page_sync_coro_impl(coro_worker: Worker): 1013 coro_worker_0 = coro_worker 1014 dargs_1 = dargs_0 1015 dkwargs_1 = dkwargs_0 1016 def wrapper(*args, **kwargs): 1017 coro_worker = coro_worker_0 1018 dargs = dargs_1 1019 dkwargs = dkwargs_1 1020 sync_coro_decorator = sync_coro_param(*dargs, **dkwargs) 1021 sync_coro_decorator_wrapper = sync_coro_decorator(coro_worker) 1022 ClientHandlers.check_args_factory(wrapper_signature, args, kwargs) 1023 PageItems.check_args_factory(wrapper_signature, args, kwargs) 1024 return sync_coro_decorator_wrapper(*args, **kwargs) 1025 1026 coro_worker_sign: Signature = signature(coro_worker) 1027 wrapper_signature = coro_worker_sign.replace(parameters=tuple(coro_worker_sign.parameters.values())[1:], return_annotation=coro_worker_sign.return_annotation) 1028 wrapper.__signature__ = wrapper_signature 1029 1030 return wrapper 1031 return nicegui_page_sync_coro_impl
Decorator. With an arguments. Gives ability to execute any decorated Cengal coroutine based page as a sync function. Can postpone execution to the actual loop when possible if None as an immediate result (no result) is acceptible. Can start own loop if needed. See sync_coro_param() decorator from cengal/parallel_execution/coroutines/coro_tools/wait_coro for more details
Returns: _type_: _description_
1002def nicegui_page_sync_coro(*dargs, **dkwargs): 1003 """Decorator. With an arguments. Gives ability to execute any decorated Cengal coroutine based page as a sync function. 1004 Can postpone execution to the actual loop when possible if None as an immediate result (no result) is acceptible. 1005 Can start own loop if needed. See sync_coro_param() decorator from cengal/parallel_execution/coroutines/coro_tools/wait_coro for more details 1006 1007 Returns: 1008 _type_: _description_ 1009 """ 1010 dargs_0 = dargs 1011 dkwargs_0 = dkwargs 1012 def nicegui_page_sync_coro_impl(coro_worker: Worker): 1013 coro_worker_0 = coro_worker 1014 dargs_1 = dargs_0 1015 dkwargs_1 = dkwargs_0 1016 def wrapper(*args, **kwargs): 1017 coro_worker = coro_worker_0 1018 dargs = dargs_1 1019 dkwargs = dkwargs_1 1020 sync_coro_decorator = sync_coro_param(*dargs, **dkwargs) 1021 sync_coro_decorator_wrapper = sync_coro_decorator(coro_worker) 1022 ClientHandlers.check_args_factory(wrapper_signature, args, kwargs) 1023 PageItems.check_args_factory(wrapper_signature, args, kwargs) 1024 return sync_coro_decorator_wrapper(*args, **kwargs) 1025 1026 coro_worker_sign: Signature = signature(coro_worker) 1027 wrapper_signature = coro_worker_sign.replace(parameters=tuple(coro_worker_sign.parameters.values())[1:], return_annotation=coro_worker_sign.return_annotation) 1028 wrapper.__signature__ = wrapper_signature 1029 1030 return wrapper 1031 return nicegui_page_sync_coro_impl
Decorator. With an arguments. Gives ability to execute any decorated Cengal coroutine based page as a sync function. Can postpone execution to the actual loop when possible if None as an immediate result (no result) is acceptible. Can start own loop if needed. See sync_coro_param() decorator from cengal/parallel_execution/coroutines/coro_tools/wait_coro for more details
Returns: _type_: _description_
395def nicegui_event_handler_func_async_coro(coro_worker: Worker): 396 """Decorator. Without arguments. Makes a proper, fully functional async Page from any decorated Cengal coroutine 397 398 Args: 399 coro_worker (Worker): _description_ 400 401 Raises: 402 TypeError: _description_ 403 404 Returns: 405 _type_: _description_ 406 """ 407 coro_worker_0 = coro_worker 408 # async def wrapper(*args, **kwargs): 409 async def wrapper(*args, **kwargs): 410 await await_cs_initiated() 411 coro_worker = coro_worker_0 412 app.cs.logger.debug(f'nicegui_event_handler_async_coro.wrapper - start: {entity_name(coro_worker)}') 413 coro_worker_type: CoroType = find_coro_type(coro_worker) 414 if CoroType.awaitable == coro_worker_type: 415 async def awaitable_coro_wrapper(i: Interface, current_asyncio_task, 416 coro_worker_with_args: EntityArgsHolderExplicit): 417 coro_worker, args, kwargs = coro_worker_with_args.entity_args_kwargs() 418 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.awaitable_coro_wrapper - start: {entity_name(coro_worker)}') 419 await apretent_to_be_asyncio_coro(i, current_asyncio_task) 420 # await i(Instance, InstanceRequest().wait(CS_PREPARED_FLAG)) 421 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.awaitable_coro_wrapper - ready: {entity_name(coro_worker)}') 422 return await coro_worker(i, *args, **kwargs) 423 424 coro_wrapper = awaitable_coro_wrapper 425 elif CoroType.greenlet == coro_worker_type: 426 def greenlet_coro_wrapper(i: Interface, current_asyncio_task, 427 coro_worker_with_args: EntityArgsHolderExplicit): 428 coro_worker, args, kwargs = coro_worker_with_args.entity_args_kwargs() 429 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.greenlet_coro_wrapper - start: {entity_name(coro_worker)}') 430 pretent_to_be_asyncio_coro(i, current_asyncio_task) 431 # i(Instance, InstanceRequest().wait(CS_PREPARED_FLAG)) 432 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.greenlet_coro_wrapper - ready: {entity_name(coro_worker)}') 433 return coro_worker(i, *args, **kwargs) 434 435 coro_wrapper = greenlet_coro_wrapper 436 else: 437 raise TypeError(f'{coro_worker} is neither an awaitable nor a greenlet') 438 439 current_asyncio_task = asyncio.current_task() 440 return await await_coro_prim(coro_wrapper, current_asyncio_task, 441 EntityArgsHolderExplicit(coro_worker, args, kwargs)) 442 443 coro_worker_sign: Signature = signature(coro_worker) 444 wrapper_signature = coro_worker_sign.replace(parameters=tuple(coro_worker_sign.parameters.values())[1:], return_annotation=coro_worker_sign.return_annotation) 445 wrapper.__signature__ = wrapper_signature 446 447 return wrapper
Decorator. Without arguments. Makes a proper, fully functional async Page from any decorated Cengal coroutine
Args: coro_worker (Worker): _description_
Raises: TypeError: _description_
Returns: _type_: _description_
395def nicegui_event_handler_func_async_coro(coro_worker: Worker): 396 """Decorator. Without arguments. Makes a proper, fully functional async Page from any decorated Cengal coroutine 397 398 Args: 399 coro_worker (Worker): _description_ 400 401 Raises: 402 TypeError: _description_ 403 404 Returns: 405 _type_: _description_ 406 """ 407 coro_worker_0 = coro_worker 408 # async def wrapper(*args, **kwargs): 409 async def wrapper(*args, **kwargs): 410 await await_cs_initiated() 411 coro_worker = coro_worker_0 412 app.cs.logger.debug(f'nicegui_event_handler_async_coro.wrapper - start: {entity_name(coro_worker)}') 413 coro_worker_type: CoroType = find_coro_type(coro_worker) 414 if CoroType.awaitable == coro_worker_type: 415 async def awaitable_coro_wrapper(i: Interface, current_asyncio_task, 416 coro_worker_with_args: EntityArgsHolderExplicit): 417 coro_worker, args, kwargs = coro_worker_with_args.entity_args_kwargs() 418 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.awaitable_coro_wrapper - start: {entity_name(coro_worker)}') 419 await apretent_to_be_asyncio_coro(i, current_asyncio_task) 420 # await i(Instance, InstanceRequest().wait(CS_PREPARED_FLAG)) 421 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.awaitable_coro_wrapper - ready: {entity_name(coro_worker)}') 422 return await coro_worker(i, *args, **kwargs) 423 424 coro_wrapper = awaitable_coro_wrapper 425 elif CoroType.greenlet == coro_worker_type: 426 def greenlet_coro_wrapper(i: Interface, current_asyncio_task, 427 coro_worker_with_args: EntityArgsHolderExplicit): 428 coro_worker, args, kwargs = coro_worker_with_args.entity_args_kwargs() 429 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.greenlet_coro_wrapper - start: {entity_name(coro_worker)}') 430 pretent_to_be_asyncio_coro(i, current_asyncio_task) 431 # i(Instance, InstanceRequest().wait(CS_PREPARED_FLAG)) 432 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.greenlet_coro_wrapper - ready: {entity_name(coro_worker)}') 433 return coro_worker(i, *args, **kwargs) 434 435 coro_wrapper = greenlet_coro_wrapper 436 else: 437 raise TypeError(f'{coro_worker} is neither an awaitable nor a greenlet') 438 439 current_asyncio_task = asyncio.current_task() 440 return await await_coro_prim(coro_wrapper, current_asyncio_task, 441 EntityArgsHolderExplicit(coro_worker, args, kwargs)) 442 443 coro_worker_sign: Signature = signature(coro_worker) 444 wrapper_signature = coro_worker_sign.replace(parameters=tuple(coro_worker_sign.parameters.values())[1:], return_annotation=coro_worker_sign.return_annotation) 445 wrapper.__signature__ = wrapper_signature 446 447 return wrapper
Decorator. Without arguments. Makes a proper, fully functional async Page from any decorated Cengal coroutine
Args: coro_worker (Worker): _description_
Raises: TypeError: _description_
Returns: _type_: _description_
395def nicegui_event_handler_func_async_coro(coro_worker: Worker): 396 """Decorator. Without arguments. Makes a proper, fully functional async Page from any decorated Cengal coroutine 397 398 Args: 399 coro_worker (Worker): _description_ 400 401 Raises: 402 TypeError: _description_ 403 404 Returns: 405 _type_: _description_ 406 """ 407 coro_worker_0 = coro_worker 408 # async def wrapper(*args, **kwargs): 409 async def wrapper(*args, **kwargs): 410 await await_cs_initiated() 411 coro_worker = coro_worker_0 412 app.cs.logger.debug(f'nicegui_event_handler_async_coro.wrapper - start: {entity_name(coro_worker)}') 413 coro_worker_type: CoroType = find_coro_type(coro_worker) 414 if CoroType.awaitable == coro_worker_type: 415 async def awaitable_coro_wrapper(i: Interface, current_asyncio_task, 416 coro_worker_with_args: EntityArgsHolderExplicit): 417 coro_worker, args, kwargs = coro_worker_with_args.entity_args_kwargs() 418 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.awaitable_coro_wrapper - start: {entity_name(coro_worker)}') 419 await apretent_to_be_asyncio_coro(i, current_asyncio_task) 420 # await i(Instance, InstanceRequest().wait(CS_PREPARED_FLAG)) 421 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.awaitable_coro_wrapper - ready: {entity_name(coro_worker)}') 422 return await coro_worker(i, *args, **kwargs) 423 424 coro_wrapper = awaitable_coro_wrapper 425 elif CoroType.greenlet == coro_worker_type: 426 def greenlet_coro_wrapper(i: Interface, current_asyncio_task, 427 coro_worker_with_args: EntityArgsHolderExplicit): 428 coro_worker, args, kwargs = coro_worker_with_args.entity_args_kwargs() 429 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.greenlet_coro_wrapper - start: {entity_name(coro_worker)}') 430 pretent_to_be_asyncio_coro(i, current_asyncio_task) 431 # i(Instance, InstanceRequest().wait(CS_PREPARED_FLAG)) 432 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.greenlet_coro_wrapper - ready: {entity_name(coro_worker)}') 433 return coro_worker(i, *args, **kwargs) 434 435 coro_wrapper = greenlet_coro_wrapper 436 else: 437 raise TypeError(f'{coro_worker} is neither an awaitable nor a greenlet') 438 439 current_asyncio_task = asyncio.current_task() 440 return await await_coro_prim(coro_wrapper, current_asyncio_task, 441 EntityArgsHolderExplicit(coro_worker, args, kwargs)) 442 443 coro_worker_sign: Signature = signature(coro_worker) 444 wrapper_signature = coro_worker_sign.replace(parameters=tuple(coro_worker_sign.parameters.values())[1:], return_annotation=coro_worker_sign.return_annotation) 445 wrapper.__signature__ = wrapper_signature 446 447 return wrapper
Decorator. Without arguments. Makes a proper, fully functional async Page from any decorated Cengal coroutine
Args: coro_worker (Worker): _description_
Raises: TypeError: _description_
Returns: _type_: _description_
454def nicegui_event_handler_method_async_coro(coro_worker: Worker): 455 """Decorator. Without arguments. Makes a proper, fully functional async Page from any decorated Cengal coroutine 456 457 Args: 458 coro_worker (Worker): _description_ 459 460 Raises: 461 TypeError: _description_ 462 463 Returns: 464 _type_: _description_ 465 """ 466 coro_worker_0 = coro_worker 467 # async def wrapper(*args, **kwargs): 468 async def wrapper(self, *args, **kwargs): 469 await await_cs_initiated() 470 coro_worker = coro_worker_0 471 coro_worker_name: str = coro_worker.__name__ 472 unwrapped_coro_worker_name: str = f'_unwrapped_method__{coro_worker_name}' 473 if not hasattr(self, unwrapped_coro_worker_name): 474 bound_coro_worker = coro_worker.__get__(self, self.__class__) 475 setattr(self, unwrapped_coro_worker_name, bound_coro_worker) 476 477 coro_worker = getattr(self, unwrapped_coro_worker_name) 478 app.cs.logger.debug(f'nicegui_event_handler_async_coro.wrapper - start: {entity_name(coro_worker)}') 479 coro_worker_type: CoroType = find_coro_type(coro_worker) 480 if CoroType.awaitable == coro_worker_type: 481 async def awaitable_coro_wrapper(i: Interface, current_asyncio_task, 482 coro_worker_with_args: EntityArgsHolderExplicit): 483 coro_worker, args, kwargs = coro_worker_with_args.entity_args_kwargs() 484 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.awaitable_coro_wrapper - start: {entity_name(coro_worker)}') 485 await apretent_to_be_asyncio_coro(i, current_asyncio_task) 486 # await i(Instance, InstanceRequest().wait(CS_PREPARED_FLAG)) 487 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.awaitable_coro_wrapper - ready: {entity_name(coro_worker)}') 488 i.log.debug(f'{entity_repr(coro_worker)}') 489 return await coro_worker(i, *args, **kwargs) 490 491 coro_wrapper = awaitable_coro_wrapper 492 elif CoroType.greenlet == coro_worker_type: 493 def greenlet_coro_wrapper(i: Interface, current_asyncio_task, 494 coro_worker_with_args: EntityArgsHolderExplicit): 495 coro_worker, args, kwargs = coro_worker_with_args.entity_args_kwargs() 496 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.greenlet_coro_wrapper - start: {entity_name(coro_worker)}') 497 pretent_to_be_asyncio_coro(i, current_asyncio_task) 498 # i(Instance, InstanceRequest().wait(CS_PREPARED_FLAG)) 499 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.greenlet_coro_wrapper - ready: {entity_name(coro_worker)}') 500 return coro_worker(i, *args, **kwargs) 501 502 coro_wrapper = greenlet_coro_wrapper 503 else: 504 raise TypeError(f'{coro_worker} is neither an awaitable nor a greenlet') 505 506 current_asyncio_task = asyncio.current_task() 507 return await await_coro_prim(coro_wrapper, current_asyncio_task, 508 EntityArgsHolderExplicit(coro_worker, args, kwargs)) 509 510 coro_worker_sign: Signature = signature(coro_worker) 511 new_parameters = list(coro_worker_sign.parameters.values()) 512 del new_parameters[1] 513 wrapper_signature = coro_worker_sign.replace(parameters=tuple(new_parameters), return_annotation=coro_worker_sign.return_annotation) 514 wrapper.__signature__ = wrapper_signature 515 516 return wrapper
Decorator. Without arguments. Makes a proper, fully functional async Page from any decorated Cengal coroutine
Args: coro_worker (Worker): _description_
Raises: TypeError: _description_
Returns: _type_: _description_
454def nicegui_event_handler_method_async_coro(coro_worker: Worker): 455 """Decorator. Without arguments. Makes a proper, fully functional async Page from any decorated Cengal coroutine 456 457 Args: 458 coro_worker (Worker): _description_ 459 460 Raises: 461 TypeError: _description_ 462 463 Returns: 464 _type_: _description_ 465 """ 466 coro_worker_0 = coro_worker 467 # async def wrapper(*args, **kwargs): 468 async def wrapper(self, *args, **kwargs): 469 await await_cs_initiated() 470 coro_worker = coro_worker_0 471 coro_worker_name: str = coro_worker.__name__ 472 unwrapped_coro_worker_name: str = f'_unwrapped_method__{coro_worker_name}' 473 if not hasattr(self, unwrapped_coro_worker_name): 474 bound_coro_worker = coro_worker.__get__(self, self.__class__) 475 setattr(self, unwrapped_coro_worker_name, bound_coro_worker) 476 477 coro_worker = getattr(self, unwrapped_coro_worker_name) 478 app.cs.logger.debug(f'nicegui_event_handler_async_coro.wrapper - start: {entity_name(coro_worker)}') 479 coro_worker_type: CoroType = find_coro_type(coro_worker) 480 if CoroType.awaitable == coro_worker_type: 481 async def awaitable_coro_wrapper(i: Interface, current_asyncio_task, 482 coro_worker_with_args: EntityArgsHolderExplicit): 483 coro_worker, args, kwargs = coro_worker_with_args.entity_args_kwargs() 484 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.awaitable_coro_wrapper - start: {entity_name(coro_worker)}') 485 await apretent_to_be_asyncio_coro(i, current_asyncio_task) 486 # await i(Instance, InstanceRequest().wait(CS_PREPARED_FLAG)) 487 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.awaitable_coro_wrapper - ready: {entity_name(coro_worker)}') 488 i.log.debug(f'{entity_repr(coro_worker)}') 489 return await coro_worker(i, *args, **kwargs) 490 491 coro_wrapper = awaitable_coro_wrapper 492 elif CoroType.greenlet == coro_worker_type: 493 def greenlet_coro_wrapper(i: Interface, current_asyncio_task, 494 coro_worker_with_args: EntityArgsHolderExplicit): 495 coro_worker, args, kwargs = coro_worker_with_args.entity_args_kwargs() 496 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.greenlet_coro_wrapper - start: {entity_name(coro_worker)}') 497 pretent_to_be_asyncio_coro(i, current_asyncio_task) 498 # i(Instance, InstanceRequest().wait(CS_PREPARED_FLAG)) 499 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.greenlet_coro_wrapper - ready: {entity_name(coro_worker)}') 500 return coro_worker(i, *args, **kwargs) 501 502 coro_wrapper = greenlet_coro_wrapper 503 else: 504 raise TypeError(f'{coro_worker} is neither an awaitable nor a greenlet') 505 506 current_asyncio_task = asyncio.current_task() 507 return await await_coro_prim(coro_wrapper, current_asyncio_task, 508 EntityArgsHolderExplicit(coro_worker, args, kwargs)) 509 510 coro_worker_sign: Signature = signature(coro_worker) 511 new_parameters = list(coro_worker_sign.parameters.values()) 512 del new_parameters[1] 513 wrapper_signature = coro_worker_sign.replace(parameters=tuple(new_parameters), return_annotation=coro_worker_sign.return_annotation) 514 wrapper.__signature__ = wrapper_signature 515 516 return wrapper
Decorator. Without arguments. Makes a proper, fully functional async Page from any decorated Cengal coroutine
Args: coro_worker (Worker): _description_
Raises: TypeError: _description_
Returns: _type_: _description_
454def nicegui_event_handler_method_async_coro(coro_worker: Worker): 455 """Decorator. Without arguments. Makes a proper, fully functional async Page from any decorated Cengal coroutine 456 457 Args: 458 coro_worker (Worker): _description_ 459 460 Raises: 461 TypeError: _description_ 462 463 Returns: 464 _type_: _description_ 465 """ 466 coro_worker_0 = coro_worker 467 # async def wrapper(*args, **kwargs): 468 async def wrapper(self, *args, **kwargs): 469 await await_cs_initiated() 470 coro_worker = coro_worker_0 471 coro_worker_name: str = coro_worker.__name__ 472 unwrapped_coro_worker_name: str = f'_unwrapped_method__{coro_worker_name}' 473 if not hasattr(self, unwrapped_coro_worker_name): 474 bound_coro_worker = coro_worker.__get__(self, self.__class__) 475 setattr(self, unwrapped_coro_worker_name, bound_coro_worker) 476 477 coro_worker = getattr(self, unwrapped_coro_worker_name) 478 app.cs.logger.debug(f'nicegui_event_handler_async_coro.wrapper - start: {entity_name(coro_worker)}') 479 coro_worker_type: CoroType = find_coro_type(coro_worker) 480 if CoroType.awaitable == coro_worker_type: 481 async def awaitable_coro_wrapper(i: Interface, current_asyncio_task, 482 coro_worker_with_args: EntityArgsHolderExplicit): 483 coro_worker, args, kwargs = coro_worker_with_args.entity_args_kwargs() 484 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.awaitable_coro_wrapper - start: {entity_name(coro_worker)}') 485 await apretent_to_be_asyncio_coro(i, current_asyncio_task) 486 # await i(Instance, InstanceRequest().wait(CS_PREPARED_FLAG)) 487 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.awaitable_coro_wrapper - ready: {entity_name(coro_worker)}') 488 i.log.debug(f'{entity_repr(coro_worker)}') 489 return await coro_worker(i, *args, **kwargs) 490 491 coro_wrapper = awaitable_coro_wrapper 492 elif CoroType.greenlet == coro_worker_type: 493 def greenlet_coro_wrapper(i: Interface, current_asyncio_task, 494 coro_worker_with_args: EntityArgsHolderExplicit): 495 coro_worker, args, kwargs = coro_worker_with_args.entity_args_kwargs() 496 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.greenlet_coro_wrapper - start: {entity_name(coro_worker)}') 497 pretent_to_be_asyncio_coro(i, current_asyncio_task) 498 # i(Instance, InstanceRequest().wait(CS_PREPARED_FLAG)) 499 i.log.debug(f'nicegui_event_handler_async_coro.wrapper.greenlet_coro_wrapper - ready: {entity_name(coro_worker)}') 500 return coro_worker(i, *args, **kwargs) 501 502 coro_wrapper = greenlet_coro_wrapper 503 else: 504 raise TypeError(f'{coro_worker} is neither an awaitable nor a greenlet') 505 506 current_asyncio_task = asyncio.current_task() 507 return await await_coro_prim(coro_wrapper, current_asyncio_task, 508 EntityArgsHolderExplicit(coro_worker, args, kwargs)) 509 510 coro_worker_sign: Signature = signature(coro_worker) 511 new_parameters = list(coro_worker_sign.parameters.values()) 512 del new_parameters[1] 513 wrapper_signature = coro_worker_sign.replace(parameters=tuple(new_parameters), return_annotation=coro_worker_sign.return_annotation) 514 wrapper.__signature__ = wrapper_signature 515 516 return wrapper
Decorator. Without arguments. Makes a proper, fully functional async Page from any decorated Cengal coroutine
Args: coro_worker (Worker): _description_
Raises: TypeError: _description_
Returns: _type_: _description_
549class PageContextBase: 550 def __init__(self, client: Client, request: FastAPIRequest, _t: NTTE, current_asyncio_task) -> None: 551 self.client: Client = client 552 self.request: FastAPIRequest = request 553 self.client_host_port: Address = self.request.client 554 self.client_id: Hashable = client.id 555 self.session_id: Hashable = client.session_id 556 self.user_id: Hashable = None 557 self._t: NTTE = _t 558 self.current_asyncio_task = current_asyncio_task 559 self.current_asyncio_task_id = id(current_asyncio_task) 560 self.client_view_type: ClientViewType = self._determine_client_view_type() 561 self.better_lang: str = None 562 self.featured_langs: OrderedDict[str, RationalNumber] = None 563 self.langs: OrderedDict[str, RationalNumber] = None 564 self.better_lang, self.featured_langs, self.langs = self._determine_client_languages() 565 self._t.text_translation_language_chooser.lang = self.better_lang 566 567 def _init(self, i: Interface): 568 self.register_session_page(i) 569 i(PutCoro, self._arequest_ip_geolocation, self.client_host_port[0]) 570 if self._find_user(i): 571 i.log.debug(f'{self.session_id}, {self.client_id}: logged in') 572 else: 573 i.log.debug(f'{self.session_id}, {self.client_id}: logged out') 574 575 async def _ainit(self, i: Interface): 576 self.register_session_page(i) 577 await i(PutCoro, self._arequest_ip_geolocation, self.client_host_port[0]) 578 if await self._afind_user(i): 579 i.log.debug(f'{self.session_id}, {self.client_id}: logged in') 580 else: 581 i.log.debug(f'{self.session_id}, {self.client_id}: logged out') 582 583 async def _arequest_ip_geolocation(self, i: Interface, host: str): 584 ip_geolocation: Optional[Dict] = None 585 need_to_request: bool = True 586 try: 587 ip_geolocation = await i(db_request__ip_geolocation.get(host)) 588 need_to_request = False 589 except KeyError: 590 pass 591 592 if need_to_request: 593 ip_geolocation = await i(AsyncioLoop, AsyncioLoopRequest().wait(get_ip_geolocation(ipinfo_io_token, host))) 594 595 await self.on_ip_geolocation_ready(i, ip_geolocation) 596 597 def register_session_page(self, i: Interface): 598 session_pages: Dict[Hashable, Set[PageContextBase]] = fast_get_explicit(i, 'cengal_nicegui__session_pages') 599 if self.session_id not in session_pages: 600 session_pages[self.session_id] = set() 601 602 session_pages[self.session_id].add(self) 603 604 def _determine_client_view_type(self) -> ClientViewType: 605 return client_view_type(self.request.headers) 606 607 def _determine_client_languages(self): 608 parsed_accept_language: Optional[OrderedDict[str, RationalNumber]] = optimize_accept_language(parse_accept_language(self.request.headers)) 609 translation_data: Dict = self._t.text_translator.decoded_data 610 return match_langs( 611 translation_data['default_language'], 612 set(translation_data['featured_languages']), 613 set(translation_data['supported_languages']), 614 translation_data['translation_language_map'], 615 parsed_accept_language, 616 ) 617 618 def _find_user(self, i: Interface) -> bool: 619 if self.session_id is None: 620 return False 621 622 try: 623 user_id, sign_in_date_time = i(db_request__logged_in_sessions.get(self.session_id)) 624 sign_in_date_time = datetime.fromisoformat(sign_in_date_time) 625 if (datetime.now() - sign_in_date_time) > signed_in_session_timeout: 626 i(db_request__logged_in_sessions.delete(self.session_id)) 627 return False 628 629 self.user_id = user_id 630 return True 631 except KeyError: 632 return False 633 634 async def _afind_user(self, i: Interface) -> bool: 635 if self.session_id is None: 636 return False 637 638 try: 639 user_id, sign_in_date_time = await i(db_request__logged_in_sessions.get(self.session_id)) 640 sign_in_date_time = datetime.fromisoformat(sign_in_date_time) 641 if (datetime.now() - sign_in_date_time) > signed_in_session_timeout: 642 await i(db_request__logged_in_sessions.delete(self.session_id)) 643 return False 644 645 self.user_id = user_id 646 return True 647 except KeyError: 648 return False 649 650 # def find_user(self, i: Interface, client_connection_check_interval: RationalNumber = 0.01) -> bool: 651 # if not self.client.has_socket_connection: 652 # if not self.client.is_waiting_for_connection: 653 # i(AsyncioLoop, AsyncioLoopRequest().wait(self.client.connected())) 654 655 # while self.client.is_waiting_for_connection: 656 # i(Sleep, client_connection_check_interval) 657 658 # return self._find_user(i) 659 660 # async def afind_user(self, i: Interface, client_connection_check_interval: RationalNumber = 0.01) -> bool: 661 # if not self.client.has_socket_connection: 662 # if not self.client.is_waiting_for_connection: 663 # await i(AsyncioLoop, AsyncioLoopRequest().wait(self.client.connected())) 664 665 # while self.client.is_waiting_for_connection: 666 # await i(Sleep, client_connection_check_interval) 667 668 # return await self._afind_user(i) 669 670 def try_sign_in(self, i: Interface, credentials: Union[Dict, Tuple, List, str, bytes, int, float]) -> Optional[Union[Dict, Tuple, List]]: 671 user_data: Union[Dict, Tuple, List] = None 672 673 try: 674 user_data = i(db_request__user_sign_in_info.get(credentials)) 675 except KeyError: 676 pass 677 678 if user_data is None: 679 return None 680 681 user_id = user_data[0] 682 if self.session_id is None: 683 i(db_request__logged_in_clients.put(self.client_id, (user_id, datetime.now()))) 684 user_clients_lock: Lock = fast_get_explicit(i, 'cengal_nicegui__user_clients_lock') 685 with user_clients_lock: 686 try: 687 user_clients: Set[Hashable] = set(i(db_request__user_clients.get(user_id))) 688 except KeyError: 689 user_clients = set() 690 691 user_clients.add(self.client_id) 692 i(db_request__user_sessions.put(user_id, user_clients)) 693 694 i(PutCoro, self._on_signed_in, user_id) 695 else: 696 i(db_request__logged_in_sessions.put(self.session_id, (user_id, datetime.now()))) 697 user_sessions_lock: Lock = fast_get_explicit(i, 'cengal_nicegui__user_sessions_lock') 698 with user_sessions_lock: 699 try: 700 user_sessions: Set[Hashable] = set(i(db_request__user_sessions.get(user_id))) 701 except KeyError: 702 user_sessions = set() 703 704 user_sessions.add(self.session_id) 705 i(db_request__user_sessions.put(user_id, user_sessions)) 706 707 session_pages: Dict[Hashable, Set[PageContextBase]] = fast_get_explicit(i, 'cengal_nicegui__session_pages') 708 current_session_pages: Set[PageContextBase] = session_pages.get(self.session_id, set()) 709 for session_page in current_session_pages: 710 i(PutCoro, session_page._on_signed_in, user_id, user_data) 711 712 return user_data 713 714 async def atry_sign_in(self, i: Interface, credentials: Union[Dict, Tuple, List, str, bytes, int, float]) -> Optional[Union[Dict, Tuple, List]]: 715 user_data: Union[Dict, Tuple, List] = None 716 717 try: 718 user_data = await i(db_request__user_sign_in_info.get(credentials)) 719 except KeyError: 720 pass 721 722 if user_data is None: 723 return None 724 725 user_id = user_data[0] 726 if self.session_id is None: 727 await i(db_request__logged_in_clients.put(self.client_id, (user_id, datetime.now()))) 728 user_clients_lock: Lock = fast_get_explicit(i, 'cengal_nicegui__user_clients_lock') 729 async with user_clients_lock: 730 try: 731 user_clients: Set[Hashable] = set(await i(db_request__user_clients.get(user_id))) 732 except KeyError: 733 user_clients = set() 734 735 user_clients.add(self.client_id) 736 await i(db_request__user_sessions.put(user_id, user_clients)) 737 738 await i(PutCoro, self._on_signed_in, user_id) 739 else: 740 await i(db_request__logged_in_sessions.put(self.session_id, (user_id, datetime.now()))) 741 user_sessions_lock: Lock = fast_get_explicit(i, 'cengal_nicegui__user_sessions_lock') 742 async with user_sessions_lock: 743 try: 744 user_sessions: Set[Hashable] = set(await i(db_request__user_sessions.get(user_id))) 745 except KeyError: 746 user_sessions = set() 747 748 user_sessions.add(self.session_id) 749 await i(db_request__user_sessions.put(user_id, user_sessions)) 750 751 session_pages: Dict[Hashable, Set[PageContextBase]] = fast_get_explicit(i, 'cengal_nicegui__session_pages') 752 current_session_pages: Set[PageContextBase] = set(session_pages.get(self.session_id, set())) # TODO: robust fix needed for `RuntimeError: Set changed size during iteration` 753 for session_page in current_session_pages: 754 await i(PutCoro, session_page._on_signed_in, user_id, user_data) 755 756 return user_data 757 758 def user_signed_up(self, i: Interface, credentials: Union[Dict, Tuple, List, str, bytes, int, float], 759 user_sign_in_info: Union[Dict, Tuple, List]): 760 i(db_request__user_sign_in_info.put(credentials, user_sign_in_info)) 761 762 async def auser_signed_up(self, i: Interface, credentials: Union[Dict, Tuple, List, str, bytes, int, float], 763 user_sign_in_info: Union[Dict, Tuple, List]): 764 await i(db_request__user_sign_in_info.put(credentials, user_sign_in_info)) 765 766 def sign_out(self, i: Interface) -> bool: 767 user_id = self.user_id 768 if user_id is None: 769 return False 770 771 if self.session_id is None: 772 try: 773 i(db_request__logged_in_clients.delete(self.client_id)) 774 except KeyError: 775 pass 776 777 i(PutCoro, self._on_signed_out) 778 return True 779 else: 780 try: 781 i(db_request__logged_in_sessions.delete(self.session_id)) 782 except KeyError: 783 pass 784 785 session_pages: Dict[Hashable, Set[PageContextBase]] = fast_get_explicit(i, 'cengal_nicegui__session_pages') 786 current_session_pages: Set[PageContextBase] = session_pages.get(self.session_id, set()) 787 for session_page in current_session_pages: 788 i(PutCoro, session_page._on_signed_out) 789 790 return True 791 792 async def asign_out(self, i: Interface) -> bool: 793 user_id = self.user_id 794 if user_id is None: 795 return False 796 797 if self.session_id is None: 798 try: 799 await i(db_request__logged_in_clients.delete(self.client_id)) 800 except KeyError: 801 pass 802 803 user_clients_lock: Lock = fast_get_explicit(i, 'cengal_nicegui__user_clients_lock') 804 async with user_clients_lock: 805 try: 806 user_clients: Set[Hashable] = set(await i(db_request__user_clients.get(user_id))) 807 except KeyError: 808 user_clients = set() 809 810 user_clients.discard(self.client_id) 811 await i(db_request__user_sessions.put(user_id, user_clients)) 812 813 await i(PutCoro, self._on_signed_out) 814 return True 815 else: 816 try: 817 await i(db_request__logged_in_sessions.delete(self.session_id)) 818 except KeyError: 819 pass 820 821 user_sessions_lock: Lock = fast_get_explicit(i, 'cengal_nicegui__user_sessions_lock') 822 async with user_sessions_lock: 823 try: 824 user_sessions: Set[Hashable] = set(await i(db_request__user_sessions.get(user_id))) 825 except KeyError: 826 user_sessions = set() 827 828 user_sessions.discard(self.session_id) 829 await i(db_request__user_sessions.put(user_id, user_sessions)) 830 831 session_pages: Dict[Hashable, Set[PageContextBase]] = fast_get_explicit(i, 'cengal_nicegui__session_pages') 832 current_session_pages: Set[PageContextBase] = session_pages.get(self.session_id, set()) 833 for session_page in current_session_pages: 834 await i(PutCoro, session_page._on_signed_out) 835 836 return True 837 838 def try_sign_up__login_password(self, i: Interface, login: str, password: str, 839 user_sign_in_info_maker: Callable[[Interface, str, Hashable, datetime], Union[Dict, Tuple, List]]) -> bool: 840 login_exists: bool = False 841 try: 842 i(db_request__user_sign_up_info.get(login)) 843 login_exists = True 844 except KeyError: 845 pass 846 847 if login_exists: 848 return False 849 850 password_bytes = password.encode('utf-8') 851 salt = os.urandom(16) 852 key_length = 64 853 N = 16384 # CPU/memory cost factor 854 r = 8 # Block size 855 p = 1 # Parallelization factor 856 dk = hashlib.scrypt(password_bytes, salt=salt, n=N, r=r, p=p, dklen=key_length) 857 i(db_request__user_sign_up_info.put(login, (dk, salt, N, r, p, key_length))) 858 user_id: Hashable = uuid4() 859 credentials: Tuple = (login, dk) 860 i(db_request__credentials_by_user_id.put(user_id, credentials)) 861 user_sign_in_info: Union[Dict, Tuple, List] = run_coro_fast(i, user_sign_in_info_maker, login, user_id, datetime.now()) 862 self.user_signed_up(i, credentials, user_sign_in_info) 863 return True 864 865 async def atry_sign_up__login_password(self, i: Interface, login: str, password: str, 866 user_sign_in_info_maker: Callable[[Interface, str, Hashable, datetime], Union[Dict, Tuple, List]]) -> bool: 867 login_exists: bool = False 868 try: 869 await i(db_request__user_sign_up_info.get(login)) 870 login_exists = True 871 except KeyError: 872 pass 873 874 if login_exists: 875 return False 876 877 password_bytes = password.encode('utf-8') 878 salt = os.urandom(16) 879 key_length = 64 880 N = 16384 # CPU/memory cost factor 881 r = 8 # Block size 882 p = 1 # Parallelization factor 883 dk = hashlib.scrypt(password_bytes, salt=salt, n=N, r=r, p=p, dklen=key_length) 884 await i(db_request__user_sign_up_info.put(login, (dk, salt, N, r, p, key_length))) 885 user_id: Hashable = uuid4().bytes 886 credentials: Tuple = (login, dk) 887 await i(db_request__credentials_by_user_id.put(user_id, credentials)) 888 user_sign_in_info: Union[Dict, Tuple, List] = await arun_coro_fast(i, user_sign_in_info_maker, login, user_id, datetime.now()) 889 await self.auser_signed_up(i, credentials, user_sign_in_info) 890 return True 891 892 def try_sign_in__login_password(self, i: Interface, login: str, password: str) -> Union[Dict, Tuple, List]: 893 user_found: bool = False 894 try: 895 dk, salt, N, r, p, key_length = i(db_request__user_sign_up_info.get(login)) 896 user_found = True 897 except KeyError: 898 pass 899 900 if not user_found: 901 raise UserNotFoundError 902 903 password_bytes = password.encode('utf-8') 904 dk_0 = hashlib.scrypt(password_bytes, salt=salt, n=N, r=r, p=p, dklen=key_length) 905 if dk != dk_0: 906 raise PasswordIsNotCorrectError 907 908 credentials: Tuple = (login, dk) 909 return self.try_sign_in(i, credentials) 910 911 async def atry_sign_in__login_password(self, i: Interface, login: str, password: str) -> Union[Dict, Tuple, List]: 912 user_found: bool = False 913 try: 914 dk, salt, N, r, p, key_length = await i(db_request__user_sign_up_info.get(login)) 915 user_found = True 916 except KeyError: 917 pass 918 919 if not user_found: 920 raise UserNotFoundError 921 922 password_bytes = password.encode('utf-8') 923 dk_0 = hashlib.scrypt(password_bytes, salt=salt, n=N, r=r, p=p, dklen=key_length) 924 if dk != dk_0: 925 raise PasswordIsNotCorrectError 926 927 credentials: Tuple = (login, dk) 928 return await self.atry_sign_in(i, credentials) 929 930 def try_sign_up__email_password(self, i: Interface, email: str, password: str) -> bool: 931 raise NotImplementedError 932 933 async def atry_sign_up__email_password(self, i: Interface, email: str, password: str) -> bool: 934 raise NotImplementedError 935 936 async def _on_signed_in(self, i: Interface, user_id: Hashable, user_sign_in_info: Union[Dict, Tuple, List]) -> None: 937 self.user_id = user_id 938 handle_event(self._on_signed_in_impl, OnSignInEventArguments(sender=FakeElementForEvents(self.current_asyncio_task_id), client=self.client, user_id=user_id, user_sign_in_info=user_sign_in_info)) 939 940 @aevent_handler_method 941 async def _on_signed_in_impl(self, i: Interface, arguments: OnSignInEventArguments) -> None: 942 return await self.on_signed_in(i, arguments.user_id, arguments.user_sign_in_info) 943 944 async def on_signed_in(self, i: Interface, user_id: Hashable, user_sign_in_info: Union[Dict, Tuple, List]) -> None: 945 pass 946 947 async def _on_signed_out(self, i: Interface) -> None: 948 user_id = self.user_id 949 self.user_id = None 950 handle_event(self._on_signed_out_impl, OnSignOutEventArguments(sender=FakeElementForEvents(self.current_asyncio_task_id), client=self.client, user_id=user_id)) 951 952 @aevent_handler_method 953 async def _on_signed_out_impl(self, i: Interface, arguments: OnSignOutEventArguments) -> None: 954 return await self.on_signed_out(i, arguments.user_id) 955 956 async def on_signed_out(self, i: Interface, user_id: Hashable) -> None: 957 pass 958 959 async def on_ip_geolocation_ready(self, i: Interface, ip_geolocation: Optional[Dict]) -> None: 960 pass 961 962 def refferer(self) -> Optional[str]: 963 return self.request.headers.get('referer', None) 964 965 def url(self) -> URL: 966 return self.request.url 967 968 def open_page(self, target: Optional[Union[Callable[..., Any], str]] = None, new_tab: bool = False) -> Optional[RedirectResponse]: 969 if target is None: 970 return 971 972 client = self.client 973 if client.has_socket_connection: 974 client.open(target, new_tab) 975 else: 976 return RedirectResponse(target) 977 978 def open_previous_page(self, default_target: Optional[Union[Callable[..., Any], str]] = None, new_tab: bool = False, can_be_current_page: bool = False) -> Optional[RedirectResponse]: 979 target: str = self.refferer() 980 current_url: str = str(self.url()) 981 if (target is None) or (False if can_be_current_page else (target == current_url)): 982 if not isinstance(default_target, str): 983 default_target = globals.page_routes[target] 984 985 target = default_target if default_target is not None else '/' 986 987 client = self.client 988 if client.has_socket_connection: 989 client.open(target, new_tab) 990 else: 991 return self.open_previous_page_http_response(default_target, can_be_current_page) 992 993 def open_previous_page_http_response(self, default_target: Optional[Union[Callable[..., Any], str]] = None, can_be_current_page: bool = False) -> RedirectResponse: 994 refferer: str = self.refferer() 995 current_url: str = str(self.url()) 996 if (refferer is None) or (False if can_be_current_page else (refferer == current_url)): 997 refferer = default_target if default_target is not None else '/' 998 999 return RedirectResponse(refferer)
550 def __init__(self, client: Client, request: FastAPIRequest, _t: NTTE, current_asyncio_task) -> None: 551 self.client: Client = client 552 self.request: FastAPIRequest = request 553 self.client_host_port: Address = self.request.client 554 self.client_id: Hashable = client.id 555 self.session_id: Hashable = client.session_id 556 self.user_id: Hashable = None 557 self._t: NTTE = _t 558 self.current_asyncio_task = current_asyncio_task 559 self.current_asyncio_task_id = id(current_asyncio_task) 560 self.client_view_type: ClientViewType = self._determine_client_view_type() 561 self.better_lang: str = None 562 self.featured_langs: OrderedDict[str, RationalNumber] = None 563 self.langs: OrderedDict[str, RationalNumber] = None 564 self.better_lang, self.featured_langs, self.langs = self._determine_client_languages() 565 self._t.text_translation_language_chooser.lang = self.better_lang
670 def try_sign_in(self, i: Interface, credentials: Union[Dict, Tuple, List, str, bytes, int, float]) -> Optional[Union[Dict, Tuple, List]]: 671 user_data: Union[Dict, Tuple, List] = None 672 673 try: 674 user_data = i(db_request__user_sign_in_info.get(credentials)) 675 except KeyError: 676 pass 677 678 if user_data is None: 679 return None 680 681 user_id = user_data[0] 682 if self.session_id is None: 683 i(db_request__logged_in_clients.put(self.client_id, (user_id, datetime.now()))) 684 user_clients_lock: Lock = fast_get_explicit(i, 'cengal_nicegui__user_clients_lock') 685 with user_clients_lock: 686 try: 687 user_clients: Set[Hashable] = set(i(db_request__user_clients.get(user_id))) 688 except KeyError: 689 user_clients = set() 690 691 user_clients.add(self.client_id) 692 i(db_request__user_sessions.put(user_id, user_clients)) 693 694 i(PutCoro, self._on_signed_in, user_id) 695 else: 696 i(db_request__logged_in_sessions.put(self.session_id, (user_id, datetime.now()))) 697 user_sessions_lock: Lock = fast_get_explicit(i, 'cengal_nicegui__user_sessions_lock') 698 with user_sessions_lock: 699 try: 700 user_sessions: Set[Hashable] = set(i(db_request__user_sessions.get(user_id))) 701 except KeyError: 702 user_sessions = set() 703 704 user_sessions.add(self.session_id) 705 i(db_request__user_sessions.put(user_id, user_sessions)) 706 707 session_pages: Dict[Hashable, Set[PageContextBase]] = fast_get_explicit(i, 'cengal_nicegui__session_pages') 708 current_session_pages: Set[PageContextBase] = session_pages.get(self.session_id, set()) 709 for session_page in current_session_pages: 710 i(PutCoro, session_page._on_signed_in, user_id, user_data) 711 712 return user_data
714 async def atry_sign_in(self, i: Interface, credentials: Union[Dict, Tuple, List, str, bytes, int, float]) -> Optional[Union[Dict, Tuple, List]]: 715 user_data: Union[Dict, Tuple, List] = None 716 717 try: 718 user_data = await i(db_request__user_sign_in_info.get(credentials)) 719 except KeyError: 720 pass 721 722 if user_data is None: 723 return None 724 725 user_id = user_data[0] 726 if self.session_id is None: 727 await i(db_request__logged_in_clients.put(self.client_id, (user_id, datetime.now()))) 728 user_clients_lock: Lock = fast_get_explicit(i, 'cengal_nicegui__user_clients_lock') 729 async with user_clients_lock: 730 try: 731 user_clients: Set[Hashable] = set(await i(db_request__user_clients.get(user_id))) 732 except KeyError: 733 user_clients = set() 734 735 user_clients.add(self.client_id) 736 await i(db_request__user_sessions.put(user_id, user_clients)) 737 738 await i(PutCoro, self._on_signed_in, user_id) 739 else: 740 await i(db_request__logged_in_sessions.put(self.session_id, (user_id, datetime.now()))) 741 user_sessions_lock: Lock = fast_get_explicit(i, 'cengal_nicegui__user_sessions_lock') 742 async with user_sessions_lock: 743 try: 744 user_sessions: Set[Hashable] = set(await i(db_request__user_sessions.get(user_id))) 745 except KeyError: 746 user_sessions = set() 747 748 user_sessions.add(self.session_id) 749 await i(db_request__user_sessions.put(user_id, user_sessions)) 750 751 session_pages: Dict[Hashable, Set[PageContextBase]] = fast_get_explicit(i, 'cengal_nicegui__session_pages') 752 current_session_pages: Set[PageContextBase] = set(session_pages.get(self.session_id, set())) # TODO: robust fix needed for `RuntimeError: Set changed size during iteration` 753 for session_page in current_session_pages: 754 await i(PutCoro, session_page._on_signed_in, user_id, user_data) 755 756 return user_data
766 def sign_out(self, i: Interface) -> bool: 767 user_id = self.user_id 768 if user_id is None: 769 return False 770 771 if self.session_id is None: 772 try: 773 i(db_request__logged_in_clients.delete(self.client_id)) 774 except KeyError: 775 pass 776 777 i(PutCoro, self._on_signed_out) 778 return True 779 else: 780 try: 781 i(db_request__logged_in_sessions.delete(self.session_id)) 782 except KeyError: 783 pass 784 785 session_pages: Dict[Hashable, Set[PageContextBase]] = fast_get_explicit(i, 'cengal_nicegui__session_pages') 786 current_session_pages: Set[PageContextBase] = session_pages.get(self.session_id, set()) 787 for session_page in current_session_pages: 788 i(PutCoro, session_page._on_signed_out) 789 790 return True
792 async def asign_out(self, i: Interface) -> bool: 793 user_id = self.user_id 794 if user_id is None: 795 return False 796 797 if self.session_id is None: 798 try: 799 await i(db_request__logged_in_clients.delete(self.client_id)) 800 except KeyError: 801 pass 802 803 user_clients_lock: Lock = fast_get_explicit(i, 'cengal_nicegui__user_clients_lock') 804 async with user_clients_lock: 805 try: 806 user_clients: Set[Hashable] = set(await i(db_request__user_clients.get(user_id))) 807 except KeyError: 808 user_clients = set() 809 810 user_clients.discard(self.client_id) 811 await i(db_request__user_sessions.put(user_id, user_clients)) 812 813 await i(PutCoro, self._on_signed_out) 814 return True 815 else: 816 try: 817 await i(db_request__logged_in_sessions.delete(self.session_id)) 818 except KeyError: 819 pass 820 821 user_sessions_lock: Lock = fast_get_explicit(i, 'cengal_nicegui__user_sessions_lock') 822 async with user_sessions_lock: 823 try: 824 user_sessions: Set[Hashable] = set(await i(db_request__user_sessions.get(user_id))) 825 except KeyError: 826 user_sessions = set() 827 828 user_sessions.discard(self.session_id) 829 await i(db_request__user_sessions.put(user_id, user_sessions)) 830 831 session_pages: Dict[Hashable, Set[PageContextBase]] = fast_get_explicit(i, 'cengal_nicegui__session_pages') 832 current_session_pages: Set[PageContextBase] = session_pages.get(self.session_id, set()) 833 for session_page in current_session_pages: 834 await i(PutCoro, session_page._on_signed_out) 835 836 return True
838 def try_sign_up__login_password(self, i: Interface, login: str, password: str, 839 user_sign_in_info_maker: Callable[[Interface, str, Hashable, datetime], Union[Dict, Tuple, List]]) -> bool: 840 login_exists: bool = False 841 try: 842 i(db_request__user_sign_up_info.get(login)) 843 login_exists = True 844 except KeyError: 845 pass 846 847 if login_exists: 848 return False 849 850 password_bytes = password.encode('utf-8') 851 salt = os.urandom(16) 852 key_length = 64 853 N = 16384 # CPU/memory cost factor 854 r = 8 # Block size 855 p = 1 # Parallelization factor 856 dk = hashlib.scrypt(password_bytes, salt=salt, n=N, r=r, p=p, dklen=key_length) 857 i(db_request__user_sign_up_info.put(login, (dk, salt, N, r, p, key_length))) 858 user_id: Hashable = uuid4() 859 credentials: Tuple = (login, dk) 860 i(db_request__credentials_by_user_id.put(user_id, credentials)) 861 user_sign_in_info: Union[Dict, Tuple, List] = run_coro_fast(i, user_sign_in_info_maker, login, user_id, datetime.now()) 862 self.user_signed_up(i, credentials, user_sign_in_info) 863 return True
865 async def atry_sign_up__login_password(self, i: Interface, login: str, password: str, 866 user_sign_in_info_maker: Callable[[Interface, str, Hashable, datetime], Union[Dict, Tuple, List]]) -> bool: 867 login_exists: bool = False 868 try: 869 await i(db_request__user_sign_up_info.get(login)) 870 login_exists = True 871 except KeyError: 872 pass 873 874 if login_exists: 875 return False 876 877 password_bytes = password.encode('utf-8') 878 salt = os.urandom(16) 879 key_length = 64 880 N = 16384 # CPU/memory cost factor 881 r = 8 # Block size 882 p = 1 # Parallelization factor 883 dk = hashlib.scrypt(password_bytes, salt=salt, n=N, r=r, p=p, dklen=key_length) 884 await i(db_request__user_sign_up_info.put(login, (dk, salt, N, r, p, key_length))) 885 user_id: Hashable = uuid4().bytes 886 credentials: Tuple = (login, dk) 887 await i(db_request__credentials_by_user_id.put(user_id, credentials)) 888 user_sign_in_info: Union[Dict, Tuple, List] = await arun_coro_fast(i, user_sign_in_info_maker, login, user_id, datetime.now()) 889 await self.auser_signed_up(i, credentials, user_sign_in_info) 890 return True
892 def try_sign_in__login_password(self, i: Interface, login: str, password: str) -> Union[Dict, Tuple, List]: 893 user_found: bool = False 894 try: 895 dk, salt, N, r, p, key_length = i(db_request__user_sign_up_info.get(login)) 896 user_found = True 897 except KeyError: 898 pass 899 900 if not user_found: 901 raise UserNotFoundError 902 903 password_bytes = password.encode('utf-8') 904 dk_0 = hashlib.scrypt(password_bytes, salt=salt, n=N, r=r, p=p, dklen=key_length) 905 if dk != dk_0: 906 raise PasswordIsNotCorrectError 907 908 credentials: Tuple = (login, dk) 909 return self.try_sign_in(i, credentials)
911 async def atry_sign_in__login_password(self, i: Interface, login: str, password: str) -> Union[Dict, Tuple, List]: 912 user_found: bool = False 913 try: 914 dk, salt, N, r, p, key_length = await i(db_request__user_sign_up_info.get(login)) 915 user_found = True 916 except KeyError: 917 pass 918 919 if not user_found: 920 raise UserNotFoundError 921 922 password_bytes = password.encode('utf-8') 923 dk_0 = hashlib.scrypt(password_bytes, salt=salt, n=N, r=r, p=p, dklen=key_length) 924 if dk != dk_0: 925 raise PasswordIsNotCorrectError 926 927 credentials: Tuple = (login, dk) 928 return await self.atry_sign_in(i, credentials)
968 def open_page(self, target: Optional[Union[Callable[..., Any], str]] = None, new_tab: bool = False) -> Optional[RedirectResponse]: 969 if target is None: 970 return 971 972 client = self.client 973 if client.has_socket_connection: 974 client.open(target, new_tab) 975 else: 976 return RedirectResponse(target)
978 def open_previous_page(self, default_target: Optional[Union[Callable[..., Any], str]] = None, new_tab: bool = False, can_be_current_page: bool = False) -> Optional[RedirectResponse]: 979 target: str = self.refferer() 980 current_url: str = str(self.url()) 981 if (target is None) or (False if can_be_current_page else (target == current_url)): 982 if not isinstance(default_target, str): 983 default_target = globals.page_routes[target] 984 985 target = default_target if default_target is not None else '/' 986 987 client = self.client 988 if client.has_socket_connection: 989 client.open(target, new_tab) 990 else: 991 return self.open_previous_page_http_response(default_target, can_be_current_page)
993 def open_previous_page_http_response(self, default_target: Optional[Union[Callable[..., Any], str]] = None, can_be_current_page: bool = False) -> RedirectResponse: 994 refferer: str = self.refferer() 995 current_url: str = str(self.url()) 996 if (refferer is None) or (False if can_be_current_page else (refferer == current_url)): 997 refferer = default_target if default_target is not None else '/' 998 999 return RedirectResponse(refferer)
1336def run(*, 1337 host: str = '0.0.0.0', 1338 port_or_range: Union[int, slice, Tuple[int, int]] = 8080, 1339 main_coro: AnyWorker = None, 1340 is_fast_loop: bool = True, 1341 app_name: str = str(), 1342 app_name_for_fs: str = str(), 1343 app_version: Tuple[int, int, int, Union[int, str]] = tuple(), 1344 app_version_str: str = str(), 1345 **kwargs 1346 ) -> None: 1347 """Prepares and starts NiceGUI. Saves initial args and kwargs parameters (as well as determined free port) into a tuple (Tuple[Tuple, Dict]) within an Instance service awailable by a 'cengal_nicegui__app_args_kwargs' string key 1348 1349 Args: 1350 host (str, optional): _description_. Defaults to '0.0.0.0'. 1351 port_or_range (Union[int, slice, Tuple[int, int]], optional): _description_. Defaults to 8080. 1352 title (str, optional): _description_. Defaults to 'NiceGUI'. 1353 viewport (str, optional): _description_. Defaults to 'width=device-width, initial-scale=1'. 1354 favicon (Optional[str], optional): _description_. Defaults to None. 1355 dark (Optional[bool], optional): _description_. Defaults to False. 1356 binding_refresh_interval (float, optional): _description_. Defaults to 0.1. 1357 show (bool, optional): _description_. Defaults to True. 1358 reload (bool, optional): _description_. Defaults to True. 1359 uvicorn_logging_level (str, optional): _description_. Defaults to 'warning'. 1360 uvicorn_reload_dirs (str, optional): _description_. Defaults to '.'. 1361 uvicorn_reload_includes (str, optional): _description_. Defaults to '*.py'. 1362 uvicorn_reload_excludes (str, optional): _description_. Defaults to '.*, .py[cod], .sw.*, ~*'. 1363 tailwind (bool, optional): _description_. Defaults to True. 1364 is_fast_loop (bool, optional): _description_. Defaults to True. 1365 main_coro (AnyWorker, optional): _description_. Defaults to None. 1366 """ 1367 port = simple_port_search(host, port_or_range) 1368 app_args_kwargs: Tuple[Tuple, Dict] = args_kwargs( 1369 host=host, 1370 port_or_range=port_or_range, 1371 port=port, 1372 main_coro=main_coro, 1373 is_fast_loop=is_fast_loop, 1374 app_name=app_name, 1375 app_name_for_fs=app_name_for_fs, 1376 app_version=app_version, 1377 app_version_str=app_version_str, 1378 **kwargs, 1379 ) 1380 run_in_loop(init_translation, app_args_kwargs) 1381 app.on_startup(init_cs(is_fast_loop, main_coro, app_args_kwargs)) 1382 app.on_shutdown(destroy_cs) 1383 # app.on_connect(on_connect_handler) 1384 app.on_disconnect(on_disconnect_handler) 1385 ui.run( 1386 host=host, 1387 port=port, 1388 **kwargs, 1389 )
Prepares and starts NiceGUI. Saves initial args and kwargs parameters (as well as determined free port) into a tuple (Tuple[Tuple, Dict]) within an Instance service awailable by a 'cengal_nicegui__app_args_kwargs' string key
Args: host (str, optional): _description_. Defaults to '0.0.0.0'. port_or_range (Union[int, slice, Tuple[int, int]], optional): _description_. Defaults to 8080. title (str, optional): _description_. Defaults to 'NiceGUI'. viewport (str, optional): _description_. Defaults to 'width=device-width, initial-scale=1'. favicon (Optional[str], optional): _description_. Defaults to None. dark (Optional[bool], optional): _description_. Defaults to False. binding_refresh_interval (float, optional): _description_. Defaults to 0.1. show (bool, optional): _description_. Defaults to True. reload (bool, optional): _description_. Defaults to True. uvicorn_logging_level (str, optional): _description_. Defaults to 'warning'. uvicorn_reload_dirs (str, optional): _description_. Defaults to '.'. uvicorn_reload_includes (str, optional): _description_. Defaults to '.py'. uvicorn_reload_excludes (str, optional): _description_. Defaults to '., .py[cod], .sw., ~'. tailwind (bool, optional): _description_. Defaults to True. is_fast_loop (bool, optional): _description_. Defaults to True. main_coro (AnyWorker, optional): _description_. Defaults to None.