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  }