github.com/argoproj/argo-cd@v1.8.7/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/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  type broadcasterHandler struct {
    27  	lock        sync.Mutex
    28  	subscribers []*subscriber
    29  }
    30  
    31  func (b *broadcasterHandler) notify(event *appv1.ApplicationWatchEvent) {
    32  	// Make a local copy of b.subscribers, then send channel events outside the lock,
    33  	// to avoid data race on b.subscribers changes
    34  	subscribers := []*subscriber{}
    35  	b.lock.Lock()
    36  	subscribers = append(subscribers, b.subscribers...)
    37  	b.lock.Unlock()
    38  
    39  	for _, s := range subscribers {
    40  		if s.matches(event) {
    41  			select {
    42  			case s.ch <- event:
    43  			default:
    44  				// drop event if cannot send right away
    45  				log.WithField("application", event.Application.Name).Warn("unable to send event notification")
    46  			}
    47  		}
    48  	}
    49  }
    50  
    51  // Subscribe forward application informer watch events to the provided channel.
    52  // The watch events are dropped if no receives are reading events from the channel so the channel must have
    53  // buffer if dropping events is not acceptable.
    54  func (b *broadcasterHandler) Subscribe(ch chan *appv1.ApplicationWatchEvent, filters ...func(event *appv1.ApplicationWatchEvent) bool) func() {
    55  	b.lock.Lock()
    56  	defer b.lock.Unlock()
    57  	subscriber := &subscriber{ch, filters}
    58  	b.subscribers = append(b.subscribers, subscriber)
    59  	return func() {
    60  		b.lock.Lock()
    61  		defer b.lock.Unlock()
    62  		for i := range b.subscribers {
    63  			if b.subscribers[i] == subscriber {
    64  				b.subscribers = append(b.subscribers[:i], b.subscribers[i+1:]...)
    65  				break
    66  			}
    67  		}
    68  	}
    69  }
    70  
    71  func (b *broadcasterHandler) OnAdd(obj interface{}) {
    72  	if app, ok := obj.(*appv1.Application); ok {
    73  		b.notify(&appv1.ApplicationWatchEvent{Application: *app, Type: watch.Added})
    74  	}
    75  }
    76  
    77  func (b *broadcasterHandler) OnUpdate(_, newObj interface{}) {
    78  	if app, ok := newObj.(*appv1.Application); ok {
    79  		b.notify(&appv1.ApplicationWatchEvent{Application: *app, Type: watch.Modified})
    80  	}
    81  }
    82  
    83  func (b *broadcasterHandler) OnDelete(obj interface{}) {
    84  	if app, ok := obj.(*appv1.Application); ok {
    85  		b.notify(&appv1.ApplicationWatchEvent{Application: *app, Type: watch.Deleted})
    86  	}
    87  }