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 }