github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/observer/observer.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package observer
     5  
     6  import (
     7  	"net/http"
     8  	"sync"
     9  
    10  	"gopkg.in/juju/names.v2"
    11  
    12  	"github.com/juju/juju/rpc"
    13  )
    14  
    15  // Observer defines a type which will observe API server events as
    16  // they happen.
    17  type Observer interface {
    18  	rpc.ObserverFactory
    19  
    20  	// Login informs an Observer that an entity has logged in.
    21  	Login(entity names.Tag, model names.ModelTag, fromController bool, userData string)
    22  
    23  	// Join is called when the connection to the API server's
    24  	// WebSocket is opened.
    25  	Join(req *http.Request, connectionID uint64)
    26  
    27  	// Leave is called when the connection to the API server's
    28  	// WebSocket is closed.
    29  	Leave()
    30  }
    31  
    32  // ObserverFactory is a function which creates an Observer.
    33  type ObserverFactory func() Observer
    34  
    35  // ObserverFactoryMultiplexer returns an ObserverFactory which will
    36  // return a Multiplexer of all the observers instantiated from the
    37  // factories passed in.
    38  func ObserverFactoryMultiplexer(factories ...ObserverFactory) ObserverFactory {
    39  	return func() Observer {
    40  		observers := make([]Observer, 0, len(factories))
    41  		for _, newObserver := range factories {
    42  			observers = append(observers, newObserver())
    43  		}
    44  		return NewMultiplexer(observers...)
    45  	}
    46  }
    47  
    48  // None is a wrapper around the Multiplexer factory to add clarity to
    49  // code that doesn't need any observers.
    50  func None() *Multiplexer {
    51  	return NewMultiplexer()
    52  }
    53  
    54  // NewMultiplexer creates a new Multiplexer with the provided
    55  // observers.
    56  func NewMultiplexer(observers ...Observer) *Multiplexer {
    57  	return &Multiplexer{
    58  		observers: removeNilObservers(observers),
    59  	}
    60  }
    61  
    62  func removeNilObservers(observers []Observer) []Observer {
    63  	var validatedObservers []Observer
    64  	for _, o := range observers {
    65  		if o == nil {
    66  			continue
    67  		}
    68  		validatedObservers = append(validatedObservers, o)
    69  	}
    70  	return validatedObservers
    71  }
    72  
    73  // Multiplexer multiplexes calls to an arbitrary number of observers.
    74  type Multiplexer struct {
    75  	observers []Observer
    76  }
    77  
    78  // Join is called when the connection to the API server's WebSocket is
    79  // opened.
    80  func (m *Multiplexer) Join(req *http.Request, connectionID uint64) {
    81  	mapConcurrent(func(o Observer) { o.Join(req, connectionID) }, m.observers)
    82  }
    83  
    84  // Leave implements Observer.
    85  func (m *Multiplexer) Leave() {
    86  	mapConcurrent(Observer.Leave, m.observers)
    87  }
    88  
    89  // Login implements Observer.
    90  func (m *Multiplexer) Login(entity names.Tag, model names.ModelTag, fromController bool, userData string) {
    91  	mapConcurrent(func(o Observer) { o.Login(entity, model, fromController, userData) }, m.observers)
    92  }
    93  
    94  // RPCObserver implements Observer. It will create an
    95  // rpc.ObserverMultiplexer by calling all the Observer's RPCObserver
    96  // methods.
    97  func (m *Multiplexer) RPCObserver() rpc.Observer {
    98  	rpcObservers := make([]rpc.Observer, len(m.observers))
    99  	for i, o := range m.observers {
   100  		rpcObservers[i] = o.RPCObserver()
   101  	}
   102  	return rpc.NewObserverMultiplexer(rpcObservers...)
   103  }
   104  
   105  // mapConcurrent calls fn on all observers concurrently and then waits
   106  // for all calls to exit before returning.
   107  func mapConcurrent(fn func(Observer), observers []Observer) {
   108  	var wg sync.WaitGroup
   109  	wg.Add(len(observers))
   110  	defer wg.Wait()
   111  
   112  	for _, o := range observers {
   113  		go func(obs Observer) {
   114  			defer wg.Done()
   115  			fn(obs)
   116  		}(o)
   117  	}
   118  }