github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/common/relationunitswatcher.go (about) 1 // Copyright 2019 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package common 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/worker/v3" 9 "github.com/juju/worker/v3/catacomb" 10 11 "github.com/juju/juju/core/watcher" 12 "github.com/juju/juju/rpc/params" 13 "github.com/juju/juju/state" 14 ) 15 16 // RelationUnitsWatcher represents a state.RelationUnitsWatcher at the 17 // apiserver level (different type for changes). 18 type RelationUnitsWatcher interface { 19 watcher.CoreWatcher 20 Changes() <-chan params.RelationUnitsChange 21 22 // Stop is needed to implement facade.Resource. 23 Stop() error 24 25 // Err implements watcher.Errer. 26 Err() error 27 } 28 29 // RelationUnitsWatcherFromState wraps a state-level 30 // RelationUnitsWatcher in an equivalent apiserver-level one, taking 31 // responsibility for the source watcher's lifetime. 32 func RelationUnitsWatcherFromState(source state.RelationUnitsWatcher) (RelationUnitsWatcher, error) { 33 w := &relationUnitsWatcher{ 34 source: source, 35 out: make(chan params.RelationUnitsChange), 36 } 37 err := catacomb.Invoke(catacomb.Plan{ 38 Site: &w.catacomb, 39 Work: w.loop, 40 Init: []worker.Worker{source}, 41 }) 42 return w, errors.Trace(err) 43 } 44 45 type relationUnitsWatcher struct { 46 source state.RelationUnitsWatcher 47 out chan params.RelationUnitsChange 48 catacomb catacomb.Catacomb 49 } 50 51 func (w *relationUnitsWatcher) loop() error { 52 // We need to close the changes channel because we're inside the 53 // API - see apiserver/watcher.go:srvRelationUnitsWatcher.Next() 54 defer close(w.out) 55 for { 56 select { 57 case <-w.catacomb.Dying(): 58 return w.catacomb.ErrDying() 59 case event, ok := <-w.source.Changes(): 60 if !ok { 61 return w.catacomb.ErrDying() 62 } 63 select { 64 case <-w.catacomb.Dying(): 65 return w.catacomb.ErrDying() 66 case w.out <- w.convert(event): 67 } 68 } 69 } 70 } 71 72 func (w *relationUnitsWatcher) convert( 73 event watcher.RelationUnitsChange, 74 ) params.RelationUnitsChange { 75 var changed map[string]params.UnitSettings 76 if event.Changed != nil { 77 changed = make(map[string]params.UnitSettings, len(event.Changed)) 78 for key, val := range event.Changed { 79 changed[key] = params.UnitSettings{Version: val.Version} 80 } 81 } 82 return params.RelationUnitsChange{ 83 Changed: changed, 84 AppChanged: event.AppChanged, 85 Departed: event.Departed, 86 } 87 } 88 89 // Changes is part of RelationUnitsWatcher. 90 func (w *relationUnitsWatcher) Changes() <-chan params.RelationUnitsChange { 91 return w.out 92 } 93 94 // Kill is part of worker.Worker. 95 func (w *relationUnitsWatcher) Kill() { 96 w.catacomb.Kill(nil) 97 } 98 99 // Wait is part of worker.Worker. 100 func (w *relationUnitsWatcher) Wait() error { 101 return w.catacomb.Wait() 102 } 103 104 // Stop is part of facade.Resource. 105 func (w *relationUnitsWatcher) Stop() error { 106 w.Kill() 107 return w.Wait() 108 } 109 110 // Err is part of state/watcher.Errer. 111 func (w *relationUnitsWatcher) Err() error { 112 return w.catacomb.Err() 113 }