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  }