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  }