func (w *watchGrpcStream) dispatchEvent(pbresp *pb.WatchResponse) bool {
	ws, ok := w.substreams[pbresp.WatchId]
	if !ok {
		return false
	}
	events := make([]*Event, len(pbresp.Events))
	for i, ev := range pbresp.Events {
		events[i] = (*Event)(ev)
	}
	wr := &WatchResponse{
		Header:          *pbresp.Header,
		Events:          events,
		CompactRevision: pbresp.CompactRevision,
		Created:         pbresp.Created,
		Canceled:        pbresp.Canceled,
	}
	select {
	case ws.recvc <- wr:
	case <-ws.donec:
		return false
	}
	return true
}
dispatchEvent sends a WatchResponse to the appropriate watcher stream
package clientv3
import (
	"fmt"
	"sync"
	"time"
	v3rpc "github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
	mvccpb "github.com/coreos/etcd/mvcc/mvccpb"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
)
const (
	EventTypeDelete = mvccpb.DELETE
	EventTypePut    = mvccpb.PUT
	closeSendErrTimeout = 250 * time.Millisecond
)
type Event mvccpb.Event
type WatchChan <-chan WatchResponse
type Watcher interface {
	Watch(ctx context.Context, key string, opts ...OpOption) WatchChan
	Close() error
}
type WatchResponse struct {
	Header pb.ResponseHeader
	Events []*Event
	CompactRevision int64
	Canceled bool
	Created bool
	closeErr error
}
func (e *Event) IsCreate() bool {
	return e.Type == EventTypePut && e.Kv.CreateRevision == e.Kv.ModRevision
}
func (e *Event) IsModify() bool {
	return e.Type == EventTypePut && e.Kv.CreateRevision != e.Kv.ModRevision
}
func (wr *WatchResponse) Err() error {
	switch {
	case wr.closeErr != nil:
		return v3rpc.Error(wr.closeErr)
	case wr.CompactRevision != 0:
		return v3rpc.ErrCompacted
	case wr.Canceled:
		return v3rpc.ErrFutureRev
	}
	return nil
}
func (wr *WatchResponse) IsProgressNotify() bool {
	return len(wr.Events) == 0 && !wr.Canceled && !wr.Created && wr.CompactRevision == 0 && wr.Header.Revision != 0
}
type watcher struct {
	remote pb.WatchClient
	mu sync.RWMutex
	streams map[string]*watchGrpcStream
}
type watchGrpcStream struct {
	owner  *watcher
	remote pb.WatchClient
	ctx context.Context
	ctxKey string
	cancel context.CancelFunc
	substreams map[int64]*watcherStream
	resuming []*watcherStream
	reqc chan *watchRequest
	respc chan *pb.WatchResponse
	donec chan struct{}
	errc chan error
	closingc chan *watcherStream
	wg sync.WaitGroup
	resumec chan struct{}
	closeErr error
}
type watchRequest struct {
	ctx context.Context
	key string
	end string
	rev int64
	createdNotify bool
	progressNotify bool
	filters []pb.WatchCreateRequest_FilterType
	prevKV bool
	retc chan chan WatchResponse
}
type watcherStream struct {
	initReq watchRequest
	outc chan WatchResponse
	recvc chan *WatchResponse
	donec chan struct{}
	closing bool
	id int64
	buf []*WatchResponse
}
func NewWatcher(c *Client) Watcher {
	return NewWatchFromWatchClient(pb.NewWatchClient(c.conn))
}
func NewWatchFromWatchClient(wc pb.WatchClient) Watcher {
	return &watcher{
		remote:  wc,
		streams: make(map[string]*watchGrpcStream),
	}
}
var valCtxCh = make(chan struct{})
var zeroTime = time.Unix(0, 0)
type valCtx struct{ context.Context }
func (vc *valCtx) Deadline() (time.Time, bool) { return zeroTime, false }
func (vc *valCtx) Done() <-chan struct{}       { return valCtxCh }
func (vc *valCtx) Err() error                  { return nil }
func (w *watcher) newWatcherGrpcStream(inctx context.Context) *watchGrpcStream {
	ctx, cancel := context.WithCancel(&valCtx{inctx})
	wgs := &watchGrpcStream{
		owner:      w,
		remote:     w.remote,
		ctx:        ctx,
		ctxKey:     fmt.Sprintf("%v", inctx),
		cancel:     cancel,
		substreams: make(map[int64]*watcherStream),
		respc:    make(chan *pb.WatchResponse),
		reqc:     make(chan *watchRequest),
		donec:    make(chan struct{}),
		errc:     make(chan error, 1),
		closingc: make(chan *watcherStream),
		resumec:  make(chan struct{}),
	}
	go wgs.run()
	return wgs
}
func (w *watcher) Watch(ctx context.Context, key string, opts ...OpOption) WatchChan {
	ow := opWatch(key, opts...)
	var filters []pb.WatchCreateRequest_FilterType
	if ow.filterPut {
		filters = append(filters, pb.WatchCreateRequest_NOPUT)
	}
	if ow.filterDelete {
		filters = append(filters, pb.WatchCreateRequest_NODELETE)
	}
	wr := &watchRequest{
		ctx:            ctx,
		createdNotify:  ow.createdNotify,
		key:            string(ow.key),
		end:            string(ow.end),
		rev:            ow.rev,
		progressNotify: ow.progressNotify,
		filters:        filters,
		prevKV:         ow.prevKV,
		retc:           make(chan chan WatchResponse, 1),
	}
	ok := false
	ctxKey := fmt.Sprintf("%v", ctx)
	w.mu.Lock()
	if w.streams == nil {
		w.mu.Unlock()
		ch := make(chan WatchResponse)
		close(ch)
		return ch
	}
	wgs := w.streams[ctxKey]
	if wgs == nil {
		wgs = w.newWatcherGrpcStream(ctx)
		w.streams[ctxKey] = wgs
	}
	donec := wgs.donec
	reqc := wgs.reqc
	w.mu.Unlock()
	closeCh := make(chan WatchResponse, 1)
	select {
	case reqc <- wr:
		ok = true
	case <-wr.ctx.Done():
	case <-donec:
		if wgs.closeErr != nil {
			closeCh <- WatchResponse{closeErr: wgs.closeErr}
			break
		}
		return w.Watch(ctx, key, opts...)
	}
	if ok {
		select {
		case ret := <-wr.retc:
			return ret
		case <-ctx.Done():
		case <-donec:
			if wgs.closeErr != nil {
				closeCh <- WatchResponse{closeErr: wgs.closeErr}
				break
			}
			return w.Watch(ctx, key, opts...)
		}
	}
	close(closeCh)
	return closeCh
}
func (w *watcher) Close() (err error) {
	w.mu.Lock()
	streams := w.streams
	w.streams = nil
	w.mu.Unlock()
	for _, wgs := range streams {
		if werr := wgs.Close(); werr != nil {
			err = werr
		}
	}
	return err
}
func (w *watchGrpcStream) Close() (err error) {
	w.cancel()
	<-w.donec
	select {
	case err = <-w.errc:
	default:
	}
	return toErr(w.ctx, err)
}
func (w *watcher) closeStream(wgs *watchGrpcStream) {
	w.mu.Lock()
	close(wgs.donec)
	wgs.cancel()
	if w.streams != nil {
		delete(w.streams, wgs.ctxKey)
	}
	w.mu.Unlock()
}
func (w *watchGrpcStream) addSubstream(resp *pb.WatchResponse, ws *watcherStream) {
	if resp.WatchId == -1 {
		close(ws.recvc)
		return
	}
	ws.id = resp.WatchId
	w.substreams[ws.id] = ws
}
func (w *watchGrpcStream) sendCloseSubstream(ws *watcherStream, resp *WatchResponse) {
	select {
	case ws.outc <- *resp:
	case <-ws.initReq.ctx.Done():
	case <-time.After(closeSendErrTimeout):
	}
	close(ws.outc)
}
func (w *watchGrpcStream) closeSubstream(ws *watcherStream) {
	select {
	case ws.initReq.retc <- ws.outc:
	default:
	}
	if closeErr := w.closeErr; closeErr != nil && ws.initReq.ctx.Err() == nil {
		go w.sendCloseSubstream(ws, &WatchResponse{closeErr: w.closeErr})
	} else if ws.outc != nil {
		close(ws.outc)
	}
	if ws.id != -1 {
		delete(w.substreams, ws.id)
		return
	}
	for i := range w.resuming {
		if w.resuming[i] == ws {
			w.resuming[i] = nil
			return
		}
	}
}
func (w *watchGrpcStream) run() {
	var wc pb.Watch_WatchClient
	var closeErr error
	closing := make(map[*watcherStream]struct{})
	defer func() {
		w.closeErr = closeErr
		for _, ws := range w.substreams {
			if _, ok := closing[ws]; !ok {
				close(ws.recvc)
				closing[ws] = struct{}{}
			}
		}
		for _, ws := range w.resuming {
			if _, ok := closing[ws]; ws != nil && !ok {
				close(ws.recvc)
				closing[ws] = struct{}{}
			}
		}
		w.joinSubstreams()
		for range closing {
			w.closeSubstream(<-w.closingc)
		}
		w.wg.Wait()
		w.owner.closeStream(w)
	}()
	if wc, closeErr = w.newWatchClient(); closeErr != nil {
		return
	}
	cancelSet := make(map[int64]struct{})
	for {
		select {
		case wreq := <-w.reqc:
			outc := make(chan WatchResponse, 1)
			ws := &watcherStream{
				initReq: *wreq,
				id:      -1,
				outc:    outc,
				recvc: make(chan *WatchResponse),
			}
			ws.donec = make(chan struct{})
			w.wg.Add(1)
			go w.serveSubstream(ws, w.resumec)
			w.resuming = append(w.resuming, ws)
			if len(w.resuming) == 1 {
				wc.Send(ws.initReq.toPB())
			}
		case pbresp := <-w.respc:
			switch {
			case pbresp.Created:
				if ws := w.resuming[0]; ws != nil {
					w.addSubstream(pbresp, ws)
					w.dispatchEvent(pbresp)
					w.resuming[0] = nil
				}
				if ws := w.nextResume(); ws != nil {
					wc.Send(ws.initReq.toPB())
				}
			case pbresp.Canceled:
				delete(cancelSet, pbresp.WatchId)
				if ws, ok := w.substreams[pbresp.WatchId]; ok {
					close(ws.recvc)
					closing[ws] = struct{}{}
				}
			default:
				if ok := w.dispatchEvent(pbresp); ok {
					break
				}
				if _, ok := cancelSet[pbresp.WatchId]; ok {
					break
				}
				cancelSet[pbresp.WatchId] = struct{}{}
				cr := &pb.WatchRequest_CancelRequest{
					CancelRequest: &pb.WatchCancelRequest{
						WatchId: pbresp.WatchId,
					},
				}
				req := &pb.WatchRequest{RequestUnion: cr}
				wc.Send(req)
			}
		case err := <-w.errc:
			if isHaltErr(w.ctx, err) || toErr(w.ctx, err) == v3rpc.ErrNoLeader {
				closeErr = err
				return
			}
			if wc, closeErr = w.newWatchClient(); closeErr != nil {
				return
			}
			if ws := w.nextResume(); ws != nil {
				wc.Send(ws.initReq.toPB())
			}
			cancelSet = make(map[int64]struct{})
		case <-w.ctx.Done():
			return
		case ws := <-w.closingc:
			w.closeSubstream(ws)
			delete(closing, ws)
			if len(w.substreams)+len(w.resuming) == 0 {
				return
			}
		}
	}
}
func (w *watchGrpcStream) nextResume() *watcherStream {
	for len(w.resuming) != 0 {
		if w.resuming[0] != nil {
			return w.resuming[0]
		}
		w.resuming = w.resuming[1:len(w.resuming)]
	}
	return nil
}