github.com/annwntech/go-micro/v2@v2.9.5/router/service/service.go (about)

     1  package service
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"sync"
     8  	"time"
     9  
    10  	"github.com/annwntech/go-micro/v2/client"
    11  	"github.com/annwntech/go-micro/v2/router"
    12  	pb "github.com/annwntech/go-micro/v2/router/service/proto"
    13  )
    14  
    15  type svc struct {
    16  	sync.RWMutex
    17  	opts       router.Options
    18  	callOpts   []client.CallOption
    19  	router     pb.RouterService
    20  	table      *table
    21  	exit       chan bool
    22  	errChan    chan error
    23  	advertChan chan *router.Advert
    24  }
    25  
    26  // NewRouter creates new service router and returns it
    27  func NewRouter(opts ...router.Option) router.Router {
    28  	// get default options
    29  	options := router.DefaultOptions()
    30  
    31  	// apply requested options
    32  	for _, o := range opts {
    33  		o(&options)
    34  	}
    35  
    36  	// NOTE: might need some client opts here
    37  	cli := client.DefaultClient
    38  
    39  	// set options client
    40  	if options.Client != nil {
    41  		cli = options.Client
    42  	}
    43  
    44  	// NOTE: should we have Client/Service option in router.Options?
    45  	s := &svc{
    46  		opts:   options,
    47  		router: pb.NewRouterService(router.DefaultName, cli),
    48  	}
    49  
    50  	// set the router address to call
    51  	if len(options.Address) > 0 {
    52  		s.callOpts = []client.CallOption{
    53  			client.WithAddress(options.Address),
    54  		}
    55  	}
    56  	// set the table
    57  	s.table = &table{pb.NewTableService(router.DefaultName, cli), s.callOpts}
    58  
    59  	return s
    60  }
    61  
    62  // Init initializes router with given options
    63  func (s *svc) Init(opts ...router.Option) error {
    64  	s.Lock()
    65  	defer s.Unlock()
    66  
    67  	for _, o := range opts {
    68  		o(&s.opts)
    69  	}
    70  
    71  	return nil
    72  }
    73  
    74  // Options returns router options
    75  func (s *svc) Options() router.Options {
    76  	s.Lock()
    77  	opts := s.opts
    78  	s.Unlock()
    79  
    80  	return opts
    81  }
    82  
    83  // Table returns routing table
    84  func (s *svc) Table() router.Table {
    85  	return s.table
    86  }
    87  
    88  // Start starts the service
    89  func (s *svc) Start() error {
    90  	s.Lock()
    91  	defer s.Unlock()
    92  	return nil
    93  }
    94  
    95  func (s *svc) advertiseEvents(advertChan chan *router.Advert, stream pb.Router_AdvertiseService) error {
    96  	go func() {
    97  		<-s.exit
    98  		stream.Close()
    99  	}()
   100  
   101  	var advErr error
   102  
   103  	for {
   104  		resp, err := stream.Recv()
   105  		if err != nil {
   106  			if err != io.EOF {
   107  				advErr = err
   108  			}
   109  			break
   110  		}
   111  
   112  		events := make([]*router.Event, len(resp.Events))
   113  		for i, event := range resp.Events {
   114  			route := router.Route{
   115  				Service: event.Route.Service,
   116  				Address: event.Route.Address,
   117  				Gateway: event.Route.Gateway,
   118  				Network: event.Route.Network,
   119  				Link:    event.Route.Link,
   120  				Metric:  event.Route.Metric,
   121  			}
   122  
   123  			events[i] = &router.Event{
   124  				Id:        event.Id,
   125  				Type:      router.EventType(event.Type),
   126  				Timestamp: time.Unix(0, event.Timestamp),
   127  				Route:     route,
   128  			}
   129  		}
   130  
   131  		advert := &router.Advert{
   132  			Id:        resp.Id,
   133  			Type:      router.AdvertType(resp.Type),
   134  			Timestamp: time.Unix(0, resp.Timestamp),
   135  			TTL:       time.Duration(resp.Ttl),
   136  			Events:    events,
   137  		}
   138  
   139  		select {
   140  		case advertChan <- advert:
   141  		case <-s.exit:
   142  			close(advertChan)
   143  			return nil
   144  		}
   145  	}
   146  
   147  	// close the channel on exit
   148  	close(advertChan)
   149  
   150  	return advErr
   151  }
   152  
   153  // Advertise advertises routes to the network
   154  func (s *svc) Advertise() (<-chan *router.Advert, error) {
   155  	s.Lock()
   156  	defer s.Unlock()
   157  
   158  	stream, err := s.router.Advertise(context.Background(), &pb.Request{}, s.callOpts...)
   159  	if err != nil {
   160  		return nil, fmt.Errorf("failed getting advert stream: %s", err)
   161  	}
   162  
   163  	// create advertise and event channels
   164  	advertChan := make(chan *router.Advert)
   165  	go s.advertiseEvents(advertChan, stream)
   166  
   167  	return advertChan, nil
   168  }
   169  
   170  // Process processes incoming adverts
   171  func (s *svc) Process(advert *router.Advert) error {
   172  	events := make([]*pb.Event, 0, len(advert.Events))
   173  	for _, event := range advert.Events {
   174  		route := &pb.Route{
   175  			Service: event.Route.Service,
   176  			Address: event.Route.Address,
   177  			Gateway: event.Route.Gateway,
   178  			Network: event.Route.Network,
   179  			Link:    event.Route.Link,
   180  			Metric:  event.Route.Metric,
   181  		}
   182  		e := &pb.Event{
   183  			Id:        event.Id,
   184  			Type:      pb.EventType(event.Type),
   185  			Timestamp: event.Timestamp.UnixNano(),
   186  			Route:     route,
   187  		}
   188  		events = append(events, e)
   189  	}
   190  
   191  	advertReq := &pb.Advert{
   192  		Id:        s.Options().Id,
   193  		Type:      pb.AdvertType(advert.Type),
   194  		Timestamp: advert.Timestamp.UnixNano(),
   195  		Events:    events,
   196  	}
   197  
   198  	if _, err := s.router.Process(context.Background(), advertReq, s.callOpts...); err != nil {
   199  		return err
   200  	}
   201  
   202  	return nil
   203  }
   204  
   205  // Remote router cannot be stopped
   206  func (s *svc) Stop() error {
   207  	s.Lock()
   208  	defer s.Unlock()
   209  
   210  	select {
   211  	case <-s.exit:
   212  		return nil
   213  	default:
   214  		close(s.exit)
   215  	}
   216  
   217  	return nil
   218  }
   219  
   220  // Lookup looks up routes in the routing table and returns them
   221  func (s *svc) Lookup(q ...router.QueryOption) ([]router.Route, error) {
   222  	// call the router
   223  	query := router.NewQuery(q...)
   224  
   225  	resp, err := s.router.Lookup(context.Background(), &pb.LookupRequest{
   226  		Query: &pb.Query{
   227  			Service: query.Service,
   228  			Gateway: query.Gateway,
   229  			Network: query.Network,
   230  		},
   231  	}, s.callOpts...)
   232  
   233  	// errored out
   234  	if err != nil {
   235  		return nil, err
   236  	}
   237  
   238  	routes := make([]router.Route, len(resp.Routes))
   239  	for i, route := range resp.Routes {
   240  		routes[i] = router.Route{
   241  			Service: route.Service,
   242  			Address: route.Address,
   243  			Gateway: route.Gateway,
   244  			Network: route.Network,
   245  			Link:    route.Link,
   246  			Metric:  route.Metric,
   247  		}
   248  	}
   249  
   250  	return routes, nil
   251  }
   252  
   253  // Watch returns a watcher which allows to track updates to the routing table
   254  func (s *svc) Watch(opts ...router.WatchOption) (router.Watcher, error) {
   255  	rsp, err := s.router.Watch(context.Background(), &pb.WatchRequest{}, s.callOpts...)
   256  	if err != nil {
   257  		return nil, err
   258  	}
   259  	options := router.WatchOptions{
   260  		Service: "*",
   261  	}
   262  	for _, o := range opts {
   263  		o(&options)
   264  	}
   265  	return newWatcher(rsp, options)
   266  }
   267  
   268  // Returns the router implementation
   269  func (s *svc) String() string {
   270  	return "service"
   271  }