89 lines
		
	
	
		
			1.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			89 lines
		
	
	
		
			1.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package etcd
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"errors"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/coreos/etcd/clientv3"
 | |
| 	"github.com/micro/go-micro/registry"
 | |
| )
 | |
| 
 | |
| type etcdWatcher struct {
 | |
| 	stop    chan bool
 | |
| 	w       clientv3.WatchChan
 | |
| 	client  *clientv3.Client
 | |
| 	timeout time.Duration
 | |
| }
 | |
| 
 | |
| func newEtcdWatcher(r *etcdRegistry, timeout time.Duration, opts ...registry.WatchOption) (registry.Watcher, error) {
 | |
| 	var wo registry.WatchOptions
 | |
| 	for _, o := range opts {
 | |
| 		o(&wo)
 | |
| 	}
 | |
| 
 | |
| 	ctx, cancel := context.WithCancel(context.Background())
 | |
| 	stop := make(chan bool, 1)
 | |
| 
 | |
| 	go func() {
 | |
| 		<-stop
 | |
| 		cancel()
 | |
| 	}()
 | |
| 
 | |
| 	watchPath := prefix
 | |
| 	if len(wo.Service) > 0 {
 | |
| 		watchPath = servicePath(wo.Service) + "/"
 | |
| 	}
 | |
| 
 | |
| 	return &etcdWatcher{
 | |
| 		stop:    stop,
 | |
| 		w:       r.client.Watch(ctx, watchPath, clientv3.WithPrefix(), clientv3.WithPrevKV()),
 | |
| 		client:  r.client,
 | |
| 		timeout: timeout,
 | |
| 	}, nil
 | |
| }
 | |
| 
 | |
| func (ew *etcdWatcher) Next() (*registry.Result, error) {
 | |
| 	for wresp := range ew.w {
 | |
| 		if wresp.Err() != nil {
 | |
| 			return nil, wresp.Err()
 | |
| 		}
 | |
| 		for _, ev := range wresp.Events {
 | |
| 			service := decode(ev.Kv.Value)
 | |
| 			var action string
 | |
| 
 | |
| 			switch ev.Type {
 | |
| 			case clientv3.EventTypePut:
 | |
| 				if ev.IsCreate() {
 | |
| 					action = "create"
 | |
| 				} else if ev.IsModify() {
 | |
| 					action = "update"
 | |
| 				}
 | |
| 			case clientv3.EventTypeDelete:
 | |
| 				action = "delete"
 | |
| 
 | |
| 				// get service from prevKv
 | |
| 				service = decode(ev.PrevKv.Value)
 | |
| 			}
 | |
| 
 | |
| 			if service == nil {
 | |
| 				continue
 | |
| 			}
 | |
| 			return ®istry.Result{
 | |
| 				Action:  action,
 | |
| 				Service: service,
 | |
| 			}, nil
 | |
| 		}
 | |
| 	}
 | |
| 	return nil, errors.New("could not get next")
 | |
| }
 | |
| 
 | |
| func (ew *etcdWatcher) Stop() {
 | |
| 	select {
 | |
| 	case <-ew.stop:
 | |
| 		return
 | |
| 	default:
 | |
| 		close(ew.stop)
 | |
| 	}
 | |
| }
 |