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.

195 lines
4.1 KiB

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