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 }