gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/router/service/watcher.go (about) 1 package service 2 3 import ( 4 "io" 5 "sync" 6 "time" 7 8 "gitee.com/liuxuezhan/go-micro-v1.18.0/router" 9 pb "gitee.com/liuxuezhan/go-micro-v1.18.0/router/proto" 10 ) 11 12 type watcher struct { 13 sync.RWMutex 14 opts router.WatchOptions 15 resChan chan *router.Event 16 done chan struct{} 17 } 18 19 func newWatcher(rsp pb.Router_WatchService, opts router.WatchOptions) (*watcher, error) { 20 w := &watcher{ 21 opts: opts, 22 resChan: make(chan *router.Event), 23 done: make(chan struct{}), 24 } 25 26 go func() { 27 for { 28 select { 29 case <-w.done: 30 return 31 default: 32 if err := w.watch(rsp); err != nil { 33 w.Stop() 34 return 35 } 36 } 37 } 38 }() 39 40 return w, nil 41 } 42 43 // watchRouter watches router and send events to all registered watchers 44 func (w *watcher) watch(stream pb.Router_WatchService) error { 45 defer stream.Close() 46 47 var watchErr error 48 49 for { 50 resp, err := stream.Recv() 51 if err != nil { 52 if err != io.EOF { 53 watchErr = err 54 } 55 break 56 } 57 58 route := router.Route{ 59 Service: resp.Route.Service, 60 Address: resp.Route.Address, 61 Gateway: resp.Route.Gateway, 62 Network: resp.Route.Network, 63 Link: resp.Route.Link, 64 Metric: resp.Route.Metric, 65 } 66 67 event := &router.Event{ 68 Type: router.EventType(resp.Type), 69 Timestamp: time.Unix(0, resp.Timestamp), 70 Route: route, 71 } 72 73 select { 74 case w.resChan <- event: 75 case <-w.done: 76 } 77 } 78 79 return watchErr 80 } 81 82 // Next is a blocking call that returns watch result 83 func (w *watcher) Next() (*router.Event, error) { 84 for { 85 select { 86 case res := <-w.resChan: 87 switch w.opts.Service { 88 case res.Route.Service, "*": 89 return res, nil 90 default: 91 continue 92 } 93 case <-w.done: 94 return nil, router.ErrWatcherStopped 95 } 96 } 97 } 98 99 // Chan returns event channel 100 func (w *watcher) Chan() (<-chan *router.Event, error) { 101 return w.resChan, nil 102 } 103 104 // Stop stops watcher 105 func (w *watcher) Stop() { 106 w.Lock() 107 defer w.Unlock() 108 109 select { 110 case <-w.done: 111 return 112 default: 113 close(w.done) 114 } 115 }