app.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. from pathlib import Path
  2. from typing import Awaitable, Callable, Optional, Union
  3. from uuid import uuid4
  4. from fastapi import FastAPI, Request
  5. from fastapi.responses import StreamingResponse
  6. from fastapi.staticfiles import StaticFiles
  7. from nicegui import helpers
  8. from . import globals
  9. from .native import Native
  10. from .storage import Storage
  11. class App(FastAPI):
  12. def __init__(self, **kwargs) -> None:
  13. super().__init__(**kwargs)
  14. self.native = Native()
  15. self.storage = Storage()
  16. def on_connect(self, handler: Union[Callable, Awaitable]) -> None:
  17. """Called every time a new client connects to NiceGUI.
  18. The callback has an optional parameter of `nicegui.Client`.
  19. """
  20. globals.connect_handlers.append(handler)
  21. def on_disconnect(self, handler: Union[Callable, Awaitable]) -> None:
  22. """Called every time a new client disconnects from NiceGUI.
  23. The callback has an optional parameter of `nicegui.Client`.
  24. """
  25. globals.disconnect_handlers.append(handler)
  26. def on_startup(self, handler: Union[Callable, Awaitable]) -> None:
  27. """Called when NiceGUI is started or restarted.
  28. Needs to be called before `ui.run()`.
  29. """
  30. if globals.state == globals.State.STARTED:
  31. raise RuntimeError('Unable to register another startup handler. NiceGUI has already been started.')
  32. globals.startup_handlers.append(handler)
  33. def on_shutdown(self, handler: Union[Callable, Awaitable]) -> None:
  34. """Called when NiceGUI is shut down or restarted.
  35. When NiceGUI is shut down or restarted, all tasks still in execution will be automatically canceled.
  36. """
  37. globals.shutdown_handlers.append(handler)
  38. def on_exception(self, handler: Callable) -> None:
  39. """Called when an exception occurs.
  40. The callback has an optional parameter of `Exception`.
  41. """
  42. globals.exception_handlers.append(handler)
  43. def shutdown(self) -> None:
  44. """Shut down NiceGUI.
  45. This will programmatically stop the server.
  46. Only possible when auto-reload is disabled.
  47. """
  48. if globals.reload:
  49. raise Exception('calling shutdown() is not supported when auto-reload is enabled')
  50. globals.server.should_exit = True
  51. def add_static_files(self, url_path: str, local_directory: str) -> None:
  52. """Add static files.
  53. `add_static_files()` makes a local directory available at the specified endpoint, e.g. `'/static'`.
  54. This is useful for providing local data like images to the frontend.
  55. Otherwise the browser would not be able to access the files.
  56. Do only put non-security-critical files in there, as they are accessible to everyone.
  57. :param url_path: string that starts with a slash "/" and identifies the path at which the files should be served
  58. :param local_directory: local folder with files to serve as static content
  59. """
  60. if url_path == '/':
  61. raise ValueError('''Path cannot be "/", because it would hide NiceGUI's internal "/_nicegui" route.''')
  62. globals.app.mount(url_path, StaticFiles(directory=local_directory))
  63. def add_media_files(self, url_path: str, local_directory: Union[str, Path]) -> None:
  64. """Add media files.
  65. `add_media_files()` allows a local files to be streamed from a specified endpoint, e.g. `'/media'`.
  66. """
  67. @self.get(f'{url_path}/' + '{filename}')
  68. async def read_item(request: Request, filename: str) -> StreamingResponse:
  69. filepath = Path(local_directory) / filename
  70. ic(filepath)
  71. if not filepath.is_file():
  72. return {"detail": "Not Found"}, 404
  73. ic(filepath)
  74. return helpers.get_streaming_response(filepath, request)
  75. def add_media_file(self, local_file: str, url_path: Optional[str] = None) -> None:
  76. file = Path(local_file)
  77. if not file.is_file():
  78. raise ValueError(f'File not found: {local_file}')
  79. if url_path is None:
  80. url_path = '/_nicegui/auto/media/' + uuid4().hex
  81. @self.get(url_path)
  82. async def read_item(request: Request) -> StreamingResponse:
  83. return helpers.get_streaming_response(file, request)
  84. return url_path
  85. def remove_route(self, path: str) -> None:
  86. """Remove routes with the given path."""
  87. self.routes[:] = [r for r in self.routes if getattr(r, 'path', None) != path]