Official cwtch.im peer and server implementations. https://cwtch.im
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.

120 lines
3.2KB

  1. package event
  2. import (
  3. "git.openprivacy.ca/openprivacy/libricochet-go/utils"
  4. "sync"
  5. )
  6. // Event is a structure which binds a given set of data to an Type
  7. type Event struct {
  8. EventType Type
  9. EventID string
  10. Data map[Field]string
  11. }
  12. // NewEvent creates a new event object with a unique ID and the given type and data.
  13. func NewEvent(eventType Type, data map[Field]string) Event {
  14. return Event{EventType: eventType, EventID: utils.GetRandNumber().String(), Data: data}
  15. }
  16. // NewEventList creates a new event object with a unique ID and the given type and data supplied in a list format and composed into a map of Type:string
  17. func NewEventList(eventType Type, args ...interface{}) Event {
  18. data := map[Field]string{}
  19. for i := 0; i < len(args); i += 2 {
  20. key, kok := args[i].(Field)
  21. val, vok := args[i+1].(string)
  22. if kok && vok {
  23. data[key] = val
  24. }
  25. }
  26. return Event{EventType: eventType, EventID: utils.GetRandNumber().String(), Data: data}
  27. }
  28. // Manager is an Event Bus which allows subsystems to subscribe to certain EventTypes and publish others.
  29. type manager struct {
  30. subscribers map[Type][]chan<- Event
  31. events chan Event
  32. mapMutex sync.Mutex
  33. internal chan bool
  34. closed bool
  35. }
  36. // Manager is an interface for an event bus
  37. type Manager interface {
  38. Subscribe(Type, Queue)
  39. Publish(Event)
  40. PublishLocal(Event)
  41. Shutdown()
  42. }
  43. // NewEventManager returns an initialized EventManager
  44. func NewEventManager() Manager {
  45. em := &manager{}
  46. em.initialize()
  47. return em
  48. }
  49. // Initialize sets up the Manager.
  50. func (em *manager) initialize() {
  51. em.subscribers = make(map[Type][]chan<- Event)
  52. em.events = make(chan Event)
  53. em.internal = make(chan bool)
  54. em.closed = false
  55. go em.eventBus()
  56. }
  57. // Subscribe takes an eventType and an Channel and associates them in the eventBus. All future events of that type
  58. // will be sent to the eventChannel.
  59. func (em *manager) Subscribe(eventType Type, queue Queue) {
  60. em.mapMutex.Lock()
  61. defer em.mapMutex.Unlock()
  62. em.subscribers[eventType] = append(em.subscribers[eventType], queue.InChan())
  63. }
  64. // Publish takes an Event and sends it to the internal eventBus where it is distributed to all Subscribers
  65. func (em *manager) Publish(event Event) {
  66. if event.EventType != "" && em.closed != true {
  67. em.events <- event
  68. }
  69. }
  70. // Publish an event only locally, not going over an IPC bridge if there is one
  71. func (em *manager) PublishLocal(event Event) {
  72. em.Publish(event)
  73. }
  74. // eventBus is an internal function that is used to distribute events to all subscribers
  75. func (em *manager) eventBus() {
  76. for {
  77. event := <-em.events
  78. // In the case on an empty event. Teardown the Queue
  79. if event.EventType == "" {
  80. break
  81. }
  82. // maps aren't thread safe
  83. em.mapMutex.Lock()
  84. subscribers := em.subscribers[event.EventType]
  85. em.mapMutex.Unlock()
  86. // Send the event to any subscribers to that event type
  87. for _, subscriber := range subscribers {
  88. subscriber <- event
  89. }
  90. }
  91. // We are about to exit the eventbus thread, fire off an event internally
  92. em.internal <- true
  93. }
  94. // Shutdown triggers, and waits for, the internal eventBus goroutine to finish
  95. func (em *manager) Shutdown() {
  96. em.events <- Event{}
  97. em.closed = true
  98. // wait for eventBus to finish
  99. <-em.internal
  100. close(em.events)
  101. close(em.internal)
  102. }