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 }