data.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. """This module contains the dataclasses representing the router object."""
  2. import dataclasses
  3. from collections.abc import Mapping
  4. from reflex import constants
  5. from reflex.utils import format
  6. from reflex.utils.serializers import serializer
  7. @dataclasses.dataclass(frozen=True, init=False)
  8. class _FrozenDictStrStr(Mapping[str, str]):
  9. _data: tuple[tuple[str, str], ...]
  10. def __init__(self, **kwargs):
  11. object.__setattr__(self, "_data", tuple(sorted(kwargs.items())))
  12. def __getitem__(self, key: str) -> str:
  13. return dict(self._data)[key]
  14. def __iter__(self):
  15. return (x[0] for x in self._data)
  16. def __len__(self):
  17. return len(self._data)
  18. @dataclasses.dataclass(frozen=True)
  19. class _HeaderData:
  20. host: str = ""
  21. origin: str = ""
  22. upgrade: str = ""
  23. connection: str = ""
  24. cookie: str = ""
  25. pragma: str = ""
  26. cache_control: str = ""
  27. user_agent: str = ""
  28. sec_websocket_version: str = ""
  29. sec_websocket_key: str = ""
  30. sec_websocket_extensions: str = ""
  31. accept_encoding: str = ""
  32. accept_language: str = ""
  33. raw_headers: Mapping[str, str] = dataclasses.field(
  34. default_factory=_FrozenDictStrStr
  35. )
  36. @dataclasses.dataclass(frozen=True, init=False)
  37. class HeaderData(_HeaderData):
  38. """An object containing headers data."""
  39. def __init__(self, router_data: dict | None = None):
  40. """Initialize the HeaderData object based on router_data.
  41. Args:
  42. router_data: the router_data dict.
  43. """
  44. super().__init__()
  45. if router_data:
  46. fields_names = [f.name for f in dataclasses.fields(self)]
  47. for k, v in router_data.get(constants.RouteVar.HEADERS, {}).items():
  48. snake_case_key = format.to_snake_case(k)
  49. if snake_case_key in fields_names:
  50. object.__setattr__(self, snake_case_key, v)
  51. object.__setattr__(
  52. self,
  53. "raw_headers",
  54. _FrozenDictStrStr(
  55. **{
  56. k: v
  57. for k, v in router_data.get(
  58. constants.RouteVar.HEADERS, {}
  59. ).items()
  60. if v
  61. }
  62. ),
  63. )
  64. @serializer(to=dict)
  65. def serialize_frozen_dict_str_str(obj: _FrozenDictStrStr) -> dict:
  66. """Serialize a _FrozenDictStrStr object to a dict.
  67. Args:
  68. obj: the _FrozenDictStrStr object.
  69. Returns:
  70. A dict representation of the _FrozenDictStrStr object.
  71. """
  72. return dict(obj._data)
  73. @dataclasses.dataclass(frozen=True)
  74. class PageData:
  75. """An object containing page data."""
  76. host: str = "" # repeated with self.headers.origin (remove or keep the duplicate?)
  77. path: str = ""
  78. raw_path: str = ""
  79. full_path: str = ""
  80. full_raw_path: str = ""
  81. params: dict = dataclasses.field(default_factory=dict)
  82. def __init__(self, router_data: dict | None = None):
  83. """Initialize the PageData object based on router_data.
  84. Args:
  85. router_data: the router_data dict.
  86. """
  87. if router_data:
  88. object.__setattr__(
  89. self,
  90. "host",
  91. router_data.get(constants.RouteVar.HEADERS, {}).get("origin", ""),
  92. )
  93. object.__setattr__(
  94. self, "path", router_data.get(constants.RouteVar.PATH, "")
  95. )
  96. object.__setattr__(
  97. self, "raw_path", router_data.get(constants.RouteVar.ORIGIN, "")
  98. )
  99. object.__setattr__(self, "full_path", f"{self.host}{self.path}")
  100. object.__setattr__(self, "full_raw_path", f"{self.host}{self.raw_path}")
  101. object.__setattr__(
  102. self, "params", router_data.get(constants.RouteVar.QUERY, {})
  103. )
  104. else:
  105. object.__setattr__(self, "host", "")
  106. object.__setattr__(self, "path", "")
  107. object.__setattr__(self, "raw_path", "")
  108. object.__setattr__(self, "full_path", "")
  109. object.__setattr__(self, "full_raw_path", "")
  110. object.__setattr__(self, "params", {})
  111. @dataclasses.dataclass(frozen=True, init=False)
  112. class SessionData:
  113. """An object containing session data."""
  114. client_token: str = ""
  115. client_ip: str = ""
  116. session_id: str = ""
  117. def __init__(self, router_data: dict | None = None):
  118. """Initialize the SessionData object based on router_data.
  119. Args:
  120. router_data: the router_data dict.
  121. """
  122. if router_data:
  123. client_token = router_data.get(constants.RouteVar.CLIENT_TOKEN, "")
  124. client_ip = router_data.get(constants.RouteVar.CLIENT_IP, "")
  125. session_id = router_data.get(constants.RouteVar.SESSION_ID, "")
  126. else:
  127. client_token = client_ip = session_id = ""
  128. object.__setattr__(self, "client_token", client_token)
  129. object.__setattr__(self, "client_ip", client_ip)
  130. object.__setattr__(self, "session_id", session_id)
  131. @dataclasses.dataclass(frozen=True, init=False)
  132. class RouterData:
  133. """An object containing RouterData."""
  134. session: SessionData = dataclasses.field(default_factory=SessionData)
  135. headers: HeaderData = dataclasses.field(default_factory=HeaderData)
  136. page: PageData = dataclasses.field(default_factory=PageData)
  137. def __init__(self, router_data: dict | None = None):
  138. """Initialize the RouterData object.
  139. Args:
  140. router_data: the router_data dict.
  141. """
  142. object.__setattr__(self, "session", SessionData(router_data))
  143. object.__setattr__(self, "headers", HeaderData(router_data))
  144. object.__setattr__(self, "page", PageData(router_data))