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