github.com/CyCoreSystems/ari@v4.8.4+incompatible/stdbus/bus.go (about) 1 package stdbus 2 3 import ( 4 "sync" 5 6 "github.com/CyCoreSystems/ari" 7 ) 8 9 // subscriptionEventBufferSize defines the number of events that each 10 // subscription will queue before accepting more events. 11 var subscriptionEventBufferSize = 100 12 13 // bus is an event bus for ARI events. It receives and 14 // redistributes events based on a subscription 15 // model. 16 type bus struct { 17 subs []*subscription // The list of subscriptions 18 19 rwMux sync.RWMutex 20 21 closed bool 22 } 23 24 // New creates and returns the event bus. 25 func New() ari.Bus { 26 b := &bus{ 27 subs: []*subscription{}, 28 } 29 30 return b 31 } 32 33 // Close closes out all subscriptions in the bus. 34 func (b *bus) Close() { 35 if b.closed { 36 return 37 } 38 b.closed = true 39 40 for _, s := range b.subs { 41 s.Cancel() 42 } 43 } 44 45 // Send sends the message to the bus 46 func (b *bus) Send(e ari.Event) { 47 var matched bool 48 b.rwMux.RLock() 49 50 // Disseminate the message to the subscribers 51 for _, s := range b.subs { 52 matched = false 53 for _, k := range e.Keys() { 54 if matched { 55 break 56 } 57 if s.key.Match(k) { 58 matched = true 59 for _, topic := range s.events { 60 if topic == e.GetType() || topic == ari.Events.All { 61 select { 62 case s.C <- e: 63 default: // never block 64 } 65 } 66 } 67 } 68 } 69 } 70 71 b.rwMux.RUnlock() 72 } 73 74 // Subscribe returns a subscription to the given list 75 // of event types 76 func (b *bus) Subscribe(key *ari.Key, eTypes ...string) ari.Subscription { 77 s := newSubscription(b, key, eTypes...) 78 b.add(s) 79 return s 80 } 81 82 // add appends a new subscription to the bus 83 func (b *bus) add(s *subscription) { 84 b.rwMux.Lock() 85 b.subs = append(b.subs, s) 86 b.rwMux.Unlock() 87 } 88 89 // remove deletes the given subscription from the bus 90 func (b *bus) remove(s *subscription) { 91 b.rwMux.Lock() 92 for i, si := range b.subs { 93 if s == si { 94 // Subs are pointers, so we have to explicitly remove them 95 // to prevent memory leaks 96 b.subs[i] = b.subs[len(b.subs)-1] // replace the current with the end 97 b.subs[len(b.subs)-1] = nil // remove the end 98 b.subs = b.subs[:len(b.subs)-1] // lop off the end 99 break 100 } 101 } 102 b.rwMux.Unlock() 103 } 104 105 // A Subscription is a wrapped channel for receiving 106 // events from the ARI event bus. 107 type subscription struct { 108 key *ari.Key 109 b *bus // reference to the event bus 110 events []string // list of events to listen for 111 112 mu sync.Mutex 113 closed bool // channel closure protection flag 114 C chan ari.Event // channel for sending events to the subscriber 115 } 116 117 // newSubscription creates a new, unattached subscription 118 func newSubscription(b *bus, key *ari.Key, eTypes ...string) *subscription { 119 return &subscription{ 120 key: key, 121 b: b, 122 events: eTypes, 123 C: make(chan ari.Event, subscriptionEventBufferSize), 124 } 125 } 126 127 // Events returns the events channel 128 func (s *subscription) Events() <-chan ari.Event { 129 return s.C 130 } 131 132 // Cancel cancels the subscription and removes it from 133 // the event bus. 134 func (s *subscription) Cancel() { 135 if s == nil { 136 return 137 } 138 139 s.mu.Lock() 140 if s.closed { 141 s.mu.Unlock() 142 return 143 } 144 s.closed = true 145 s.mu.Unlock() 146 147 // Remove the subscription from the bus 148 if s.b != nil { 149 s.b.remove(s) 150 } 151 152 // Close the subscription's deliver channel 153 if s.C != nil { 154 close(s.C) 155 } 156 }