gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/router/service/service.go (about)

     1  package service
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"sync"
     9  	"time"
    10  
    11  	"gitee.com/liuxuezhan/go-micro-v1.18.0/client"
    12  	"gitee.com/liuxuezhan/go-micro-v1.18.0/router"
    13  	pb "gitee.com/liuxuezhan/go-micro-v1.18.0/router/proto"
    14  )
    15  
    16  type svc struct {
    17  	sync.RWMutex
    18  	opts       router.Options
    19  	callOpts   []client.CallOption
    20  	router     pb.RouterService
    21  	table      *table
    22  	status     *router.Status
    23  	exit       chan bool
    24  	errChan    chan error
    25  	advertChan chan *router.Advert
    26  }
    27  
    28  // NewRouter creates new service router and returns it
    29  func NewRouter(opts ...router.Option) router.Router {
    30  	// get default options
    31  	options := router.DefaultOptions()
    32  
    33  	// apply requested options
    34  	for _, o := range opts {
    35  		o(&options)
    36  	}
    37  
    38  	// NOTE: might need some client opts here
    39  	cli := client.DefaultClient
    40  
    41  	// set options client
    42  	if options.Client != nil {
    43  		cli = options.Client
    44  	}
    45  
    46  	// set the status to Stopped
    47  	status := &router.Status{
    48  		Code:  router.Stopped,
    49  		Error: nil,
    50  	}
    51  
    52  	// NOTE: should we have Client/Service option in router.Options?
    53  	s := &svc{
    54  		opts:   options,
    55  		status: status,
    56  		router: pb.NewRouterService(router.DefaultName, cli),
    57  	}
    58  
    59  	// set the router address to call
    60  	if len(options.Address) > 0 {
    61  		s.callOpts = []client.CallOption{
    62  			client.WithAddress(options.Address),
    63  		}
    64  	}
    65  	// set the table
    66  	s.table = &table{pb.NewTableService(router.DefaultName, cli), s.callOpts}
    67  
    68  	return s
    69  }
    70  
    71  // Init initializes router with given options
    72  func (s *svc) Init(opts ...router.Option) error {
    73  	s.Lock()
    74  	defer s.Unlock()
    75  
    76  	for _, o := range opts {
    77  		o(&s.opts)
    78  	}
    79  
    80  	return nil
    81  }
    82  
    83  // Options returns router options
    84  func (s *svc) Options() router.Options {
    85  	s.Lock()
    86  	opts := s.opts
    87  	s.Unlock()
    88  
    89  	return opts
    90  }
    91  
    92  // Table returns routing table
    93  func (s *svc) Table() router.Table {
    94  	return s.table
    95  }
    96  
    97  // Start starts the service
    98  func (s *svc) Start() error {
    99  	s.Lock()
   100  	defer s.Unlock()
   101  
   102  	s.status = &router.Status{
   103  		Code:  router.Running,
   104  		Error: nil,
   105  	}
   106  
   107  	return nil
   108  }
   109  
   110  func (s *svc) advertiseEvents(advertChan chan *router.Advert, stream pb.Router_AdvertiseService) error {
   111  	go func() {
   112  		<-s.exit
   113  		stream.Close()
   114  	}()
   115  
   116  	var advErr error
   117  
   118  	for {
   119  		resp, err := stream.Recv()
   120  		if err != nil {
   121  			if err != io.EOF {
   122  				advErr = err
   123  			}
   124  			break
   125  		}
   126  
   127  		events := make([]*router.Event, len(resp.Events))
   128  		for i, event := range resp.Events {
   129  			route := router.Route{
   130  				Service: event.Route.Service,
   131  				Address: event.Route.Address,
   132  				Gateway: event.Route.Gateway,
   133  				Network: event.Route.Network,
   134  				Link:    event.Route.Link,
   135  				Metric:  event.Route.Metric,
   136  			}
   137  
   138  			events[i] = &router.Event{
   139  				Type:      router.EventType(event.Type),
   140  				Timestamp: time.Unix(0, event.Timestamp),
   141  				Route:     route,
   142  			}
   143  		}
   144  
   145  		advert := &router.Advert{
   146  			Id:        resp.Id,
   147  			Type:      router.AdvertType(resp.Type),
   148  			Timestamp: time.Unix(0, resp.Timestamp),
   149  			TTL:       time.Duration(resp.Ttl),
   150  			Events:    events,
   151  		}
   152  
   153  		select {
   154  		case advertChan <- advert:
   155  		case <-s.exit:
   156  			close(advertChan)
   157  			return nil
   158  		}
   159  	}
   160  
   161  	// close the channel on exit
   162  	close(advertChan)
   163  
   164  	return advErr
   165  }
   166  
   167  // Advertise advertises routes to the network
   168  func (s *svc) Advertise() (<-chan *router.Advert, error) {
   169  	s.Lock()
   170  	defer s.Unlock()
   171  
   172  	switch s.status.Code {
   173  	case router.Running, router.Advertising:
   174  		stream, err := s.router.Advertise(context.Background(), &pb.Request{}, s.callOpts...)
   175  		if err != nil {
   176  			return nil, fmt.Errorf("failed getting advert stream: %s", err)
   177  		}
   178  		// create advertise and event channels
   179  		advertChan := make(chan *router.Advert)
   180  		go s.advertiseEvents(advertChan, stream)
   181  		return advertChan, nil
   182  	case router.Stopped:
   183  		return nil, fmt.Errorf("not running")
   184  	}
   185  
   186  	return nil, fmt.Errorf("error: %s", s.status.Error)
   187  }
   188  
   189  // Process processes incoming adverts
   190  func (s *svc) Process(advert *router.Advert) error {
   191  	events := make([]*pb.Event, 0, len(advert.Events))
   192  	for _, event := range advert.Events {
   193  		route := &pb.Route{
   194  			Service: event.Route.Service,
   195  			Address: event.Route.Address,
   196  			Gateway: event.Route.Gateway,
   197  			Network: event.Route.Network,
   198  			Link:    event.Route.Link,
   199  			Metric:  event.Route.Metric,
   200  		}
   201  		e := &pb.Event{
   202  			Type:      pb.EventType(event.Type),
   203  			Timestamp: event.Timestamp.UnixNano(),
   204  			Route:     route,
   205  		}
   206  		events = append(events, e)
   207  	}
   208  
   209  	advertReq := &pb.Advert{
   210  		Id:        s.Options().Id,
   211  		Type:      pb.AdvertType(advert.Type),
   212  		Timestamp: advert.Timestamp.UnixNano(),
   213  		Events:    events,
   214  	}
   215  
   216  	if _, err := s.router.Process(context.Background(), advertReq, s.callOpts...); err != nil {
   217  		return err
   218  	}
   219  
   220  	return nil
   221  }
   222  
   223  // Solicit advertise all routes
   224  func (s *svc) Solicit() error {
   225  	// list all the routes
   226  	routes, err := s.table.List()
   227  	if err != nil {
   228  		return err
   229  	}
   230  
   231  	// build events to advertise
   232  	events := make([]*router.Event, len(routes))
   233  	for i := range events {
   234  		events[i] = &router.Event{
   235  			Type:      router.Update,
   236  			Timestamp: time.Now(),
   237  			Route:     routes[i],
   238  		}
   239  	}
   240  
   241  	advert := &router.Advert{
   242  		Id:        s.opts.Id,
   243  		Type:      router.RouteUpdate,
   244  		Timestamp: time.Now(),
   245  		TTL:       time.Duration(router.DefaultAdvertTTL),
   246  		Events:    events,
   247  	}
   248  
   249  	select {
   250  	case s.advertChan <- advert:
   251  	case <-s.exit:
   252  		close(s.advertChan)
   253  		return nil
   254  	}
   255  
   256  	return nil
   257  }
   258  
   259  // Status returns router status
   260  func (s *svc) Status() router.Status {
   261  	s.Lock()
   262  	defer s.Unlock()
   263  
   264  	// check if its stopped
   265  	select {
   266  	case <-s.exit:
   267  		return router.Status{
   268  			Code:  router.Stopped,
   269  			Error: nil,
   270  		}
   271  	default:
   272  		// don't block
   273  	}
   274  
   275  	// check the remote router
   276  	rsp, err := s.router.Status(context.Background(), &pb.Request{}, s.callOpts...)
   277  	if err != nil {
   278  		return router.Status{
   279  			Code:  router.Error,
   280  			Error: err,
   281  		}
   282  	}
   283  
   284  	code := router.Running
   285  	var serr error
   286  
   287  	switch rsp.Status.Code {
   288  	case "running":
   289  		code = router.Running
   290  	case "advertising":
   291  		code = router.Advertising
   292  	case "stopped":
   293  		code = router.Stopped
   294  	case "error":
   295  		code = router.Error
   296  	}
   297  
   298  	if len(rsp.Status.Error) > 0 {
   299  		serr = errors.New(rsp.Status.Error)
   300  	}
   301  
   302  	return router.Status{
   303  		Code:  code,
   304  		Error: serr,
   305  	}
   306  }
   307  
   308  // Remote router cannot be stopped
   309  func (s *svc) Stop() error {
   310  	s.Lock()
   311  	defer s.Unlock()
   312  
   313  	select {
   314  	case <-s.exit:
   315  		return nil
   316  	default:
   317  		close(s.exit)
   318  	}
   319  
   320  	return nil
   321  }
   322  
   323  // Lookup looks up routes in the routing table and returns them
   324  func (s *svc) Lookup(q ...router.QueryOption) ([]router.Route, error) {
   325  	// call the router
   326  	query := router.NewQuery(q...)
   327  
   328  	resp, err := s.router.Lookup(context.Background(), &pb.LookupRequest{
   329  		Query: &pb.Query{
   330  			Service: query.Service,
   331  			Gateway: query.Gateway,
   332  			Network: query.Network,
   333  		},
   334  	}, s.callOpts...)
   335  
   336  	// errored out
   337  	if err != nil {
   338  		return nil, err
   339  	}
   340  
   341  	routes := make([]router.Route, len(resp.Routes))
   342  	for i, route := range resp.Routes {
   343  		routes[i] = router.Route{
   344  			Service: route.Service,
   345  			Address: route.Address,
   346  			Gateway: route.Gateway,
   347  			Network: route.Network,
   348  			Link:    route.Link,
   349  			Metric:  route.Metric,
   350  		}
   351  	}
   352  
   353  	return routes, nil
   354  }
   355  
   356  // Watch returns a watcher which allows to track updates to the routing table
   357  func (s *svc) Watch(opts ...router.WatchOption) (router.Watcher, error) {
   358  	rsp, err := s.router.Watch(context.Background(), &pb.WatchRequest{}, s.callOpts...)
   359  	if err != nil {
   360  		return nil, err
   361  	}
   362  	options := router.WatchOptions{
   363  		Service: "*",
   364  	}
   365  	for _, o := range opts {
   366  		o(&options)
   367  	}
   368  	return newWatcher(rsp, options)
   369  }
   370  
   371  // Returns the router implementation
   372  func (s *svc) String() string {
   373  	return "service"
   374  }