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