hydrate_middleware.py 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. """Middleware to hydrate the state."""
  2. from __future__ import annotations
  3. from typing import TYPE_CHECKING, Dict, List, Optional, Union
  4. from pynecone import constants
  5. from pynecone.event import Event, EventHandler, get_hydrate_event
  6. from pynecone.middleware.middleware import Middleware
  7. from pynecone.state import State, StateUpdate
  8. from pynecone.utils import format
  9. if TYPE_CHECKING:
  10. from pynecone.app import App
  11. class HydrateMiddleware(Middleware):
  12. """Middleware to handle initial app hydration."""
  13. async def preprocess(
  14. self, app: App, state: State, event: Event
  15. ) -> Optional[Union[StateUpdate, List[StateUpdate]]]:
  16. """Preprocess the event.
  17. Args:
  18. app: The app to apply the middleware to.
  19. state: The client state.
  20. event: The event to preprocess.
  21. Returns:
  22. An optional delta or list of state updates to return.
  23. """
  24. if event.name == get_hydrate_event(state):
  25. route = event.router_data.get(constants.RouteVar.PATH, "")
  26. if route == "/":
  27. load_event = app.load_events.get(constants.INDEX_ROUTE)
  28. elif route:
  29. load_event = app.load_events.get(route.lstrip("/"))
  30. else:
  31. load_event = None
  32. if load_event:
  33. if not isinstance(load_event, List):
  34. load_event = [load_event]
  35. updates = []
  36. for single_event in load_event:
  37. updates.append(
  38. await self.execute_load_event(
  39. state, single_event, event.token, event.payload
  40. )
  41. )
  42. return updates
  43. delta = format.format_state({state.get_name(): state.dict()})
  44. return StateUpdate(delta=delta) if delta else None
  45. async def execute_load_event(
  46. self, state: State, load_event: EventHandler, token: str, payload: Dict
  47. ) -> StateUpdate:
  48. """Execute single load event.
  49. Args:
  50. state: The client state.
  51. load_event: A single load event to execute.
  52. token: Client token
  53. payload: The event payload
  54. Returns:
  55. A state Update.
  56. Raises:
  57. ValueError: If the state value is None.
  58. """
  59. substate_path = format.format_event_handler(load_event).split(".")
  60. ex_state = state.get_substate(substate_path[:-1])
  61. if not ex_state:
  62. raise ValueError(
  63. "The value of state cannot be None when processing an on-load event."
  64. )
  65. return await state._process_event(
  66. handler=load_event, state=ex_state, payload=payload, token=token
  67. )