dispatcher.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. package app
  2. import (
  3. "context"
  4. "net/url"
  5. )
  6. const (
  7. dispatcherSize = 4096
  8. )
  9. // Dispatcher is the interface that describes an environment that synchronizes
  10. // UI instructions and UI elements lifecycle.
  11. type Dispatcher interface {
  12. // Context returns the context associated with the root element.
  13. Context() Context
  14. // Executes the given dispatch operation on the UI goroutine.
  15. Dispatch(d Dispatch)
  16. // Emit executes the given function and notifies the source's parent
  17. // components to update their state.
  18. Emit(src UI, fn func())
  19. // Handle registers the handler for the given action name. When an action
  20. // occurs, the handler is executed on the UI goroutine.
  21. Handle(actionName string, src UI, h ActionHandler)
  22. // Post posts the given action. The action is then handled by handlers
  23. // registered with Handle() and Context.Handle().
  24. Post(a Action)
  25. // Sets the state with the given value.
  26. SetState(state string, v any, opts ...StateOption)
  27. // Stores the specified state value into the given receiver. Panics when the
  28. // receiver is not a pointer or nil.
  29. GetState(state string, recv any)
  30. // Deletes the given state.
  31. DelState(state string)
  32. // Creates an observer that observes changes for the specified state while
  33. // the given element is mounted.
  34. ObserveState(state string, elem UI) Observer
  35. // Async launches the given function on a new goroutine.
  36. //
  37. // The difference versus just launching a goroutine is that it ensures that
  38. // the asynchronous instructions are called before the dispatcher is closed.
  39. //
  40. // This is important during component prerendering since asynchronous
  41. // operations need to complete before sending a pre-rendered page over HTTP.
  42. Async(fn func())
  43. // Wait waits for the asynchronous operations launched with Async() to
  44. // complete.
  45. Wait()
  46. start(context.Context)
  47. getCurrentPage() Page
  48. getLocalStorage() BrowserStorage
  49. getSessionStorage() BrowserStorage
  50. isServerSide() bool
  51. resolveStaticResource(string) string
  52. removeComponentUpdate(Composer)
  53. preventComponentUpdate(Composer)
  54. }
  55. // ClientDispatcher is the interface that describes a dispatcher that emulates a
  56. // client environment.
  57. type ClientDispatcher interface {
  58. Dispatcher
  59. // Consume executes all the remaining UI instructions.
  60. Consume()
  61. // ConsumeNext executes the next UI instructions.
  62. ConsumeNext()
  63. // Close consumes all the remaining UI instruction and releases allocated
  64. // resources.
  65. Close()
  66. // Mounts the given component as root element.
  67. Mount(UI)
  68. // Triggers OnNav from the root component.
  69. Nav(*url.URL)
  70. // Triggers OnAppUpdate from the root component.
  71. AppUpdate()
  72. // Triggers OnAppInstallChange from the root component.
  73. AppInstallChange()
  74. // Triggers OnAppResize from the root component.
  75. AppResize()
  76. }
  77. // NewClientTester creates a testing dispatcher that simulates a
  78. // client environment. The given UI element is mounted upon creation.
  79. func NewClientTester(n UI) ClientDispatcher {
  80. e := &engine{
  81. ActionHandlers: actionHandlers,
  82. }
  83. e.init()
  84. e.Mount(n)
  85. e.Consume()
  86. return e
  87. }
  88. // ServerDispatcher is the interface that describes a dispatcher that emulates a server environment.
  89. type ServerDispatcher interface {
  90. Dispatcher
  91. // Consume executes all the remaining UI instructions.
  92. Consume()
  93. // ConsumeNext executes the next UI instructions.
  94. ConsumeNext()
  95. // Close consumes all the remaining UI instruction and releases allocated
  96. // resources.
  97. Close()
  98. // Pre-renders the given component.
  99. PreRender()
  100. }
  101. // NewServerTester creates a testing dispatcher that simulates a
  102. // client environment.
  103. func NewServerTester(n UI) ServerDispatcher {
  104. e := &engine{
  105. IsServerSide: true,
  106. ActionHandlers: actionHandlers,
  107. }
  108. e.init()
  109. e.Mount(n)
  110. e.Consume()
  111. return e
  112. }
  113. // Dispatch represents an operation executed on the UI goroutine.
  114. type Dispatch struct {
  115. Mode DispatchMode
  116. Source UI
  117. Function func(Context)
  118. }
  119. func (d Dispatch) do() {
  120. if d.Source == nil || !d.Source.Mounted() || d.Function == nil {
  121. return
  122. }
  123. d.Function(makeContext(d.Source))
  124. }
  125. // DispatchMode represents how a dispatch is processed.
  126. type DispatchMode int
  127. const (
  128. // A dispatch mode where the dispatched operation is enqueued to be executed
  129. // as soon as possible and its associated UI element is updated at the end
  130. // of the current update cycle.
  131. Update DispatchMode = iota
  132. // A dispatch mode that schedules the dispatched operation to be executed
  133. // after the current update frame.
  134. Defer
  135. // A dispatch mode where the dispatched operation is enqueued to be executed
  136. // as soon as possible.
  137. Next
  138. )
  139. // MsgHandler represents a handler to listen to messages sent with Context.Post.
  140. type MsgHandler func(Context, any)