gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/registry/etcd/watcher.go (about)

     1  package etcd
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"time"
     7  
     8  	"github.com/coreos/etcd/clientv3"
     9  	"gitee.com/liuxuezhan/go-micro-v1.18.0/registry"
    10  )
    11  
    12  type etcdWatcher struct {
    13  	stop    chan bool
    14  	w       clientv3.WatchChan
    15  	client  *clientv3.Client
    16  	timeout time.Duration
    17  }
    18  
    19  func newEtcdWatcher(r *etcdRegistry, timeout time.Duration, opts ...registry.WatchOption) (registry.Watcher, error) {
    20  	var wo registry.WatchOptions
    21  	for _, o := range opts {
    22  		o(&wo)
    23  	}
    24  
    25  	ctx, cancel := context.WithCancel(context.Background())
    26  	stop := make(chan bool, 1)
    27  
    28  	go func() {
    29  		<-stop
    30  		cancel()
    31  	}()
    32  
    33  	watchPath := prefix
    34  	if len(wo.Service) > 0 {
    35  		watchPath = servicePath(wo.Service) + "/"
    36  	}
    37  
    38  	return &etcdWatcher{
    39  		stop:    stop,
    40  		w:       r.client.Watch(ctx, watchPath, clientv3.WithPrefix(), clientv3.WithPrevKV()),
    41  		client:  r.client,
    42  		timeout: timeout,
    43  	}, nil
    44  }
    45  
    46  func (ew *etcdWatcher) Next() (*registry.Result, error) {
    47  	for wresp := range ew.w {
    48  		if wresp.Err() != nil {
    49  			return nil, wresp.Err()
    50  		}
    51  		for _, ev := range wresp.Events {
    52  			service := decode(ev.Kv.Value)
    53  			var action string
    54  
    55  			switch ev.Type {
    56  			case clientv3.EventTypePut:
    57  				if ev.IsCreate() {
    58  					action = "create"
    59  				} else if ev.IsModify() {
    60  					action = "update"
    61  				}
    62  			case clientv3.EventTypeDelete:
    63  				action = "delete"
    64  
    65  				// get service from prevKv
    66  				service = decode(ev.PrevKv.Value)
    67  			}
    68  
    69  			if service == nil {
    70  				continue
    71  			}
    72  			return &registry.Result{
    73  				Action:  action,
    74  				Service: service,
    75  			}, nil
    76  		}
    77  	}
    78  	return nil, errors.New("could not get next")
    79  }
    80  
    81  func (ew *etcdWatcher) Stop() {
    82  	select {
    83  	case <-ew.stop:
    84  		return
    85  	default:
    86  		close(ew.stop)
    87  	}
    88  }