Merge pull request #1505 from micro/resover-refactor
Extract Micro Resolver (Namespace)
This commit is contained in:
		| @@ -7,13 +7,15 @@ import ( | |||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v2/api/handler" | 	"github.com/micro/go-micro/v2/api/handler" | ||||||
|  | 	"github.com/micro/go-micro/v2/api/resolver" | ||||||
|  | 	"github.com/micro/go-micro/v2/api/resolver/vpath" | ||||||
| 	"github.com/micro/go-micro/v2/api/router" | 	"github.com/micro/go-micro/v2/api/router" | ||||||
| 	regRouter "github.com/micro/go-micro/v2/api/router/registry" | 	regRouter "github.com/micro/go-micro/v2/api/router/registry" | ||||||
| 	"github.com/micro/go-micro/v2/registry" | 	"github.com/micro/go-micro/v2/registry" | ||||||
| 	"github.com/micro/go-micro/v2/registry/memory" | 	"github.com/micro/go-micro/v2/registry/memory" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func testHttp(t *testing.T, path, service string) { | func testHttp(t *testing.T, path, service, ns string) { | ||||||
| 	r := memory.NewRegistry() | 	r := memory.NewRegistry() | ||||||
|  |  | ||||||
| 	l, err := net.Listen("tcp", "127.0.0.1:0") | 	l, err := net.Listen("tcp", "127.0.0.1:0") | ||||||
| @@ -55,6 +57,9 @@ func testHttp(t *testing.T, path, service string) { | |||||||
| 	rt := regRouter.NewRouter( | 	rt := regRouter.NewRouter( | ||||||
| 		router.WithHandler("http"), | 		router.WithHandler("http"), | ||||||
| 		router.WithRegistry(r), | 		router.WithRegistry(r), | ||||||
|  | 		router.WithResolver(vpath.NewResolver( | ||||||
|  | 			resolver.WithNamespace(resolver.StaticNamespace(ns)), | ||||||
|  | 		)), | ||||||
| 	) | 	) | ||||||
|  |  | ||||||
| 	p := NewHandler(handler.WithRouter(rt)) | 	p := NewHandler(handler.WithRouter(rt)) | ||||||
| @@ -75,38 +80,48 @@ func TestHttpHandler(t *testing.T) { | |||||||
| 	testData := []struct { | 	testData := []struct { | ||||||
| 		path      string | 		path      string | ||||||
| 		service   string | 		service   string | ||||||
|  | 		namespace string | ||||||
| 	}{ | 	}{ | ||||||
| 		{ | 		{ | ||||||
| 			"/test/foo", | 			"/test/foo", | ||||||
| 			"test", | 			"go.micro.api.test", | ||||||
|  | 			"go.micro.api", | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			"/test/foo/baz", | 			"/test/foo/baz", | ||||||
| 			"test", | 			"go.micro.api.test", | ||||||
|  | 			"go.micro.api", | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			"/v1/foo", | 			"/v1/foo", | ||||||
| 			"v1.foo", | 			"go.micro.api.v1.foo", | ||||||
|  | 			"go.micro.api", | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			"/v1/foo/bar", | 			"/v1/foo/bar", | ||||||
| 			"v1.foo", | 			"go.micro.api.v1.foo", | ||||||
|  | 			"go.micro.api", | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			"/v2/baz", | 			"/v2/baz", | ||||||
| 			"v2.baz", | 			"go.micro.api.v2.baz", | ||||||
| 		}, | 			"go.micro.api", | ||||||
| 		{ | 		}, | ||||||
| 			"/v2/baz/bar", | 		{ | ||||||
| 			"v2.baz", | 			"/v2/baz/bar", | ||||||
|  | 			"go.micro.api.v2.baz", | ||||||
|  | 			"go.micro.api", | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			"/v2/baz/bar", | 			"/v2/baz/bar", | ||||||
| 			"v2.baz", | 			"v2.baz", | ||||||
|  | 			"", | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for _, d := range testData { | 	for _, d := range testData { | ||||||
| 		testHttp(t, d.path, d.service) | 		t.Run(d.service, func(t *testing.T) { | ||||||
|  | 			testHttp(t, d.path, d.service, d.namespace) | ||||||
|  | 		}) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -7,7 +7,9 @@ import ( | |||||||
| 	"github.com/micro/go-micro/v2/api/resolver" | 	"github.com/micro/go-micro/v2/api/resolver" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type Resolver struct{} | type Resolver struct { | ||||||
|  | 	opts resolver.Options | ||||||
|  | } | ||||||
|  |  | ||||||
| func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) { | func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) { | ||||||
| 	return &resolver.Endpoint{ | 	return &resolver.Endpoint{ | ||||||
| @@ -23,5 +25,5 @@ func (r *Resolver) String() string { | |||||||
| } | } | ||||||
|  |  | ||||||
| func NewResolver(opts ...resolver.Option) resolver.Resolver { | func NewResolver(opts ...resolver.Option) resolver.Resolver { | ||||||
| 	return &Resolver{} | 	return &Resolver{opts: resolver.NewOptions(opts...)} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,50 +0,0 @@ | |||||||
| // Package micro provides a micro rpc resolver which prefixes a namespace |  | ||||||
| package micro |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"net/http" |  | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v2/api/resolver" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // default resolver for legacy purposes |  | ||||||
| // it uses proxy routing to resolve names |  | ||||||
| // /foo becomes namespace.foo |  | ||||||
| // /v1/foo becomes namespace.v1.foo |  | ||||||
| type Resolver struct { |  | ||||||
| 	Options resolver.Options |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) { |  | ||||||
| 	var name, method string |  | ||||||
|  |  | ||||||
| 	switch r.Options.Handler { |  | ||||||
| 	// internal handlers |  | ||||||
| 	case "meta", "api", "rpc", "micro": |  | ||||||
| 		name, method = apiRoute(req.URL.Path) |  | ||||||
| 	default: |  | ||||||
| 		method = req.Method |  | ||||||
| 		name = proxyRoute(req.URL.Path) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// set the namespace if it exists |  | ||||||
| 	if len(r.Options.Namespace) > 0 { |  | ||||||
| 		name = r.Options.Namespace + "." + name |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return &resolver.Endpoint{ |  | ||||||
| 		Name:   name, |  | ||||||
| 		Method: method, |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *Resolver) String() string { |  | ||||||
| 	return "micro" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // NewResolver creates a new micro resolver |  | ||||||
| func NewResolver(opts ...resolver.Option) resolver.Resolver { |  | ||||||
| 	return &Resolver{ |  | ||||||
| 		Options: resolver.NewOptions(opts...), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,95 +0,0 @@ | |||||||
| package micro |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"path" |  | ||||||
| 	"regexp" |  | ||||||
| 	"strings" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	proxyRe   = regexp.MustCompile("^[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*$") |  | ||||||
| 	versionRe = regexp.MustCompilePOSIX("^v[0-9]+$") |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // Translates /foo/bar/zool into api service go.micro.api.foo method Bar.Zool |  | ||||||
| // Translates /foo/bar into api service go.micro.api.foo method Foo.Bar |  | ||||||
| func apiRoute(p string) (string, string) { |  | ||||||
| 	p = path.Clean(p) |  | ||||||
| 	p = strings.TrimPrefix(p, "/") |  | ||||||
| 	parts := strings.Split(p, "/") |  | ||||||
|  |  | ||||||
| 	// if we have 1 part assume name Name.Call |  | ||||||
| 	if len(parts) == 1 && len(parts[0]) > 0 { |  | ||||||
| 		return parts[0], methodName(append(parts, "Call")) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// If we've got two or less parts |  | ||||||
| 	// Use first part as service |  | ||||||
| 	// Use all parts as method |  | ||||||
| 	if len(parts) <= 2 { |  | ||||||
| 		name := parts[0] |  | ||||||
| 		return name, methodName(parts) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Treat /v[0-9]+ as versioning where we have 3 parts |  | ||||||
| 	// /v1/foo/bar => service: v1.foo method: Foo.bar |  | ||||||
| 	if len(parts) == 3 && versionRe.Match([]byte(parts[0])) { |  | ||||||
| 		name := strings.Join(parts[:len(parts)-1], ".") |  | ||||||
| 		return name, methodName(parts[len(parts)-2:]) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Service is everything minus last two parts |  | ||||||
| 	// Method is the last two parts |  | ||||||
| 	name := strings.Join(parts[:len(parts)-2], ".") |  | ||||||
| 	return name, methodName(parts[len(parts)-2:]) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func proxyRoute(p string) string { |  | ||||||
| 	parts := strings.Split(p, "/") |  | ||||||
| 	if len(parts) < 2 { |  | ||||||
| 		return "" |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var service string |  | ||||||
| 	var alias string |  | ||||||
|  |  | ||||||
| 	// /[service]/methods |  | ||||||
| 	if len(parts) > 2 { |  | ||||||
| 		// /v1/[service] |  | ||||||
| 		if versionRe.MatchString(parts[1]) { |  | ||||||
| 			service = parts[1] + "." + parts[2] |  | ||||||
| 			alias = parts[2] |  | ||||||
| 		} else { |  | ||||||
| 			service = parts[1] |  | ||||||
| 			alias = parts[1] |  | ||||||
| 		} |  | ||||||
| 		// /[service] |  | ||||||
| 	} else { |  | ||||||
| 		service = parts[1] |  | ||||||
| 		alias = parts[1] |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// check service name is valid |  | ||||||
| 	if !proxyRe.MatchString(alias) { |  | ||||||
| 		return "" |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return service |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func methodName(parts []string) string { |  | ||||||
| 	for i, part := range parts { |  | ||||||
| 		parts[i] = toCamel(part) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return strings.Join(parts, ".") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func toCamel(s string) string { |  | ||||||
| 	words := strings.Split(s, "-") |  | ||||||
| 	var out string |  | ||||||
| 	for _, word := range words { |  | ||||||
| 		out += strings.Title(word) |  | ||||||
| 	} |  | ||||||
| 	return out |  | ||||||
| } |  | ||||||
| @@ -1,130 +0,0 @@ | |||||||
| package micro |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"testing" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func TestApiRoute(t *testing.T) { |  | ||||||
| 	testData := []struct { |  | ||||||
| 		path    string |  | ||||||
| 		service string |  | ||||||
| 		method  string |  | ||||||
| 	}{ |  | ||||||
| 		{ |  | ||||||
| 			"/foo/bar", |  | ||||||
| 			"foo", |  | ||||||
| 			"Foo.Bar", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"/foo/foo/bar", |  | ||||||
| 			"foo", |  | ||||||
| 			"Foo.Bar", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"/foo/bar/baz", |  | ||||||
| 			"foo", |  | ||||||
| 			"Bar.Baz", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"/foo/bar/baz-xyz", |  | ||||||
| 			"foo", |  | ||||||
| 			"Bar.BazXyz", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"/foo/bar/baz/cat", |  | ||||||
| 			"foo.bar", |  | ||||||
| 			"Baz.Cat", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"/foo/bar/baz/cat/car", |  | ||||||
| 			"foo.bar.baz", |  | ||||||
| 			"Cat.Car", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"/foo/fooBar/bazCat", |  | ||||||
| 			"foo", |  | ||||||
| 			"FooBar.BazCat", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"/v1/foo/bar", |  | ||||||
| 			"v1.foo", |  | ||||||
| 			"Foo.Bar", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"/v1/foo/bar/baz", |  | ||||||
| 			"v1.foo", |  | ||||||
| 			"Bar.Baz", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"/v1/foo/bar/baz/cat", |  | ||||||
| 			"v1.foo.bar", |  | ||||||
| 			"Baz.Cat", |  | ||||||
| 		}, |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for _, d := range testData { |  | ||||||
| 		s, m := apiRoute(d.path) |  | ||||||
| 		if d.service != s { |  | ||||||
| 			t.Fatalf("Expected service: %s for path: %s got: %s %s", d.service, d.path, s, m) |  | ||||||
| 		} |  | ||||||
| 		if d.method != m { |  | ||||||
| 			t.Fatalf("Expected service: %s for path: %s got: %s", d.method, d.path, m) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestProxyRoute(t *testing.T) { |  | ||||||
| 	testData := []struct { |  | ||||||
| 		path    string |  | ||||||
| 		service string |  | ||||||
| 	}{ |  | ||||||
| 		// no namespace |  | ||||||
| 		{ |  | ||||||
| 			"/f", |  | ||||||
| 			"f", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"/f", |  | ||||||
| 			"f", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"/f-b", |  | ||||||
| 			"f-b", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"/foo/bar", |  | ||||||
| 			"foo", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"/foo-bar", |  | ||||||
| 			"foo-bar", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"/foo-bar-baz", |  | ||||||
| 			"foo-bar-baz", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"/foo/bar/bar", |  | ||||||
| 			"foo", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"/v1/foo/bar", |  | ||||||
| 			"v1.foo", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"/v1/foo/bar/baz", |  | ||||||
| 			"v1.foo", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"/v1/foo/bar/baz/cat", |  | ||||||
| 			"v1.foo", |  | ||||||
| 		}, |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for _, d := range testData { |  | ||||||
| 		s := proxyRoute(d.path) |  | ||||||
| 		if d.service != s { |  | ||||||
| 			t.Fatalf("Expected service: %s for path: %s got: %s", d.service, d.path, s) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,11 +1,22 @@ | |||||||
| package resolver | package resolver | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"net/http" | ||||||
|  |  | ||||||
|  | 	"github.com/micro/go-micro/v2/auth" | ||||||
|  | ) | ||||||
|  |  | ||||||
| // NewOptions returns new initialised options | // NewOptions returns new initialised options | ||||||
| func NewOptions(opts ...Option) Options { | func NewOptions(opts ...Option) Options { | ||||||
| 	var options Options | 	var options Options | ||||||
| 	for _, o := range opts { | 	for _, o := range opts { | ||||||
| 		o(&options) | 		o(&options) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if options.Namespace == nil { | ||||||
|  | 		options.Namespace = StaticNamespace(auth.DefaultNamespace) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	return options | 	return options | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -16,8 +27,8 @@ func WithHandler(h string) Option { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // WithNamespace sets the namespace being used | // WithNamespace sets the function which determines the namespace for a request | ||||||
| func WithNamespace(n string) Option { | func WithNamespace(n func(*http.Request) string) Option { | ||||||
| 	return func(o *Options) { | 	return func(o *Options) { | ||||||
| 		o.Namespace = n | 		o.Namespace = n | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -8,15 +8,20 @@ import ( | |||||||
| 	"github.com/micro/go-micro/v2/api/resolver" | 	"github.com/micro/go-micro/v2/api/resolver" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type Resolver struct{} | type Resolver struct { | ||||||
|  | 	opts resolver.Options | ||||||
|  | } | ||||||
|  |  | ||||||
| func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) { | func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) { | ||||||
| 	if req.URL.Path == "/" { | 	if req.URL.Path == "/" { | ||||||
| 		return nil, resolver.ErrNotFound | 		return nil, resolver.ErrNotFound | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	parts := strings.Split(req.URL.Path[1:], "/") | 	parts := strings.Split(req.URL.Path[1:], "/") | ||||||
|  | 	ns := r.opts.Namespace(req) | ||||||
|  |  | ||||||
| 	return &resolver.Endpoint{ | 	return &resolver.Endpoint{ | ||||||
| 		Name:   parts[0], | 		Name:   ns + "." + parts[0], | ||||||
| 		Host:   req.Host, | 		Host:   req.Host, | ||||||
| 		Method: req.Method, | 		Method: req.Method, | ||||||
| 		Path:   req.URL.Path, | 		Path:   req.URL.Path, | ||||||
| @@ -28,5 +33,5 @@ func (r *Resolver) String() string { | |||||||
| } | } | ||||||
|  |  | ||||||
| func NewResolver(opts ...resolver.Option) resolver.Resolver { | func NewResolver(opts ...resolver.Option) resolver.Resolver { | ||||||
| 	return &Resolver{} | 	return &Resolver{opts: resolver.NewOptions(opts...)} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -31,7 +31,14 @@ type Endpoint struct { | |||||||
|  |  | ||||||
| type Options struct { | type Options struct { | ||||||
| 	Handler   string | 	Handler   string | ||||||
| 	Namespace string | 	Namespace func(*http.Request) string | ||||||
| } | } | ||||||
|  |  | ||||||
| type Option func(o *Options) | type Option func(o *Options) | ||||||
|  |  | ||||||
|  | // StaticNamespace returns the same namespace for each request | ||||||
|  | func StaticNamespace(ns string) func(*http.Request) string { | ||||||
|  | 	return func(*http.Request) string { | ||||||
|  | 		return ns | ||||||
|  | 	} | ||||||
|  | } | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ package vpath | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"errors" | 	"errors" | ||||||
|  | 	"fmt" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"regexp" | 	"regexp" | ||||||
| 	"strings" | 	"strings" | ||||||
| @@ -10,7 +11,13 @@ import ( | |||||||
| 	"github.com/micro/go-micro/v2/api/resolver" | 	"github.com/micro/go-micro/v2/api/resolver" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type Resolver struct{} | func NewResolver(opts ...resolver.Option) resolver.Resolver { | ||||||
|  | 	return &Resolver{opts: resolver.NewOptions(opts...)} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type Resolver struct { | ||||||
|  | 	opts resolver.Options | ||||||
|  | } | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	re = regexp.MustCompile("^v[0-9]+$") | 	re = regexp.MustCompile("^v[0-9]+$") | ||||||
| @@ -21,11 +28,12 @@ func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) { | |||||||
| 		return nil, errors.New("unknown name") | 		return nil, errors.New("unknown name") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	parts := strings.Split(req.URL.Path[1:], "/") | 	fmt.Println(req.URL.Path) | ||||||
|  |  | ||||||
|  | 	parts := strings.Split(req.URL.Path[1:], "/") | ||||||
| 	if len(parts) == 1 { | 	if len(parts) == 1 { | ||||||
| 		return &resolver.Endpoint{ | 		return &resolver.Endpoint{ | ||||||
| 			Name:   parts[0], | 			Name:   r.withNamespace(req, parts...), | ||||||
| 			Host:   req.Host, | 			Host:   req.Host, | ||||||
| 			Method: req.Method, | 			Method: req.Method, | ||||||
| 			Path:   req.URL.Path, | 			Path:   req.URL.Path, | ||||||
| @@ -35,7 +43,7 @@ func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) { | |||||||
| 	// /v1/foo | 	// /v1/foo | ||||||
| 	if re.MatchString(parts[0]) { | 	if re.MatchString(parts[0]) { | ||||||
| 		return &resolver.Endpoint{ | 		return &resolver.Endpoint{ | ||||||
| 			Name:   parts[1], | 			Name:   r.withNamespace(req, parts[0:2]...), | ||||||
| 			Host:   req.Host, | 			Host:   req.Host, | ||||||
| 			Method: req.Method, | 			Method: req.Method, | ||||||
| 			Path:   req.URL.Path, | 			Path:   req.URL.Path, | ||||||
| @@ -43,7 +51,7 @@ func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return &resolver.Endpoint{ | 	return &resolver.Endpoint{ | ||||||
| 		Name:   parts[0], | 		Name:   r.withNamespace(req, parts[0]), | ||||||
| 		Host:   req.Host, | 		Host:   req.Host, | ||||||
| 		Method: req.Method, | 		Method: req.Method, | ||||||
| 		Path:   req.URL.Path, | 		Path:   req.URL.Path, | ||||||
| @@ -54,6 +62,11 @@ func (r *Resolver) String() string { | |||||||
| 	return "path" | 	return "path" | ||||||
| } | } | ||||||
|  |  | ||||||
| func NewResolver(opts ...resolver.Option) resolver.Resolver { | func (r *Resolver) withNamespace(req *http.Request, parts ...string) string { | ||||||
| 	return &Resolver{} | 	ns := r.opts.Namespace(req) | ||||||
|  | 	if len(ns) == 0 { | ||||||
|  | 		return strings.Join(parts, ".") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return strings.Join(append([]string{ns}, parts...), ".") | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ package router | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"github.com/micro/go-micro/v2/api/resolver" | 	"github.com/micro/go-micro/v2/api/resolver" | ||||||
| 	"github.com/micro/go-micro/v2/api/resolver/micro" | 	"github.com/micro/go-micro/v2/api/resolver/vpath" | ||||||
| 	"github.com/micro/go-micro/v2/registry" | 	"github.com/micro/go-micro/v2/registry" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -25,7 +25,7 @@ func NewOptions(opts ...Option) Options { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if options.Resolver == nil { | 	if options.Resolver == nil { | ||||||
| 		options.Resolver = micro.NewResolver( | 		options.Resolver = vpath.NewResolver( | ||||||
| 			resolver.WithHandler(options.Handler), | 			resolver.WithHandler(options.Handler), | ||||||
| 		) | 		) | ||||||
| 	} | 	} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user