github.com/annwntech/go-micro/v2@v2.9.5/config/source/etcd/watcher.go (about)

     1  package etcd
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"sync"
     7  	"time"
     8  
     9  	cetcd "github.com/coreos/etcd/clientv3"
    10  	"github.com/annwntech/go-micro/v2/config/source"
    11  )
    12  
    13  type watcher struct {
    14  	opts        source.Options
    15  	name        string
    16  	stripPrefix string
    17  
    18  	sync.RWMutex
    19  	cs *source.ChangeSet
    20  
    21  	ch   chan *source.ChangeSet
    22  	exit chan bool
    23  }
    24  
    25  func newWatcher(key, strip string, wc cetcd.Watcher, cs *source.ChangeSet, opts source.Options) (source.Watcher, error) {
    26  	w := &watcher{
    27  		opts:        opts,
    28  		name:        "etcd",
    29  		stripPrefix: strip,
    30  		cs:          cs,
    31  		ch:          make(chan *source.ChangeSet),
    32  		exit:        make(chan bool),
    33  	}
    34  
    35  	ch := wc.Watch(context.Background(), key, cetcd.WithPrefix())
    36  
    37  	go w.run(wc, ch)
    38  
    39  	return w, nil
    40  }
    41  
    42  func (w *watcher) handle(evs []*cetcd.Event) {
    43  	w.RLock()
    44  	data := w.cs.Data
    45  	w.RUnlock()
    46  
    47  	var vals map[string]interface{}
    48  
    49  	// unpackage existing changeset
    50  	if err := w.opts.Encoder.Decode(data, &vals); err != nil {
    51  		return
    52  	}
    53  
    54  	// update base changeset
    55  	d := makeEvMap(w.opts.Encoder, vals, evs, w.stripPrefix)
    56  
    57  	// pack the changeset
    58  	b, err := w.opts.Encoder.Encode(d)
    59  	if err != nil {
    60  		return
    61  	}
    62  
    63  	// create new changeset
    64  	cs := &source.ChangeSet{
    65  		Timestamp: time.Now(),
    66  		Source:    w.name,
    67  		Data:      b,
    68  		Format:    w.opts.Encoder.String(),
    69  	}
    70  	cs.Checksum = cs.Sum()
    71  
    72  	// set base change set
    73  	w.Lock()
    74  	w.cs = cs
    75  	w.Unlock()
    76  
    77  	// send update
    78  	w.ch <- cs
    79  }
    80  
    81  func (w *watcher) run(wc cetcd.Watcher, ch cetcd.WatchChan) {
    82  	for {
    83  		select {
    84  		case rsp, ok := <-ch:
    85  			if !ok {
    86  				return
    87  			}
    88  			w.handle(rsp.Events)
    89  		case <-w.exit:
    90  			wc.Close()
    91  			return
    92  		}
    93  	}
    94  }
    95  
    96  func (w *watcher) Next() (*source.ChangeSet, error) {
    97  	select {
    98  	case cs := <-w.ch:
    99  		return cs, nil
   100  	case <-w.exit:
   101  		return nil, errors.New("watcher stopped")
   102  	}
   103  }
   104  
   105  func (w *watcher) Stop() error {
   106  	select {
   107  	case <-w.exit:
   108  		return nil
   109  	default:
   110  		close(w.exit)
   111  	}
   112  	return nil
   113  }