You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

205 lines
4.4 KiB

  1. package events
  2. import (
  3. "sync"
  4. . "github.com/tendermint/tendermint/common"
  5. "github.com/tendermint/tendermint/types"
  6. )
  7. // reactors and other modules should export
  8. // this interface to become eventable
  9. type Eventable interface {
  10. SetFireable(Fireable)
  11. }
  12. // an event switch or cache implements fireable
  13. type Fireable interface {
  14. FireEvent(event string, data types.EventData)
  15. }
  16. type EventSwitch struct {
  17. BaseService
  18. mtx sync.RWMutex
  19. eventCells map[string]*eventCell
  20. listeners map[string]*eventListener
  21. }
  22. func NewEventSwitch() *EventSwitch {
  23. evsw := &EventSwitch{}
  24. evsw.BaseService = *NewBaseService(log, "EventSwitch", evsw)
  25. return evsw
  26. }
  27. func (evsw *EventSwitch) OnStart() error {
  28. evsw.BaseService.OnStart()
  29. evsw.eventCells = make(map[string]*eventCell)
  30. evsw.listeners = make(map[string]*eventListener)
  31. return nil
  32. }
  33. func (evsw *EventSwitch) OnStop() {
  34. evsw.BaseService.OnStop()
  35. evsw.eventCells = nil
  36. evsw.listeners = nil
  37. }
  38. func (evsw *EventSwitch) AddListenerForEvent(listenerId, event string, cb eventCallback) {
  39. // Get/Create eventCell and listener
  40. evsw.mtx.Lock()
  41. eventCell := evsw.eventCells[event]
  42. if eventCell == nil {
  43. eventCell = newEventCell()
  44. evsw.eventCells[event] = eventCell
  45. }
  46. listener := evsw.listeners[listenerId]
  47. if listener == nil {
  48. listener = newEventListener(listenerId)
  49. evsw.listeners[listenerId] = listener
  50. }
  51. evsw.mtx.Unlock()
  52. // Add event and listener
  53. eventCell.AddListener(listenerId, cb)
  54. listener.AddEvent(event)
  55. }
  56. func (evsw *EventSwitch) RemoveListener(listenerId string) {
  57. // Get and remove listener
  58. evsw.mtx.RLock()
  59. listener := evsw.listeners[listenerId]
  60. delete(evsw.listeners, listenerId)
  61. evsw.mtx.RUnlock()
  62. if listener == nil {
  63. return
  64. }
  65. // Remove callback for each event.
  66. listener.SetRemoved()
  67. for _, event := range listener.GetEvents() {
  68. evsw.RemoveListenerForEvent(event, listenerId)
  69. }
  70. }
  71. func (evsw *EventSwitch) RemoveListenerForEvent(event string, listenerId string) {
  72. // Get eventCell
  73. evsw.mtx.Lock()
  74. eventCell := evsw.eventCells[event]
  75. evsw.mtx.Unlock()
  76. if eventCell == nil {
  77. return
  78. }
  79. // Remove listenerId from eventCell
  80. numListeners := eventCell.RemoveListener(listenerId)
  81. // Maybe garbage collect eventCell.
  82. if numListeners == 0 {
  83. // Lock again and double check.
  84. evsw.mtx.Lock() // OUTER LOCK
  85. eventCell.mtx.Lock() // INNER LOCK
  86. if len(eventCell.listeners) == 0 {
  87. delete(evsw.eventCells, event)
  88. }
  89. eventCell.mtx.Unlock() // INNER LOCK
  90. evsw.mtx.Unlock() // OUTER LOCK
  91. }
  92. }
  93. func (evsw *EventSwitch) FireEvent(event string, data types.EventData) {
  94. // Get the eventCell
  95. evsw.mtx.RLock()
  96. eventCell := evsw.eventCells[event]
  97. evsw.mtx.RUnlock()
  98. if eventCell == nil {
  99. return
  100. }
  101. // Fire event for all listeners in eventCell
  102. eventCell.FireEvent(data)
  103. }
  104. //-----------------------------------------------------------------------------
  105. // eventCell handles keeping track of listener callbacks for a given event.
  106. type eventCell struct {
  107. mtx sync.RWMutex
  108. listeners map[string]eventCallback
  109. }
  110. func newEventCell() *eventCell {
  111. return &eventCell{
  112. listeners: make(map[string]eventCallback),
  113. }
  114. }
  115. func (cell *eventCell) AddListener(listenerId string, cb eventCallback) {
  116. cell.mtx.Lock()
  117. cell.listeners[listenerId] = cb
  118. cell.mtx.Unlock()
  119. }
  120. func (cell *eventCell) RemoveListener(listenerId string) int {
  121. cell.mtx.Lock()
  122. delete(cell.listeners, listenerId)
  123. numListeners := len(cell.listeners)
  124. cell.mtx.Unlock()
  125. return numListeners
  126. }
  127. func (cell *eventCell) FireEvent(data types.EventData) {
  128. cell.mtx.RLock()
  129. for _, listener := range cell.listeners {
  130. listener(data)
  131. }
  132. cell.mtx.RUnlock()
  133. }
  134. //-----------------------------------------------------------------------------
  135. type eventCallback func(data types.EventData)
  136. type eventListener struct {
  137. id string
  138. mtx sync.RWMutex
  139. removed bool
  140. events []string
  141. }
  142. func newEventListener(id string) *eventListener {
  143. return &eventListener{
  144. id: id,
  145. removed: false,
  146. events: nil,
  147. }
  148. }
  149. func (evl *eventListener) AddEvent(event string) {
  150. evl.mtx.Lock()
  151. defer evl.mtx.Unlock()
  152. if evl.removed {
  153. return
  154. }
  155. evl.events = append(evl.events, event)
  156. }
  157. func (evl *eventListener) GetEvents() []string {
  158. evl.mtx.RLock()
  159. defer evl.mtx.RUnlock()
  160. events := make([]string, len(evl.events))
  161. copy(events, evl.events)
  162. return events
  163. }
  164. func (evl *eventListener) SetRemoved() {
  165. evl.mtx.Lock()
  166. defer evl.mtx.Unlock()
  167. evl.removed = true
  168. }