launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/state/apiserver/common/watch.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package common 5 6 import ( 7 "launchpad.net/juju-core/errors" 8 "launchpad.net/juju-core/state" 9 "launchpad.net/juju-core/state/api/params" 10 "launchpad.net/juju-core/state/watcher" 11 ) 12 13 // AgentEntityWatcher implements a common Watch method for use by 14 // various facades. 15 type AgentEntityWatcher struct { 16 st state.EntityFinder 17 resources *Resources 18 getCanWatch GetAuthFunc 19 } 20 21 // NewAgentEntityWatcher returns a new AgentEntityWatcher. The 22 // GetAuthFunc will be used on each invocation of Watch to determine 23 // current permissions. 24 func NewAgentEntityWatcher(st state.EntityFinder, resources *Resources, getCanWatch GetAuthFunc) *AgentEntityWatcher { 25 return &AgentEntityWatcher{ 26 st: st, 27 resources: resources, 28 getCanWatch: getCanWatch, 29 } 30 } 31 32 func (a *AgentEntityWatcher) watchEntity(tag string) (string, error) { 33 entity0, err := a.st.FindEntity(tag) 34 if err != nil { 35 return "", mask(err, errors.IsNotFoundError) 36 } 37 entity, ok := entity0.(state.NotifyWatcherFactory) 38 if !ok { 39 return "", NotSupportedError(tag, "watching") 40 } 41 watch := entity.Watch() 42 // Consume the initial event. Technically, API 43 // calls to Watch 'transmit' the initial event 44 // in the Watch response. But NotifyWatchers 45 // have no state to transmit. 46 if _, ok := <-watch.Changes(); ok { 47 return a.resources.Register(watch), nil 48 } 49 return "", watcher.MustErr(watch) 50 } 51 52 // Watch starts an NotifyWatcher for each given entity. 53 func (a *AgentEntityWatcher) Watch(args params.Entities) (params.NotifyWatchResults, error) { 54 result := params.NotifyWatchResults{ 55 Results: make([]params.NotifyWatchResult, len(args.Entities)), 56 } 57 if len(args.Entities) == 0 { 58 return result, nil 59 } 60 canWatch, err := a.getCanWatch() 61 if err != nil { 62 return params.NotifyWatchResults{}, mask(err) 63 } 64 for i, entity := range args.Entities { 65 err := ErrPerm 66 watcherId := "" 67 if canWatch(entity.Tag) { 68 watcherId, err = a.watchEntity(entity.Tag) 69 } 70 result.Results[i].NotifyWatcherId = watcherId 71 result.Results[i].Error = ServerError(err) 72 } 73 return result, nil 74 }