fix path template parsing

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
This commit is contained in:
Василий Толстов 2021-07-30 23:02:50 +03:00
parent 5f029fd432
commit 09e7282b2b
5 changed files with 93 additions and 60 deletions

2
go.mod
View File

@ -2,4 +2,4 @@ module github.com/unistack-org/micro-client-http/v3
go 1.16 go 1.16
require github.com/unistack-org/micro/v3 v3.5.2 require github.com/unistack-org/micro/v3 v3.5.4

4
go.sum
View File

@ -5,8 +5,8 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/silas/dag v0.0.0-20210121180416-41cf55125c34/go.mod h1:7RTUFBdIRC9nZ7/3RyRNH1bdqIShrDejd1YbLwgPS+I= github.com/silas/dag v0.0.0-20210121180416-41cf55125c34/go.mod h1:7RTUFBdIRC9nZ7/3RyRNH1bdqIShrDejd1YbLwgPS+I=
github.com/unistack-org/micro/v3 v3.5.2 h1:8b9Mk4FLWRLp8SduBh5Xs6g/3xJ+ZIBOnH82eHuLWnw= github.com/unistack-org/micro/v3 v3.5.4 h1:6nIljqND355f+Fhc2mtCxYb5IRwer6nsMoAXpN8kka0=
github.com/unistack-org/micro/v3 v3.5.2/go.mod h1:1ZkwpEqpiHiVhM2hiF9DamtpsF04oFybFhEQ4zEMcro= github.com/unistack-org/micro/v3 v3.5.4/go.mod h1:1ZkwpEqpiHiVhM2hiF9DamtpsF04oFybFhEQ4zEMcro=
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

33
http.go
View File

@ -532,9 +532,26 @@ func (h *httpClient) Stream(ctx context.Context, req client.Request, opts ...cli
return nil, grr return nil, grr
} }
func (h *httpClient) BatchPublish(ctx context.Context, p []client.Message, opts ...client.PublishOption) error {
return h.publish(ctx, p, opts...)
}
func (h *httpClient) Publish(ctx context.Context, p client.Message, opts ...client.PublishOption) error { func (h *httpClient) Publish(ctx context.Context, p client.Message, opts ...client.PublishOption) error {
return h.publish(ctx, []client.Message{p}, opts...)
}
func (h *httpClient) publish(ctx context.Context, ps []client.Message, opts ...client.PublishOption) error {
options := client.NewPublishOptions(opts...) options := client.NewPublishOptions(opts...)
// get proxy
exchange := ""
if v, ok := os.LookupEnv("MICRO_PROXY"); ok {
exchange = v
}
msgs := make([]*broker.Message, 0, len(ps))
for _, p := range ps {
md, ok := metadata.FromOutgoingContext(ctx) md, ok := metadata.FromOutgoingContext(ctx)
if !ok { if !ok {
md = metadata.New(2) md = metadata.New(2)
@ -561,21 +578,15 @@ func (h *httpClient) Publish(ctx context.Context, p client.Message, opts ...clie
} }
topic := p.Topic() topic := p.Topic()
if len(exchange) > 0 {
// get proxy topic = exchange
if prx := os.Getenv("MICRO_PROXY"); len(prx) > 0 {
options.Exchange = prx
} }
// get the exchange md.Set(metadata.HeaderTopic, topic)
if len(options.Exchange) > 0 { msgs = append(msgs, &broker.Message{Header: md, Body: body})
topic = options.Exchange
} }
return h.opts.Broker.Publish(ctx, topic, &broker.Message{ return h.opts.Broker.BatchPublish(ctx, msgs,
Header: md,
Body: body,
},
broker.PublishContext(ctx), broker.PublishContext(ctx),
broker.PublishBodyOnly(options.BodyOnly), broker.PublishBodyOnly(options.BodyOnly),
) )

34
util.go
View File

@ -14,11 +14,10 @@ import (
"github.com/unistack-org/micro/v3/errors" "github.com/unistack-org/micro/v3/errors"
"github.com/unistack-org/micro/v3/logger" "github.com/unistack-org/micro/v3/logger"
rutil "github.com/unistack-org/micro/v3/util/reflect" rutil "github.com/unistack-org/micro/v3/util/reflect"
util "github.com/unistack-org/micro/v3/util/router"
) )
var ( var (
templateCache = make(map[string]util.Template) templateCache = make(map[string][]string)
mu sync.RWMutex mu sync.RWMutex
) )
@ -46,14 +45,17 @@ func newPathRequest(path string, method string, body string, msg interface{}, ta
return "", nil, err return "", nil, err
} }
if len(tpl.Fields) > 0 && msg == nil { if len(tpl) > 0 && msg == nil {
return "", nil, fmt.Errorf("nil message but path params requested: %v", path) return "", nil, fmt.Errorf("nil message but path params requested: %v", path)
} }
fieldsmapskip := make(map[string]struct{}) fieldsmapskip := make(map[string]struct{})
fieldsmap := make(map[string]string, len(tpl.Fields)) fieldsmap := make(map[string]string, len(tpl))
for _, v := range tpl.Fields { for _, v := range tpl {
fieldsmap[v] = "" if v[0] != '{' || v[len(v)-1] != '}' {
continue
}
fieldsmap[v[1:len(v)-1]] = ""
} }
nmsg, err := rutil.Zero(msg) nmsg, err := rutil.Zero(msg)
@ -149,15 +151,19 @@ func newPathRequest(path string, method string, body string, msg interface{}, ta
} }
var b strings.Builder var b strings.Builder
for _, fld := range tpl.Pool { for _, fld := range tpl {
_, _ = b.WriteRune('/') _, _ = b.WriteRune('/')
if v, ok := fieldsmap[fld]; ok { if fld[0] == '{' && fld[len(fld)-1] == '}' {
if v, ok := fieldsmap[fld[1:len(fld)-1]]; ok {
if v != "" { if v != "" {
_, _ = b.WriteString(v) _, _ = b.WriteString(v)
} }
} else { } else {
_, _ = b.WriteString(fld) _, _ = b.WriteString(fld)
} }
} else {
_, _ = b.WriteString(fld)
}
} }
if len(values) > 0 { if len(values) > 0 {
@ -172,7 +178,10 @@ func newPathRequest(path string, method string, body string, msg interface{}, ta
return b.String(), nmsg, nil return b.String(), nmsg, nil
} }
func newTemplate(path string) (util.Template, error) { func newTemplate(path string) ([]string, error) {
if len(path) == 0 || path[0] != '/' {
return nil, fmt.Errorf("path must starts with /")
}
mu.RLock() mu.RLock()
tpl, ok := templateCache[path] tpl, ok := templateCache[path]
if ok { if ok {
@ -181,12 +190,7 @@ func newTemplate(path string) (util.Template, error) {
} }
mu.RUnlock() mu.RUnlock()
rule, err := util.Parse(path) tpl = strings.Split(path[1:], "/")
if err != nil {
return tpl, err
}
tpl = rule.Compile()
mu.Lock() mu.Lock()
templateCache[path] = tpl templateCache[path] = tpl
mu.Unlock() mu.Unlock()

View File

@ -5,13 +5,31 @@ import (
"testing" "testing"
) )
func TestTemplate(t *testing.T) { func TestParsing(t *testing.T) {
tpl, err := newTemplate("/v1/{ClientID}/list") type Message struct {
IIN string `protobuf:"bytes,1,opt,name=iin,proto3" json:"iin"`
}
omsg := &Message{IIN: "5555"}
for _, m := range []string{"POST"} {
body := ""
path, nmsg, err := newPathRequest("/users/iin/{iin}/push-notifications", m, body, omsg, []string{"protobuf", "json"})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
_ = tpl u, err := url.Parse(path)
// fmt.Printf("%#+v\n", tpl.Pool) if err != nil {
t.Fatal(err)
}
_ = nmsg
if u.Path != "/users/iin/5555/push-notifications" {
t.Fatalf("newPathRequest invalid path %s", u.Path)
}
if nmsg != nil {
t.Fatalf("new message must be nil: %v\n", nmsg)
}
}
} }
func TestNewPathRequest(t *testing.T) { func TestNewPathRequest(t *testing.T) {