github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/api/allwatcher.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package api 5 6 import ( 7 "sort" 8 9 "github.com/juju/juju/api/base" 10 "github.com/juju/juju/rpc/params" 11 ) 12 13 // AllWatch represents methods used on the AllWatcher 14 // Primarily to facilitate mock tests. 15 type AllWatch interface { 16 Next() ([]params.Delta, error) 17 Stop() error 18 } 19 20 // AllWatcher holds information allowing us to get Deltas describing 21 // changes to the entire model or all models (depending on 22 // the watcher type). 23 type AllWatcher struct { 24 objType string 25 caller base.APICaller 26 id *string 27 } 28 29 // NewAllWatcher returns an AllWatcher instance which interacts with a 30 // watcher created by the WatchAll API call. 31 // 32 // There should be no need to call this from outside of the api 33 // package. It is only used by Client.WatchAll in this package. 34 func NewAllWatcher(caller base.APICaller, id *string) *AllWatcher { 35 return newAllWatcher("AllWatcher", caller, id) 36 } 37 38 // NewAllModelWatcher returns an AllWatcher instance which interacts 39 // with a watcher created by the WatchAllModels API call. 40 // 41 // There should be no need to call this from outside of the api 42 // package. It is only used by Client.WatchAllModels in 43 // api/controller. 44 func NewAllModelWatcher(caller base.APICaller, id *string) *AllWatcher { 45 return newAllWatcher("AllModelWatcher", caller, id) 46 } 47 48 func newAllWatcher(objType string, caller base.APICaller, id *string) *AllWatcher { 49 return &AllWatcher{ 50 objType: objType, 51 caller: caller, 52 id: id, 53 } 54 } 55 56 // Next returns a new set of deltas from a watcher previously created 57 // by the WatchAll or WatchAllModels API calls. It will block until 58 // there are deltas to return. 59 func (watcher *AllWatcher) Next() ([]params.Delta, error) { 60 var info params.AllWatcherNextResults 61 err := watcher.caller.APICall( 62 watcher.objType, 63 watcher.caller.BestFacadeVersion(watcher.objType), 64 *watcher.id, 65 "Next", 66 nil, &info, 67 ) 68 // We'll order the deltas so relation changes come last. 69 // This allows the callers like the Dashboard to process changes 70 // in the right order. 71 sort.Sort(orderedDeltas(info.Deltas)) 72 return info.Deltas, err 73 } 74 75 type orderedDeltas []params.Delta 76 77 func (o orderedDeltas) Len() int { 78 return len(o) 79 } 80 81 func (o orderedDeltas) kindPriority(kind string) int { 82 switch kind { 83 case "machine": 84 return 1 85 case "application": 86 return 2 87 case "relation": 88 return 3 89 } 90 return 0 91 } 92 93 func (o orderedDeltas) Less(i, j int) bool { 94 // All we care about is having relation deltas last. 95 // We'll add extra checks though to make the order more 96 // deterministic for tests. 97 pi, pj := o.kindPriority(o[i].Entity.EntityId().Kind), o.kindPriority(o[j].Entity.EntityId().Kind) 98 if pi == pj { 99 return o[i].Entity.EntityId().Id < o[j].Entity.EntityId().Id 100 } 101 return pi < pj 102 } 103 104 func (o orderedDeltas) Swap(i, j int) { 105 o[i], o[j] = o[j], o[i] 106 } 107 108 // Stop shutdowns down a watcher previously created by the WatchAll or 109 // WatchAllModels API calls 110 func (watcher *AllWatcher) Stop() error { 111 return watcher.caller.APICall( 112 watcher.objType, 113 watcher.caller.BestFacadeVersion(watcher.objType), 114 *watcher.id, 115 "Stop", 116 nil, nil, 117 ) 118 }