github.com/argoproj/argo-cd/v2@v2.10.9/server/application/broadcaster.go (about) 1 package application 2 3 import ( 4 "sync" 5 6 log "github.com/sirupsen/logrus" 7 "k8s.io/apimachinery/pkg/watch" 8 9 appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" 10 ) 11 12 type subscriber struct { 13 ch chan *appv1.ApplicationWatchEvent 14 filters []func(*appv1.ApplicationWatchEvent) bool 15 } 16 17 func (s *subscriber) matches(event *appv1.ApplicationWatchEvent) bool { 18 for i := range s.filters { 19 if !s.filters[i](event) { 20 return false 21 } 22 } 23 return true 24 } 25 26 // Broadcaster is an interface for broadcasting application informer watch events to multiple subscribers. 27 type Broadcaster interface { 28 Subscribe(ch chan *appv1.ApplicationWatchEvent, filters ...func(event *appv1.ApplicationWatchEvent) bool) func() 29 OnAdd(interface{}) 30 OnUpdate(interface{}, interface{}) 31 OnDelete(interface{}) 32 } 33 34 type broadcasterHandler struct { 35 lock sync.Mutex 36 subscribers []*subscriber 37 } 38 39 func (b *broadcasterHandler) notify(event *appv1.ApplicationWatchEvent) { 40 // Make a local copy of b.subscribers, then send channel events outside the lock, 41 // to avoid data race on b.subscribers changes 42 subscribers := []*subscriber{} 43 b.lock.Lock() 44 subscribers = append(subscribers, b.subscribers...) 45 b.lock.Unlock() 46 47 for _, s := range subscribers { 48 if s.matches(event) { 49 select { 50 case s.ch <- event: 51 default: 52 // drop event if cannot send right away 53 log.WithField("application", event.Application.Name).Warn("unable to send event notification") 54 } 55 } 56 } 57 } 58 59 // Subscribe forward application informer watch events to the provided channel. 60 // The watch events are dropped if no receives are reading events from the channel so the channel must have 61 // buffer if dropping events is not acceptable. 62 func (b *broadcasterHandler) Subscribe(ch chan *appv1.ApplicationWatchEvent, filters ...func(event *appv1.ApplicationWatchEvent) bool) func() { 63 b.lock.Lock() 64 defer b.lock.Unlock() 65 subscriber := &subscriber{ch, filters} 66 b.subscribers = append(b.subscribers, subscriber) 67 return func() { 68 b.lock.Lock() 69 defer b.lock.Unlock() 70 for i := range b.subscribers { 71 if b.subscribers[i] == subscriber { 72 b.subscribers = append(b.subscribers[:i], b.subscribers[i+1:]...) 73 break 74 } 75 } 76 } 77 } 78 79 func (b *broadcasterHandler) OnAdd(obj interface{}) { 80 if app, ok := obj.(*appv1.Application); ok { 81 b.notify(&appv1.ApplicationWatchEvent{Application: *app, Type: watch.Added}) 82 } 83 } 84 85 func (b *broadcasterHandler) OnUpdate(_, newObj interface{}) { 86 if app, ok := newObj.(*appv1.Application); ok { 87 b.notify(&appv1.ApplicationWatchEvent{Application: *app, Type: watch.Modified}) 88 } 89 } 90 91 func (b *broadcasterHandler) OnDelete(obj interface{}) { 92 if app, ok := obj.(*appv1.Application); ok { 93 b.notify(&appv1.ApplicationWatchEvent{Application: *app, Type: watch.Deleted}) 94 } 95 }