From 09e7282b2bf3cf261b82fb863de36670b557edf4 Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Fri, 30 Jul 2021 23:02:50 +0300 Subject: [PATCH] fix path template parsing Signed-off-by: Vasiliy Tolstov --- go.mod | 2 +- go.sum | 4 +-- http.go | 79 ++++++++++++++++++++++++++++++---------------------- util.go | 38 ++++++++++++++----------- util_test.go | 30 ++++++++++++++++---- 5 files changed, 93 insertions(+), 60 deletions(-) diff --git a/go.mod b/go.mod index bea54cb..66b6819 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,4 @@ module github.com/unistack-org/micro-client-http/v3 go 1.16 -require github.com/unistack-org/micro/v3 v3.5.2 +require github.com/unistack-org/micro/v3 v3.5.4 diff --git a/go.sum b/go.sum index f8847d3..94ade26 100644 --- a/go.sum +++ b/go.sum @@ -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/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/unistack-org/micro/v3 v3.5.2 h1:8b9Mk4FLWRLp8SduBh5Xs6g/3xJ+ZIBOnH82eHuLWnw= -github.com/unistack-org/micro/v3 v3.5.2/go.mod h1:1ZkwpEqpiHiVhM2hiF9DamtpsF04oFybFhEQ4zEMcro= +github.com/unistack-org/micro/v3 v3.5.4 h1:6nIljqND355f+Fhc2mtCxYb5IRwer6nsMoAXpN8kka0= +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/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/http.go b/http.go index cec0d95..9bab942 100644 --- a/http.go +++ b/http.go @@ -532,50 +532,61 @@ func (h *httpClient) Stream(ctx context.Context, req client.Request, opts ...cli 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 { + 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...) - md, ok := metadata.FromOutgoingContext(ctx) - if !ok { - md = metadata.New(2) - } - md[metadata.HeaderContentType] = p.ContentType() - md[metadata.HeaderTopic] = p.Topic() - - cf, err := h.newCodec(p.ContentType()) - if err != nil { - return errors.InternalServerError("go.micro.client", err.Error()) + // get proxy + exchange := "" + if v, ok := os.LookupEnv("MICRO_PROXY"); ok { + exchange = v } - var body []byte + msgs := make([]*broker.Message, 0, len(ps)) - // passed in raw data - if d, ok := p.Payload().(*codec.Frame); ok { - body = d.Data - } else { - b := bytes.NewBuffer(nil) - if err := cf.Write(b, &codec.Message{Type: codec.Event}, p.Payload()); err != nil { + for _, p := range ps { + md, ok := metadata.FromOutgoingContext(ctx) + if !ok { + md = metadata.New(2) + } + md[metadata.HeaderContentType] = p.ContentType() + md[metadata.HeaderTopic] = p.Topic() + + cf, err := h.newCodec(p.ContentType()) + if err != nil { return errors.InternalServerError("go.micro.client", err.Error()) } - body = b.Bytes() + + var body []byte + + // passed in raw data + if d, ok := p.Payload().(*codec.Frame); ok { + body = d.Data + } else { + b := bytes.NewBuffer(nil) + if err := cf.Write(b, &codec.Message{Type: codec.Event}, p.Payload()); err != nil { + return errors.InternalServerError("go.micro.client", err.Error()) + } + body = b.Bytes() + } + + topic := p.Topic() + if len(exchange) > 0 { + topic = exchange + } + + md.Set(metadata.HeaderTopic, topic) + msgs = append(msgs, &broker.Message{Header: md, Body: body}) } - topic := p.Topic() - - // get proxy - if prx := os.Getenv("MICRO_PROXY"); len(prx) > 0 { - options.Exchange = prx - } - - // get the exchange - if len(options.Exchange) > 0 { - topic = options.Exchange - } - - return h.opts.Broker.Publish(ctx, topic, &broker.Message{ - Header: md, - Body: body, - }, + return h.opts.Broker.BatchPublish(ctx, msgs, broker.PublishContext(ctx), broker.PublishBodyOnly(options.BodyOnly), ) diff --git a/util.go b/util.go index 0747dfd..16288a6 100644 --- a/util.go +++ b/util.go @@ -14,11 +14,10 @@ import ( "github.com/unistack-org/micro/v3/errors" "github.com/unistack-org/micro/v3/logger" rutil "github.com/unistack-org/micro/v3/util/reflect" - util "github.com/unistack-org/micro/v3/util/router" ) var ( - templateCache = make(map[string]util.Template) + templateCache = make(map[string][]string) mu sync.RWMutex ) @@ -46,14 +45,17 @@ func newPathRequest(path string, method string, body string, msg interface{}, ta 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) } fieldsmapskip := make(map[string]struct{}) - fieldsmap := make(map[string]string, len(tpl.Fields)) - for _, v := range tpl.Fields { - fieldsmap[v] = "" + fieldsmap := make(map[string]string, len(tpl)) + for _, v := range tpl { + if v[0] != '{' || v[len(v)-1] != '}' { + continue + } + fieldsmap[v[1:len(v)-1]] = "" } nmsg, err := rutil.Zero(msg) @@ -149,11 +151,15 @@ func newPathRequest(path string, method string, body string, msg interface{}, ta } var b strings.Builder - for _, fld := range tpl.Pool { + for _, fld := range tpl { _, _ = b.WriteRune('/') - if v, ok := fieldsmap[fld]; ok { - if v != "" { - _, _ = b.WriteString(v) + if fld[0] == '{' && fld[len(fld)-1] == '}' { + if v, ok := fieldsmap[fld[1:len(fld)-1]]; ok { + if v != "" { + _, _ = b.WriteString(v) + } + } else { + _, _ = b.WriteString(fld) } } else { _, _ = b.WriteString(fld) @@ -172,7 +178,10 @@ func newPathRequest(path string, method string, body string, msg interface{}, ta 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() tpl, ok := templateCache[path] if ok { @@ -181,12 +190,7 @@ func newTemplate(path string) (util.Template, error) { } mu.RUnlock() - rule, err := util.Parse(path) - if err != nil { - return tpl, err - } - - tpl = rule.Compile() + tpl = strings.Split(path[1:], "/") mu.Lock() templateCache[path] = tpl mu.Unlock() diff --git a/util_test.go b/util_test.go index 5cca886..03acf84 100644 --- a/util_test.go +++ b/util_test.go @@ -5,13 +5,31 @@ import ( "testing" ) -func TestTemplate(t *testing.T) { - tpl, err := newTemplate("/v1/{ClientID}/list") - if err != nil { - t.Fatal(err) +func TestParsing(t *testing.T) { + 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 { + t.Fatal(err) + } + u, err := url.Parse(path) + 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) + } } - _ = tpl - // fmt.Printf("%#+v\n", tpl.Pool) } func TestNewPathRequest(t *testing.T) {