github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/service/router/client/client.go (about)

     1  package client
     2  
     3  import (
     4  	"net/http"
     5  	"sync"
     6  
     7  	pb "github.com/tickoalcantara12/micro/v3/proto/router"
     8  	"github.com/tickoalcantara12/micro/v3/service/client"
     9  	"github.com/tickoalcantara12/micro/v3/service/context"
    10  	"github.com/tickoalcantara12/micro/v3/service/errors"
    11  	"github.com/tickoalcantara12/micro/v3/service/router"
    12  )
    13  
    14  var (
    15  	// name of the router service
    16  	name = "router"
    17  )
    18  
    19  type svc struct {
    20  	sync.RWMutex
    21  	opts     router.Options
    22  	callOpts []client.CallOption
    23  	router   pb.RouterService
    24  	table    *table
    25  	exit     chan bool
    26  	errChan  chan error
    27  }
    28  
    29  // NewRouter creates new service router and returns it
    30  func NewRouter(opts ...router.Option) router.Router {
    31  	// get default options
    32  	options := router.DefaultOptions()
    33  
    34  	// apply requested options
    35  	for _, o := range opts {
    36  		o(&options)
    37  	}
    38  
    39  	s := &svc{
    40  		opts:   options,
    41  		router: pb.NewRouterService(name, client.DefaultClient),
    42  	}
    43  
    44  	// set the router address to call
    45  	if len(options.Address) > 0 {
    46  		s.callOpts = []client.CallOption{
    47  			client.WithAddress(options.Address),
    48  			client.WithAuthToken(),
    49  		}
    50  	}
    51  	// set the table
    52  	s.table = &table{
    53  		pb.NewTableService(name, client.DefaultClient),
    54  		s.callOpts,
    55  	}
    56  
    57  	return s
    58  }
    59  
    60  // Init initializes router with given options
    61  func (s *svc) Init(opts ...router.Option) error {
    62  	s.Lock()
    63  	defer s.Unlock()
    64  
    65  	for _, o := range opts {
    66  		o(&s.opts)
    67  	}
    68  
    69  	return nil
    70  }
    71  
    72  // Options returns router options
    73  func (s *svc) Options() router.Options {
    74  	s.Lock()
    75  	opts := s.opts
    76  	s.Unlock()
    77  
    78  	return opts
    79  }
    80  
    81  // Table returns routing table
    82  func (s *svc) Table() router.Table {
    83  	return s.table
    84  }
    85  
    86  // Remote router cannot be closed
    87  func (s *svc) Close() error {
    88  	s.Lock()
    89  	defer s.Unlock()
    90  
    91  	select {
    92  	case <-s.exit:
    93  		return nil
    94  	default:
    95  		close(s.exit)
    96  	}
    97  
    98  	return nil
    99  }
   100  
   101  // Lookup looks up routes in the routing table and returns them
   102  func (s *svc) Lookup(service string, q ...router.LookupOption) ([]router.Route, error) {
   103  	// call the router
   104  	query := router.NewLookup(q...)
   105  
   106  	resp, err := s.router.Lookup(context.DefaultContext, &pb.LookupRequest{
   107  		Service: service,
   108  		Options: &pb.LookupOptions{
   109  			Address: query.Address,
   110  			Gateway: query.Gateway,
   111  			Network: query.Network,
   112  			Router:  query.Router,
   113  			Link:    query.Link,
   114  		},
   115  	}, s.callOpts...)
   116  
   117  	if verr := errors.FromError(err); verr != nil && verr.Code == http.StatusNotFound {
   118  		return nil, router.ErrRouteNotFound
   119  	} else if err != nil {
   120  		return nil, err
   121  	}
   122  
   123  	routes := make([]router.Route, len(resp.Routes))
   124  	for i, route := range resp.Routes {
   125  		routes[i] = router.Route{
   126  			Service:  route.Service,
   127  			Address:  route.Address,
   128  			Gateway:  route.Gateway,
   129  			Network:  route.Network,
   130  			Link:     route.Link,
   131  			Metric:   route.Metric,
   132  			Metadata: route.Metadata,
   133  		}
   134  	}
   135  
   136  	return routes, nil
   137  }
   138  
   139  // Watch returns a watcher which allows to track updates to the routing table
   140  func (s *svc) Watch(opts ...router.WatchOption) (router.Watcher, error) {
   141  	rsp, err := s.router.Watch(context.DefaultContext, &pb.WatchRequest{}, s.callOpts...)
   142  	if err != nil {
   143  		return nil, err
   144  	}
   145  	options := router.WatchOptions{
   146  		Service: "*",
   147  	}
   148  	for _, o := range opts {
   149  		o(&options)
   150  	}
   151  	return newWatcher(rsp, options)
   152  }
   153  
   154  // Returns the router implementation
   155  func (s *svc) String() string {
   156  	return "service"
   157  }