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.

212 lines
4.5 KiB

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