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.

189 lines
4.0 KiB

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