Add remote lookup via router selector
This commit is contained in:
		| @@ -4,12 +4,15 @@ package router | |||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"net" | 	"net" | ||||||
|  | 	"os" | ||||||
| 	"sort" | 	"sort" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"sync" | 	"sync" | ||||||
|  |  | ||||||
|  | 	"github.com/micro/go-micro/client" | ||||||
| 	"github.com/micro/go-micro/client/selector" | 	"github.com/micro/go-micro/client/selector" | ||||||
| 	"github.com/micro/go-micro/network/router" | 	"github.com/micro/go-micro/network/router" | ||||||
|  | 	pb "github.com/micro/go-micro/network/router/proto" | ||||||
| 	"github.com/micro/go-micro/registry" | 	"github.com/micro/go-micro/registry" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -18,10 +21,64 @@ type routerSelector struct { | |||||||
|  |  | ||||||
| 	// the router | 	// the router | ||||||
| 	r router.Router | 	r router.Router | ||||||
|  |  | ||||||
|  | 	// the client for the remote router | ||||||
|  | 	c pb.RouterService | ||||||
|  |  | ||||||
|  | 	// address of the remote router | ||||||
|  | 	addr string | ||||||
|  |  | ||||||
|  | 	// whether to use the remote router | ||||||
|  | 	remote bool | ||||||
| } | } | ||||||
|  |  | ||||||
|  | type clientKey struct{} | ||||||
| type routerKey struct{} | type routerKey struct{} | ||||||
|  |  | ||||||
|  | // getRoutes returns the routes whether they are remote or local | ||||||
|  | func (r *routerSelector) getRoutes(service string) ([]router.Route, error) { | ||||||
|  | 	if !r.remote { | ||||||
|  | 		// lookup router for routes for the service | ||||||
|  | 		return r.r.Table().Lookup(router.NewQuery( | ||||||
|  | 			router.QueryDestination(service), | ||||||
|  | 		)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// lookup the remote router | ||||||
|  |  | ||||||
|  | 	var clientOpts []client.CallOption | ||||||
|  |  | ||||||
|  | 	// set the remote address if specified | ||||||
|  | 	if len(r.addr) > 0 { | ||||||
|  | 		clientOpts = append(clientOpts, client.WithAddress(r.addr)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// call the router | ||||||
|  | 	pbRoutes, err := r.c.Lookup(context.Background(), &pb.LookupRequest{ | ||||||
|  | 		Query: &pb.Query{ | ||||||
|  | 			Destination: service, | ||||||
|  | 		}, | ||||||
|  | 	}, clientOpts...) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var routes []router.Route | ||||||
|  |  | ||||||
|  | 	// convert from pb to []*router.Route | ||||||
|  | 	for _, r := range pbRoutes.Routes { | ||||||
|  | 		routes = append(routes, router.Route{ | ||||||
|  | 			Destination: r.Destination, | ||||||
|  | 			Gateway:     r.Gateway, | ||||||
|  | 			Router:      r.Router, | ||||||
|  | 			Network:     r.Network, | ||||||
|  | 			Metric:      int(r.Metric), | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return routes, nil | ||||||
|  | } | ||||||
|  |  | ||||||
| func (r *routerSelector) Init(opts ...selector.Option) error { | func (r *routerSelector) Init(opts ...selector.Option) error { | ||||||
| 	// no op | 	// no op | ||||||
| 	return nil | 	return nil | ||||||
| @@ -32,11 +89,8 @@ func (r *routerSelector) Options() selector.Options { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (r *routerSelector) Select(service string, opts ...selector.SelectOption) (selector.Next, error) { | func (r *routerSelector) Select(service string, opts ...selector.SelectOption) (selector.Next, error) { | ||||||
| 	// lookup router for routes for the service | 	// TODO: pull routes asynchronously and cache | ||||||
| 	routes, err := r.r.Table().Lookup(router.NewQuery( | 	routes, err := r.getRoutes(service) | ||||||
| 		router.QueryDestination(service), |  | ||||||
| 	)) |  | ||||||
|  |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| @@ -124,7 +178,7 @@ func NewSelector(opts ...selector.Option) selector.Selector { | |||||||
| 		options.Registry = registry.DefaultRegistry | 		options.Registry = registry.DefaultRegistry | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// try get from the context | 	// try get router from the context | ||||||
| 	r, ok := options.Context.Value(routerKey{}).(router.Router) | 	r, ok := options.Context.Value(routerKey{}).(router.Router) | ||||||
| 	if !ok { | 	if !ok { | ||||||
| 		// TODO: Use router.DefaultRouter? | 		// TODO: Use router.DefaultRouter? | ||||||
| @@ -133,12 +187,43 @@ func NewSelector(opts ...selector.Option) selector.Selector { | |||||||
| 		) | 		) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// start the router advertisements | 	// try get client from the context | ||||||
| 	r.Advertise() | 	c, ok := options.Context.Value(clientKey{}).(client.Client) | ||||||
|  | 	if !ok { | ||||||
|  | 		c = client.DefaultClient | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// get the router from env vars if its a remote service | ||||||
|  | 	remote := true | ||||||
|  | 	routerName := os.Getenv("MICRO_ROUTER") | ||||||
|  | 	routerAddress := os.Getenv("MICRO_ROUTER_ADDRESS") | ||||||
|  |  | ||||||
|  | 	// start the router advertisements if we're running it locally | ||||||
|  | 	if len(routerName) == 0 && len(routerAddress) == 0 { | ||||||
|  | 		go r.Advertise() | ||||||
|  | 		remote = false | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	return &routerSelector{ | 	return &routerSelector{ | ||||||
| 		opts: options, | 		opts: options, | ||||||
| 		r:    r, | 		// set the internal router | ||||||
|  | 		r: r, | ||||||
|  | 		// set the client | ||||||
|  | 		c: pb.NewRouterService(routerName, c), | ||||||
|  | 		// address of router | ||||||
|  | 		addr: routerAddress, | ||||||
|  | 		// let ourselves know to use the remote router | ||||||
|  | 		remote: remote, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // WithClient sets the client for the request | ||||||
|  | func WithClient(c client.Client) selector.Option { | ||||||
|  | 	return func(o *selector.Options) { | ||||||
|  | 		if o.Context == nil { | ||||||
|  | 			o.Context = context.Background() | ||||||
|  | 		} | ||||||
|  | 		o.Context = context.WithValue(o.Context, clientKey{}, c) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user