From 18eb0d9e5ce695b5136dd7e8088be49482766cb2 Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Fri, 28 Apr 2023 22:29:18 +0300 Subject: [PATCH 01/10] move to micro v4 Signed-off-by: Vasiliy Tolstov --- README.md | 4 ++-- go.mod | 6 +++--- go.sum | 10 ++-------- http.go | 18 +++++++++--------- message.go | 4 ++-- options.go | 4 ++-- request.go | 4 ++-- stream.go | 8 ++++---- util.go | 8 ++++---- 9 files changed, 30 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 564d4bd..2b23578 100644 --- a/README.md +++ b/README.md @@ -5,14 +5,14 @@ This plugin is a http client for micro. ## Overview The http client wraps `net/http` to provide a robust micro client with service discovery, load balancing and streaming. -It complies with the [micro.Client](https://godoc.org/go.unistack.org/micro-client-http/v3#Client) interface. +It complies with the [micro.Client](https://godoc.org/go.unistack.org/micro-client-http/v4#Client) interface. ## Usage ### Use directly ```go -import "go.unistack.org/micro-client-http/v3" +import "go.unistack.org/micro-client-http/v4" service := micro.NewService( micro.Name("my.service"), diff --git a/go.mod b/go.mod index 4f0bd11..3393dc1 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,5 @@ -module go.unistack.org/micro-client-http/v3 +module go.unistack.org/micro-client-http/v4 -go 1.18 +go 1.19 -require go.unistack.org/micro/v3 v3.10.16 +require go.unistack.org/micro/v4 v4.0.1 diff --git a/go.sum b/go.sum index af3467d..ff93cdc 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,2 @@ -github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= -github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/silas/dag v0.0.0-20211117232152-9d50aa809f35/go.mod h1:7RTUFBdIRC9nZ7/3RyRNH1bdqIShrDejd1YbLwgPS+I= -go.unistack.org/micro/v3 v3.10.16 h1:2er/SKKYbV60M+UuJM4eYCF0MZYAIq/yNUrAbTfgq8Q= -go.unistack.org/micro/v3 v3.10.16/go.mod h1:uMAc0U/x7dmtICCrblGf0ZLgYegu3VwQAquu+OFCw1Q= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +go.unistack.org/micro/v4 v4.0.1 h1:xo1IxbVfgh8i0eY0VeYa3cbb13u5n/Mxnp3FOgWD4Jo= +go.unistack.org/micro/v4 v4.0.1/go.mod h1:p/J5UcSJjfHsWGT31uKoghQ5rUQZzQJBAFy+Z4+ZVMs= diff --git a/http.go b/http.go index 22150b8..35c8495 100644 --- a/http.go +++ b/http.go @@ -1,5 +1,5 @@ // Package http provides a http client -package http // import "go.unistack.org/micro-client-http/v3" +package http // import "go.unistack.org/micro-client-http/v4" import ( "bufio" @@ -15,14 +15,14 @@ import ( "sync" "time" - "go.unistack.org/micro/v3/broker" - "go.unistack.org/micro/v3/client" - "go.unistack.org/micro/v3/codec" - "go.unistack.org/micro/v3/errors" - "go.unistack.org/micro/v3/logger" - "go.unistack.org/micro/v3/metadata" - "go.unistack.org/micro/v3/selector" - rutil "go.unistack.org/micro/v3/util/reflect" + "go.unistack.org/micro/v4/broker" + "go.unistack.org/micro/v4/client" + "go.unistack.org/micro/v4/codec" + "go.unistack.org/micro/v4/errors" + "go.unistack.org/micro/v4/logger" + "go.unistack.org/micro/v4/metadata" + "go.unistack.org/micro/v4/selector" + rutil "go.unistack.org/micro/v4/util/reflect" ) var DefaultContentType = "application/json" diff --git a/message.go b/message.go index 5b7f95a..c356af0 100644 --- a/message.go +++ b/message.go @@ -1,8 +1,8 @@ package http import ( - "go.unistack.org/micro/v3/client" - "go.unistack.org/micro/v3/metadata" + "go.unistack.org/micro/v4/client" + "go.unistack.org/micro/v4/metadata" ) type httpMessage struct { diff --git a/options.go b/options.go index 0e24695..3590a05 100644 --- a/options.go +++ b/options.go @@ -4,8 +4,8 @@ import ( "net" "net/http" - "go.unistack.org/micro/v3/client" - "go.unistack.org/micro/v3/metadata" + "go.unistack.org/micro/v4/client" + "go.unistack.org/micro/v4/metadata" ) var ( diff --git a/request.go b/request.go index 00c23a4..0622422 100644 --- a/request.go +++ b/request.go @@ -1,8 +1,8 @@ package http import ( - "go.unistack.org/micro/v3/client" - "go.unistack.org/micro/v3/codec" + "go.unistack.org/micro/v4/client" + "go.unistack.org/micro/v4/codec" ) type httpRequest struct { diff --git a/stream.go b/stream.go index 7c70b50..fbd0d8c 100644 --- a/stream.go +++ b/stream.go @@ -9,10 +9,10 @@ import ( "net/http" "sync" - "go.unistack.org/micro/v3/client" - "go.unistack.org/micro/v3/codec" - "go.unistack.org/micro/v3/errors" - "go.unistack.org/micro/v3/logger" + "go.unistack.org/micro/v4/client" + "go.unistack.org/micro/v4/codec" + "go.unistack.org/micro/v4/errors" + "go.unistack.org/micro/v4/logger" ) // Implements the streamer interface diff --git a/util.go b/util.go index f5fcf36..96a0e2f 100644 --- a/util.go +++ b/util.go @@ -10,10 +10,10 @@ import ( "strings" "sync" - "go.unistack.org/micro/v3/client" - "go.unistack.org/micro/v3/errors" - "go.unistack.org/micro/v3/logger" - rutil "go.unistack.org/micro/v3/util/reflect" + "go.unistack.org/micro/v4/client" + "go.unistack.org/micro/v4/errors" + "go.unistack.org/micro/v4/logger" + rutil "go.unistack.org/micro/v4/util/reflect" ) var ( -- 2.49.1 From 21c897be4705b04cc136a39153e5e5c9883b3760 Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Tue, 11 Jul 2023 00:47:36 +0300 Subject: [PATCH 02/10] fix request/response md handling Signed-off-by: Vasiliy Tolstov --- http.go | 79 ++++-------------------------------------------------- message.go | 44 ------------------------------ util.go | 10 ++++++- 3 files changed, 14 insertions(+), 119 deletions(-) delete mode 100644 message.go diff --git a/http.go b/http.go index 35c8495..7cfa677 100644 --- a/http.go +++ b/http.go @@ -10,12 +10,10 @@ import ( "net" "net/http" "net/url" - "os" "strings" "sync" "time" - "go.unistack.org/micro/v4/broker" "go.unistack.org/micro/v4/client" "go.unistack.org/micro/v4/codec" "go.unistack.org/micro/v4/errors" @@ -147,6 +145,11 @@ func newRequest(ctx context.Context, log logger.Logger, addr string, req client. if opts.AuthToken != "" { header.Set(metadata.HeaderAuthorization, opts.AuthToken) } + if opts.RequestMetadata != nil { + for k, v := range opts.RequestMetadata { + header.Set(k, v) + } + } if md, ok := metadata.FromOutgoingContext(ctx); ok { for k, v := range md { @@ -308,9 +311,6 @@ func (h *httpClient) Init(opts ...client.Option) error { o(&h.opts) } - if err := h.opts.Broker.Init(); err != nil { - return err - } if err := h.opts.Tracer.Init(); err != nil { return err } @@ -334,10 +334,6 @@ func (h *httpClient) Options() client.Options { return h.opts } -func (h *httpClient) NewMessage(topic string, msg interface{}, opts ...client.MessageOption) client.Message { - return newHTTPMessage(topic, msg, h.opts.ContentType, opts...) -} - func (h *httpClient) NewRequest(service, method string, req interface{}, opts ...client.RequestOption) client.Request { return newHTTPRequest(service, method, req, h.opts.ContentType, opts...) } @@ -614,71 +610,6 @@ 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 { - var body []byte - - options := client.NewPublishOptions(opts...) - - // get proxy - exchange := "" - if v, ok := os.LookupEnv("MICRO_PROXY"); ok { - exchange = v - } - - omd, ok := metadata.FromOutgoingContext(ctx) - if !ok { - omd = metadata.New(2) - } - - msgs := make([]*broker.Message, 0, len(ps)) - - for _, p := range ps { - md := metadata.Copy(omd) - md[metadata.HeaderContentType] = p.ContentType() - - // passed in raw data - if d, ok := p.Payload().(*codec.Frame); ok { - body = d.Data - } else { - // use codec for payload - cf, err := h.newCodec(p.ContentType()) - if err != nil { - return errors.InternalServerError("go.micro.client", err.Error()) - } - // set the body - b, err := cf.Marshal(p.Payload()) - if err != nil { - return errors.InternalServerError("go.micro.client", err.Error()) - } - body = b - } - - topic := p.Topic() - if len(exchange) > 0 { - topic = exchange - } - - for k, v := range p.Metadata() { - md.Set(k, v) - } - md.Set(metadata.HeaderTopic, topic) - msgs = append(msgs, &broker.Message{Header: md, Body: body}) - } - - return h.opts.Broker.BatchPublish(ctx, msgs, - broker.PublishContext(ctx), - broker.PublishBodyOnly(options.BodyOnly), - ) -} - func (h *httpClient) String() string { return "http" } diff --git a/message.go b/message.go deleted file mode 100644 index c356af0..0000000 --- a/message.go +++ /dev/null @@ -1,44 +0,0 @@ -package http - -import ( - "go.unistack.org/micro/v4/client" - "go.unistack.org/micro/v4/metadata" -) - -type httpMessage struct { - payload interface{} - topic string - contentType string - opts client.MessageOptions -} - -func newHTTPMessage(topic string, payload interface{}, contentType string, opts ...client.MessageOption) client.Message { - options := client.NewMessageOptions(opts...) - - if len(options.ContentType) > 0 { - contentType = options.ContentType - } - - return &httpMessage{ - payload: payload, - topic: topic, - contentType: contentType, - opts: options, - } -} - -func (h *httpMessage) ContentType() string { - return h.contentType -} - -func (h *httpMessage) Topic() string { - return h.topic -} - -func (h *httpMessage) Payload() interface{} { - return h.payload -} - -func (h *httpMessage) Metadata() metadata.Metadata { - return h.opts.Metadata -} diff --git a/util.go b/util.go index 96a0e2f..0a59021 100644 --- a/util.go +++ b/util.go @@ -13,6 +13,7 @@ import ( "go.unistack.org/micro/v4/client" "go.unistack.org/micro/v4/errors" "go.unistack.org/micro/v4/logger" + "go.unistack.org/micro/v4/metadata" rutil "go.unistack.org/micro/v4/util/reflect" ) @@ -252,6 +253,13 @@ func (h *httpClient) parseRsp(ctx context.Context, hrsp *http.Response, rsp inte return nil } + if opts.ResponseMetadata != nil { + *opts.ResponseMetadata = metadata.New(len(hrsp.Header)) + for k, v := range hrsp.Header { + opts.ResponseMetadata.Set(k, strings.Join(v, ",")) + } + } + select { case <-ctx.Done(): err = ctx.Err() @@ -275,7 +283,7 @@ func (h *httpClient) parseRsp(ctx context.Context, hrsp *http.Response, rsp inte cf, cerr := h.newCodec(ct) if cerr != nil { if h.opts.Logger.V(logger.DebugLevel) { - h.opts.Logger.Debugf(ctx, "response with %v unknown content-type %s", hrsp.Header, ct, buf) + h.opts.Logger.Debugf(ctx, "response with %v unknown content-type %s %s", hrsp.Header, ct, buf) } return errors.InternalServerError("go.micro.client", cerr.Error()) } -- 2.49.1 From 8de525a8f8be2af77c64f5b4079d51ba4f03c682 Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Sat, 12 Aug 2023 13:17:47 +0300 Subject: [PATCH 03/10] update for latest micro changes Signed-off-by: Vasiliy Tolstov --- go.mod | 2 +- go.sum | 2 ++ http.go | 35 ++++++++++++++------------------ options.go | 58 +++++++++++++++++++++++++++--------------------------- request.go | 3 ++- 5 files changed, 49 insertions(+), 51 deletions(-) diff --git a/go.mod b/go.mod index 3393dc1..62bc45c 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,4 @@ module go.unistack.org/micro-client-http/v4 go 1.19 -require go.unistack.org/micro/v4 v4.0.1 +require go.unistack.org/micro/v4 v4.0.6 diff --git a/go.sum b/go.sum index ff93cdc..979a288 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,4 @@ go.unistack.org/micro/v4 v4.0.1 h1:xo1IxbVfgh8i0eY0VeYa3cbb13u5n/Mxnp3FOgWD4Jo= go.unistack.org/micro/v4 v4.0.1/go.mod h1:p/J5UcSJjfHsWGT31uKoghQ5rUQZzQJBAFy+Z4+ZVMs= +go.unistack.org/micro/v4 v4.0.6 h1:YFWvTh3VwyOd6NHYTQcf47n2TF5+p/EhpnbuBQX3qhk= +go.unistack.org/micro/v4 v4.0.6/go.mod h1:bVEYTlPi0EsdgZZt311bIroDg9ict7ky3C87dSCCAGk= diff --git a/http.go b/http.go index 7cfa677..b5f2ebf 100644 --- a/http.go +++ b/http.go @@ -19,6 +19,7 @@ import ( "go.unistack.org/micro/v4/errors" "go.unistack.org/micro/v4/logger" "go.unistack.org/micro/v4/metadata" + "go.unistack.org/micro/v4/options" "go.unistack.org/micro/v4/selector" rutil "go.unistack.org/micro/v4/util/reflect" ) @@ -303,7 +304,7 @@ func (h *httpClient) newCodec(ct string) (codec.Codec, error) { return nil, codec.ErrUnknownContentType } -func (h *httpClient) Init(opts ...client.Option) error { +func (h *httpClient) Init(opts ...options.Option) error { if len(opts) == 0 && h.init { return nil } @@ -323,9 +324,6 @@ func (h *httpClient) Init(opts ...client.Option) error { if err := h.opts.Meter.Init(); err != nil { return err } - if err := h.opts.Transport.Init(); err != nil { - return err - } return nil } @@ -334,11 +332,11 @@ func (h *httpClient) Options() client.Options { return h.opts } -func (h *httpClient) NewRequest(service, method string, req interface{}, opts ...client.RequestOption) client.Request { +func (h *httpClient) NewRequest(service, method string, req interface{}, opts ...options.Option) client.Request { return newHTTPRequest(service, method, req, h.opts.ContentType, opts...) } -func (h *httpClient) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error { +func (h *httpClient) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...options.Option) error { // make a copy of call opts callOpts := h.opts.CallOptions for _, opt := range opts { @@ -355,8 +353,9 @@ func (h *httpClient) Call(ctx context.Context, req client.Request, rsp interface } else { // got a deadline so no need to setup context // but we need to set the timeout we pass along - opt := client.WithRequestTimeout(time.Until(d)) - opt(&callOpts) + if err := options.Set(&callOpts, time.Until(d), ".RequestTimeout"); err != nil { + return errors.New("go.micro.client", fmt.Sprintf("%v", err.Error()), 400) + } } // should we noop right here? @@ -370,9 +369,9 @@ func (h *httpClient) Call(ctx context.Context, req client.Request, rsp interface hcall := h.call // wrap the call in reverse - for i := len(callOpts.CallWrappers); i > 0; i-- { - hcall = callOpts.CallWrappers[i-1](hcall) - } + //for i := len(callOpts.CallWrappers); i > 0; i-- { + // hcall = callOpts.CallWrappers[i-1](hcall) + //} // use the router passed as a call option, or fallback to the rpc clients router if callOpts.Router == nil { @@ -470,7 +469,7 @@ func (h *httpClient) Call(ctx context.Context, req client.Request, rsp interface return gerr } -func (h *httpClient) Stream(ctx context.Context, req client.Request, opts ...client.CallOption) (client.Stream, error) { +func (h *httpClient) Stream(ctx context.Context, req client.Request, opts ...options.Option) (client.Stream, error) { var err error // make a copy of call opts @@ -489,8 +488,9 @@ func (h *httpClient) Stream(ctx context.Context, req client.Request, opts ...cli } else { // got a deadline so no need to setup context // but we need to set the timeout we pass along - o := client.WithStreamTimeout(time.Until(d)) - o(&callOpts) + if err = options.Set(&callOpts, time.Until(d), ".StreamTimeout"); err != nil { + return nil, errors.New("go.micro.client", fmt.Sprintf("%v", err.Error()), 400) + } } // should we noop right here? @@ -618,7 +618,7 @@ func (h *httpClient) Name() string { return h.opts.Name } -func NewClient(opts ...client.Option) client.Client { +func NewClient(opts ...options.Option) client.Client { options := client.NewOptions(opts...) if len(options.ContentType) == 0 { @@ -668,10 +668,5 @@ func NewClient(opts ...client.Option) client.Client { } c := client.Client(rc) - // wrap in reverse - for i := len(options.Wrappers); i > 0; i-- { - c = options.Wrappers[i-1](c) - } - return c } diff --git a/options.go b/options.go index 3590a05..03066e8 100644 --- a/options.go +++ b/options.go @@ -4,8 +4,8 @@ import ( "net" "net/http" - "go.unistack.org/micro/v4/client" "go.unistack.org/micro/v4/metadata" + "go.unistack.org/micro/v4/options" ) var ( @@ -29,98 +29,98 @@ var ( type poolMaxStreams struct{} // PoolMaxStreams maximum streams on a connectioin -func PoolMaxStreams(n int) client.Option { - return client.SetOption(poolMaxStreams{}, n) +func PoolMaxStreams(n int) options.Option { + return options.ContextOption(poolMaxStreams{}, n) } type poolMaxIdle struct{} // PoolMaxIdle maximum idle conns of a pool -func PoolMaxIdle(d int) client.Option { - return client.SetOption(poolMaxIdle{}, d) +func PoolMaxIdle(d int) options.Option { + return options.ContextOption(poolMaxIdle{}, d) } type maxRecvMsgSizeKey struct{} // MaxRecvMsgSize set the maximum size of message that client can receive. -func MaxRecvMsgSize(s int) client.Option { - return client.SetOption(maxRecvMsgSizeKey{}, s) +func MaxRecvMsgSize(s int) options.Option { + return options.ContextOption(maxRecvMsgSizeKey{}, s) } type maxSendMsgSizeKey struct{} // MaxSendMsgSize set the maximum size of message that client can send. -func MaxSendMsgSize(s int) client.Option { - return client.SetOption(maxSendMsgSizeKey{}, s) +func MaxSendMsgSize(s int) options.Option { + return options.ContextOption(maxSendMsgSizeKey{}, s) } type httpClientKey struct{} // nolint: golint // HTTPClient pass http.Client option to client Call -func HTTPClient(c *http.Client) client.Option { - return client.SetOption(httpClientKey{}, c) +func HTTPClient(c *http.Client) options.Option { + return options.ContextOption(httpClientKey{}, c) } type httpDialerKey struct{} // nolint: golint // HTTPDialer pass net.Dialer option to client -func HTTPDialer(d *net.Dialer) client.Option { - return client.SetOption(httpDialerKey{}, d) +func HTTPDialer(d *net.Dialer) options.Option { + return options.ContextOption(httpDialerKey{}, d) } type methodKey struct{} // Method pass method option to client Call -func Method(m string) client.CallOption { - return client.SetCallOption(methodKey{}, m) +func Method(m string) options.Option { + return options.ContextOption(methodKey{}, m) } type pathKey struct{} // Path spcecifies path option to client Call -func Path(p string) client.CallOption { - return client.SetCallOption(pathKey{}, p) +func Path(p string) options.Option { + return options.ContextOption(pathKey{}, p) } type bodyKey struct{} // Body specifies body option to client Call -func Body(b string) client.CallOption { - return client.SetCallOption(bodyKey{}, b) +func Body(b string) options.Option { + return options.ContextOption(bodyKey{}, b) } type errorMapKey struct{} -func ErrorMap(m map[string]interface{}) client.CallOption { - return client.SetCallOption(errorMapKey{}, m) +func ErrorMap(m map[string]interface{}) options.Option { + return options.ContextOption(errorMapKey{}, m) } type structTagsKey struct{} // StructTags pass tags slice option to client Call -func StructTags(tags []string) client.CallOption { - return client.SetCallOption(structTagsKey{}, tags) +func StructTags(tags []string) options.Option { + return options.ContextOption(structTagsKey{}, tags) } type metadataKey struct{} // Metadata pass metadata to client Call -func Metadata(md metadata.Metadata) client.CallOption { - return client.SetCallOption(metadataKey{}, md) +func Metadata(md metadata.Metadata) options.Option { + return options.ContextOption(metadataKey{}, md) } type cookieKey struct{} // Cookie pass cookie to client Call -func Cookie(cookies ...string) client.CallOption { - return client.SetCallOption(cookieKey{}, cookies) +func Cookie(cookies ...string) options.Option { + return options.ContextOption(cookieKey{}, cookies) } type headerKey struct{} // Header pass cookie to client Call -func Header(headers ...string) client.CallOption { - return client.SetCallOption(headerKey{}, headers) +func Header(headers ...string) options.Option { + return options.ContextOption(headerKey{}, headers) } diff --git a/request.go b/request.go index 0622422..47f3512 100644 --- a/request.go +++ b/request.go @@ -3,6 +3,7 @@ package http import ( "go.unistack.org/micro/v4/client" "go.unistack.org/micro/v4/codec" + "go.unistack.org/micro/v4/options" ) type httpRequest struct { @@ -13,7 +14,7 @@ type httpRequest struct { opts client.RequestOptions } -func newHTTPRequest(service, method string, request interface{}, contentType string, opts ...client.RequestOption) client.Request { +func newHTTPRequest(service, method string, request interface{}, contentType string, opts ...options.Option) client.Request { options := client.NewRequestOptions(opts...) if len(options.ContentType) == 0 { options.ContentType = contentType -- 2.49.1 From 7ea55fb4667c9dd2102a5496b31c9f8192d0a05d Mon Sep 17 00:00:00 2001 From: Vasiliy Tolstov Date: Mon, 25 Mar 2024 21:12:26 +0300 Subject: [PATCH 04/10] update for latest micro Signed-off-by: Vasiliy Tolstov --- go.mod | 2 +- go.sum | 2 ++ http.go | 8 ++++---- stream.go | 4 ++-- util.go | 6 +++--- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 62bc45c..65733a3 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,4 @@ module go.unistack.org/micro-client-http/v4 go 1.19 -require go.unistack.org/micro/v4 v4.0.6 +require go.unistack.org/micro/v4 v4.0.18 diff --git a/go.sum b/go.sum index 979a288..03a7fae 100644 --- a/go.sum +++ b/go.sum @@ -2,3 +2,5 @@ go.unistack.org/micro/v4 v4.0.1 h1:xo1IxbVfgh8i0eY0VeYa3cbb13u5n/Mxnp3FOgWD4Jo= go.unistack.org/micro/v4 v4.0.1/go.mod h1:p/J5UcSJjfHsWGT31uKoghQ5rUQZzQJBAFy+Z4+ZVMs= go.unistack.org/micro/v4 v4.0.6 h1:YFWvTh3VwyOd6NHYTQcf47n2TF5+p/EhpnbuBQX3qhk= go.unistack.org/micro/v4 v4.0.6/go.mod h1:bVEYTlPi0EsdgZZt311bIroDg9ict7ky3C87dSCCAGk= +go.unistack.org/micro/v4 v4.0.18 h1:b7WFwem8Nz1xBrRg5FeLnm9CE5gJseHyf9j0BhkiXW0= +go.unistack.org/micro/v4 v4.0.18/go.mod h1:5+da5r835gP0WnNZbYUJDCvWpJ9Xc3IEGyp62e8o8R4= diff --git a/http.go b/http.go index b5f2ebf..bb83d6c 100644 --- a/http.go +++ b/http.go @@ -139,7 +139,7 @@ func newRequest(ctx context.Context, log logger.Logger, addr string, req client. if opts.Context != nil { if md, ok := opts.Context.Value(metadataKey{}).(metadata.Metadata); ok { for k, v := range md { - header.Set(k, v) + header[k] = v } } } @@ -148,13 +148,13 @@ func newRequest(ctx context.Context, log logger.Logger, addr string, req client. } if opts.RequestMetadata != nil { for k, v := range opts.RequestMetadata { - header.Set(k, v) + header[k] = v } } if md, ok := metadata.FromOutgoingContext(ctx); ok { for k, v := range md { - header.Set(k, v) + header[k] = v } } @@ -216,7 +216,7 @@ func newRequest(ctx context.Context, log logger.Logger, addr string, req client. } if log.V(logger.DebugLevel) { - log.Debugf(ctx, "request %s to %s with headers %v body %s", method, u.String(), hreq.Header, b) + log.Debug(ctx, fmt.Sprintf("request %s to %s with headers %v body %s", method, u.String(), hreq.Header, b)) } return hreq, nil diff --git a/stream.go b/stream.go index fbd0d8c..2a69b89 100644 --- a/stream.go +++ b/stream.go @@ -134,14 +134,14 @@ func (h *httpStream) parseRsp(ctx context.Context, log logger.Logger, hrsp *http buf, err = io.ReadAll(hrsp.Body) if err != nil { if log.V(logger.ErrorLevel) { - log.Errorf(ctx, "failed to read body: %v", err) + log.Error(ctx, "failed to read body", err) } return errors.InternalServerError("go.micro.client", string(buf)) } } if log.V(logger.DebugLevel) { - log.Debugf(ctx, "response %s with %v", buf, hrsp.Header) + log.Debug(ctx, fmt.Sprintf("response %s with %v", buf, hrsp.Header)) } if hrsp.StatusCode < 400 { diff --git a/util.go b/util.go index 0a59021..4d4edd7 100644 --- a/util.go +++ b/util.go @@ -274,7 +274,7 @@ func (h *httpClient) parseRsp(ctx context.Context, hrsp *http.Response, rsp inte buf, err = io.ReadAll(hrsp.Body) if err != nil { if h.opts.Logger.V(logger.ErrorLevel) { - h.opts.Logger.Errorf(ctx, "failed to read body: %v", err) + h.opts.Logger.Error(ctx, "failed to read body", err) } return errors.InternalServerError("go.micro.client", string(buf)) } @@ -283,13 +283,13 @@ func (h *httpClient) parseRsp(ctx context.Context, hrsp *http.Response, rsp inte cf, cerr := h.newCodec(ct) if cerr != nil { if h.opts.Logger.V(logger.DebugLevel) { - h.opts.Logger.Debugf(ctx, "response with %v unknown content-type %s %s", hrsp.Header, ct, buf) + h.opts.Logger.Debug(ctx, fmt.Sprintf("response with %v unknown content-type %s %s", hrsp.Header, ct, buf)) } return errors.InternalServerError("go.micro.client", cerr.Error()) } if h.opts.Logger.V(logger.DebugLevel) { - h.opts.Logger.Debugf(ctx, "response %s with %v", buf, hrsp.Header) + h.opts.Logger.Debug(ctx, fmt.Sprintf("response %s with %v", buf, hrsp.Header)) } // succeseful response -- 2.49.1 From bc59fcb8861d05cece8c57a80902844a1860bcf9 Mon Sep 17 00:00:00 2001 From: Nurzhan Ilyassov <“nilyassov@one.kz”> Date: Tue, 26 Mar 2024 11:09:38 +0500 Subject: [PATCH 05/10] fix nil nmsg in case of empty request body --- util.go | 10 +++++++++- util_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/util.go b/util.go index 4d4edd7..b0496c5 100644 --- a/util.go +++ b/util.go @@ -217,13 +217,21 @@ func newPathRequest(path string, method string, body string, msg interface{}, ta _, _ = b.WriteString(values.Encode()) } - if rutil.IsZero(nmsg) { + if rutil.IsZero(nmsg) && !isEmptyStruct(nmsg) { return b.String(), nil, nil } return b.String(), nmsg, nil } +func isEmptyStruct(v interface{}) bool { + val := reflect.ValueOf(v) + if val.Kind() == reflect.Ptr { + val = val.Elem() + } + return val.Kind() == reflect.Struct && val.NumField() == 0 +} + func newTemplate(path string) ([]string, error) { if len(path) == 0 || path[0] != '/' { return nil, fmt.Errorf("path must starts with /") diff --git a/util_test.go b/util_test.go index 5d8b799..d1fb061 100644 --- a/util_test.go +++ b/util_test.go @@ -59,6 +59,30 @@ func TestNewPathRequest(t *testing.T) { } } +func TestNewPathRequestWithEmptyBody(t *testing.T) { + val := struct{}{} + + for _, m := range []string{"POST", "PUT", "PATCH", "GET", "DELETE"} { + body := `{"type": "invalid"}` + path, nmsg, err := newPathRequest("/v1/test", m, body, val, []string{"protobuf", "json"}, nil) + if err != nil { + t.Fatal(err) + } + if nmsg == nil { + t.Fatalf("invalid path: nil nmsg") + } + + u, err := url.Parse(path) + if err != nil { + t.Fatal(err) + } + vals := u.Query() + if len(vals) != 0 { + t.Fatalf("invalid path: %v nmsg: %v", path, nmsg) + } + } +} + func TestNewPathVarRequest(t *testing.T) { type Message struct { Name string `json:"name"` -- 2.49.1 From 916d248147d69c45eb3e56fdea45bac732713bf3 Mon Sep 17 00:00:00 2001 From: Nurzhan Ilyassov <“nilyassov@one.kz”> Date: Tue, 26 Mar 2024 12:44:45 +0500 Subject: [PATCH 06/10] update tests --- util_test.go | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/util_test.go b/util_test.go index d1fb061..1c0b713 100644 --- a/util_test.go +++ b/util_test.go @@ -61,24 +61,32 @@ func TestNewPathRequest(t *testing.T) { func TestNewPathRequestWithEmptyBody(t *testing.T) { val := struct{}{} + cases := []string{ + "", + "*", + "{}", + "nil", + `{"type": "invalid"}`, + } - for _, m := range []string{"POST", "PUT", "PATCH", "GET", "DELETE"} { - body := `{"type": "invalid"}` - path, nmsg, err := newPathRequest("/v1/test", m, body, val, []string{"protobuf", "json"}, nil) - if err != nil { - t.Fatal(err) - } - if nmsg == nil { - t.Fatalf("invalid path: nil nmsg") - } + for _, body := range cases { + for _, m := range []string{"POST", "PUT", "PATCH", "GET", "DELETE"} { + path, nmsg, err := newPathRequest("/v1/test", m, body, val, []string{"protobuf", "json"}, nil) + if err != nil { + t.Fatal(err) + } + if nmsg == nil { + t.Fatalf("invalid path: nil nmsg") + } - u, err := url.Parse(path) - if err != nil { - t.Fatal(err) - } - vals := u.Query() - if len(vals) != 0 { - t.Fatalf("invalid path: %v nmsg: %v", path, nmsg) + u, err := url.Parse(path) + if err != nil { + t.Fatal(err) + } + vals := u.Query() + if len(vals) != 0 { + t.Fatalf("invalid path: %v nmsg: %v", path, nmsg) + } } } } -- 2.49.1 From b224e80b8003b82a1d143375372d42832b621120 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=A2=D0=BE=D0=BB=D1=81=D1=82=D0=B8=D1=85=D0=B8=D0=BD?= Date: Wed, 11 Dec 2024 00:34:13 +0300 Subject: [PATCH 07/10] Update workflows (#120) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Aleksandr Tolstikhin Reviewed-on: https://git.unistack.org/unistack-org/micro-client-http/pulls/120 Co-authored-by: Александр Толстихин Co-committed-by: Александр Толстихин --- .../ISSUE_TEMPLATE/bug_report.md | 0 .../feature-request---enhancement.md | 0 .../ISSUE_TEMPLATE/question.md | 0 {.github => .gitea}/PULL_REQUEST_TEMPLATE.md | 0 .gitea/workflows/job_lint.yml | 29 +++++++ .gitea/workflows/job_test.yml | 34 ++++++++ .gitea/workflows/job_tests.yml | 53 +++++++++++++ .github/dependabot.yml | 19 ----- .github/workflows/autoapprove.yml | 20 ----- .github/workflows/automerge.yml | 21 ----- .github/workflows/build.yml | 47 ----------- .github/workflows/codeql-analysis.yml | 78 ------------------- .github/workflows/dependabot-automerge.yml | 27 ------- .github/workflows/pr.yml | 47 ----------- .golangci.yml | 41 +--------- 15 files changed, 117 insertions(+), 299 deletions(-) rename {.github => .gitea}/ISSUE_TEMPLATE/bug_report.md (100%) rename {.github => .gitea}/ISSUE_TEMPLATE/feature-request---enhancement.md (100%) rename {.github => .gitea}/ISSUE_TEMPLATE/question.md (100%) rename {.github => .gitea}/PULL_REQUEST_TEMPLATE.md (100%) create mode 100644 .gitea/workflows/job_lint.yml create mode 100644 .gitea/workflows/job_test.yml create mode 100644 .gitea/workflows/job_tests.yml delete mode 100644 .github/dependabot.yml delete mode 100644 .github/workflows/autoapprove.yml delete mode 100644 .github/workflows/automerge.yml delete mode 100644 .github/workflows/build.yml delete mode 100644 .github/workflows/codeql-analysis.yml delete mode 100644 .github/workflows/dependabot-automerge.yml delete mode 100644 .github/workflows/pr.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.gitea/ISSUE_TEMPLATE/bug_report.md similarity index 100% rename from .github/ISSUE_TEMPLATE/bug_report.md rename to .gitea/ISSUE_TEMPLATE/bug_report.md diff --git a/.github/ISSUE_TEMPLATE/feature-request---enhancement.md b/.gitea/ISSUE_TEMPLATE/feature-request---enhancement.md similarity index 100% rename from .github/ISSUE_TEMPLATE/feature-request---enhancement.md rename to .gitea/ISSUE_TEMPLATE/feature-request---enhancement.md diff --git a/.github/ISSUE_TEMPLATE/question.md b/.gitea/ISSUE_TEMPLATE/question.md similarity index 100% rename from .github/ISSUE_TEMPLATE/question.md rename to .gitea/ISSUE_TEMPLATE/question.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.gitea/PULL_REQUEST_TEMPLATE.md similarity index 100% rename from .github/PULL_REQUEST_TEMPLATE.md rename to .gitea/PULL_REQUEST_TEMPLATE.md diff --git a/.gitea/workflows/job_lint.yml b/.gitea/workflows/job_lint.yml new file mode 100644 index 0000000..d97e747 --- /dev/null +++ b/.gitea/workflows/job_lint.yml @@ -0,0 +1,29 @@ +name: lint + +on: + pull_request: + types: [opened, reopened, synchronize] + branches: + - master + - v3 + - v4 + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: checkout code + uses: actions/checkout@v4 + with: + filter: 'blob:none' + - name: setup go + uses: actions/setup-go@v5 + with: + cache-dependency-path: "**/*.sum" + go-version: 'stable' + - name: setup deps + run: go get -v ./... + - name: run lint + uses: https://github.com/golangci/golangci-lint-action@v6 + with: + version: 'latest' diff --git a/.gitea/workflows/job_test.yml b/.gitea/workflows/job_test.yml new file mode 100644 index 0000000..f68cbca --- /dev/null +++ b/.gitea/workflows/job_test.yml @@ -0,0 +1,34 @@ +name: test + +on: + pull_request: + types: [opened, reopened, synchronize] + branches: + - master + - v3 + - v4 + push: + branches: + - master + - v3 + - v4 + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: checkout code + uses: actions/checkout@v4 + with: + filter: 'blob:none' + - name: setup go + uses: actions/setup-go@v5 + with: + cache-dependency-path: "**/*.sum" + go-version: 'stable' + - name: setup deps + run: go get -v ./... + - name: run test + env: + INTEGRATION_TESTS: yes + run: go test -mod readonly -v ./... diff --git a/.gitea/workflows/job_tests.yml b/.gitea/workflows/job_tests.yml new file mode 100644 index 0000000..e911576 --- /dev/null +++ b/.gitea/workflows/job_tests.yml @@ -0,0 +1,53 @@ +name: test + +on: + pull_request: + types: [opened, reopened, synchronize] + branches: + - master + - v3 + - v4 + push: + branches: + - master + - v3 + - v4 + +jobs: + test: + runs-on: ubuntu-latest + steps: + - name: checkout code + uses: actions/checkout@v4 + with: + filter: 'blob:none' + - name: checkout tests + uses: actions/checkout@v4 + with: + ref: master + filter: 'blob:none' + repository: unistack-org/micro-tests + path: micro-tests + - name: setup go + uses: actions/setup-go@v5 + with: + cache-dependency-path: "**/*.sum" + go-version: 'stable' + - name: setup go work + env: + GOWORK: /workspace/${{ github.repository_owner }}/go.work + run: | + go work init + go work use . + go work use micro-tests + - name: setup deps + env: + GOWORK: /workspace/${{ github.repository_owner }}/go.work + run: go get -v ./... + - name: run tests + env: + INTEGRATION_TESTS: yes + GOWORK: /workspace/${{ github.repository_owner }}/go.work + run: | + cd micro-tests + go test -mod readonly -v ./... || true diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index d5f7eae..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,19 +0,0 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - -version: 2 -updates: - - # Maintain dependencies for GitHub Actions - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "daily" - - # Maintain dependencies for Golang - - package-ecosystem: "gomod" - directory: "/" - schedule: - interval: "daily" diff --git a/.github/workflows/autoapprove.yml b/.github/workflows/autoapprove.yml deleted file mode 100644 index 5bf5d9f..0000000 --- a/.github/workflows/autoapprove.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: "autoapprove" - -on: - pull_request_target: - types: [assigned, opened, synchronize, reopened] - -permissions: - pull-requests: write - contents: write - -jobs: - autoapprove: - runs-on: ubuntu-latest - steps: - - name: approve - uses: hmarr/auto-approve-action@v3 - if: github.actor == 'vtolstov' || github.actor == 'dependabot[bot]' - id: approve - with: - github-token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml deleted file mode 100644 index 5ff3f69..0000000 --- a/.github/workflows/automerge.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: "automerge" - -on: - pull_request_target: - types: [assigned, opened, synchronize, reopened] - -permissions: - pull-requests: write - contents: write - -jobs: - automerge: - runs-on: ubuntu-latest - if: github.actor == 'vtolstov' - steps: - - name: merge - id: merge - run: gh pr merge --auto --merge "$PR_URL" - env: - PR_URL: ${{github.event.pull_request.html_url}} - GITHUB_TOKEN: ${{secrets.TOKEN}} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 9603352..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: build -on: - push: - branches: - - master - - v3 -jobs: - test: - name: test - runs-on: ubuntu-latest - steps: - - name: setup - uses: actions/setup-go@v3 - with: - go-version: 1.17 - - name: checkout - uses: actions/checkout@v3 - - name: cache - uses: actions/cache@v3 - with: - path: ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: ${{ runner.os }}-go- - - name: deps - run: go get -v -t -d ./... - - name: test - env: - INTEGRATION_TESTS: yes - run: go test -mod readonly -v ./... - lint: - name: lint - runs-on: ubuntu-latest - steps: - - name: checkout - uses: actions/checkout@v3 - - name: lint - uses: golangci/golangci-lint-action@v3.4.0 - continue-on-error: true - with: - # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. - version: v1.30 - # Optional: working directory, useful for monorepos - # working-directory: somedir - # Optional: golangci-lint command line arguments. - # args: --issues-exit-code=0 - # Optional: show only new issues if it's a pull request. The default value is `false`. - # only-new-issues: true diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 2f6c6de..0000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,78 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "codeql" - -on: - workflow_run: - workflows: ["prbuild"] - types: - - completed - push: - branches: [ master, v3 ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ master, v3 ] - schedule: - - cron: '34 1 * * 0' - -jobs: - analyze: - name: analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'go' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] - # Learn more: - # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed - - steps: - - name: checkout - uses: actions/checkout@v3 - - name: setup - uses: actions/setup-go@v3 - with: - go-version: 1.17 - # Initializes the CodeQL tools for scanning. - - name: init - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: autobuild - uses: github/codeql-action/autobuild@v2 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: analyze - uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/dependabot-automerge.yml b/.github/workflows/dependabot-automerge.yml deleted file mode 100644 index f41c1c0..0000000 --- a/.github/workflows/dependabot-automerge.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: "dependabot-automerge" - -on: - pull_request_target: - types: [assigned, opened, synchronize, reopened] - -permissions: - pull-requests: write - contents: write - -jobs: - automerge: - runs-on: ubuntu-latest - if: github.actor == 'dependabot[bot]' - steps: - - name: metadata - id: metadata - uses: dependabot/fetch-metadata@v1.3.6 - with: - github-token: "${{ secrets.TOKEN }}" - - name: merge - id: merge - if: ${{contains(steps.metadata.outputs.dependency-names, 'go.unistack.org')}} - run: gh pr merge --auto --merge "$PR_URL" - env: - PR_URL: ${{github.event.pull_request.html_url}} - GITHUB_TOKEN: ${{secrets.TOKEN}} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml deleted file mode 100644 index f313ebe..0000000 --- a/.github/workflows/pr.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: prbuild -on: - pull_request: - branches: - - master - - v3 -jobs: - test: - name: test - runs-on: ubuntu-latest - steps: - - name: setup - uses: actions/setup-go@v3 - with: - go-version: 1.17 - - name: checkout - uses: actions/checkout@v3 - - name: cache - uses: actions/cache@v3 - with: - path: ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: ${{ runner.os }}-go- - - name: deps - run: go get -v -t -d ./... - - name: test - env: - INTEGRATION_TESTS: yes - run: go test -mod readonly -v ./... - lint: - name: lint - runs-on: ubuntu-latest - steps: - - name: checkout - uses: actions/checkout@v3 - - name: lint - uses: golangci/golangci-lint-action@v3.4.0 - continue-on-error: true - with: - # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. - version: v1.30 - # Optional: working directory, useful for monorepos - # working-directory: somedir - # Optional: golangci-lint command line arguments. - # args: --issues-exit-code=0 - # Optional: show only new issues if it's a pull request. The default value is `false`. - # only-new-issues: true diff --git a/.golangci.yml b/.golangci.yml index 6ff842d..2bb1c30 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,44 +1,5 @@ run: - concurrency: 4 + concurrency: 8 deadline: 5m issues-exit-code: 1 tests: true - -linters-settings: - govet: - check-shadowing: true - enable: - - fieldalignment - -linters: - enable: - - govet - - deadcode - - errcheck - - govet - - ineffassign - - staticcheck - - structcheck - - typecheck - - unused - - varcheck - - bodyclose - - gci - - goconst - - gocritic - - gosimple - - gofmt - - gofumpt - - goimports - - golint - - gosec - - makezero - - misspell - - nakedret - - nestif - - nilerr - - noctx - - prealloc - - unconvert - - unparam - disable-all: false -- 2.49.1 From c0312308886bf64e95463fc48ea61253bc3cba47 Mon Sep 17 00:00:00 2001 From: Evstigneev Denis Date: Thu, 20 Feb 2025 19:11:27 +0300 Subject: [PATCH 08/10] fixed v4 chages --- .gitignore | 39 +++++++++++++++++++++++++++++++++++++++ go.mod | 19 +++++++++++++++++-- go.sum | 49 +++++++++++++++++++++++++++++++++++++++++++------ http.go | 19 ++++++++++--------- options.go | 8 ++++++-- request.go | 3 +-- 6 files changed, 116 insertions(+), 21 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c2fff38 --- /dev/null +++ b/.gitignore @@ -0,0 +1,39 @@ +# Develop tools +/.vscode/ +/.idea/ +.idea +.vscode + +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Folders +_obj +_test +_build +.DS_Store + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# vim temp files +*~ +*.swp +*.swo diff --git a/go.mod b/go.mod index 65733a3..4c8ccb9 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,20 @@ module go.unistack.org/micro-client-http/v4 -go 1.19 +go 1.22.0 -require go.unistack.org/micro/v4 v4.0.18 +toolchain go1.23.3 + +require go.unistack.org/micro/v4 v4.1.1 + +require ( + github.com/ash3in/uuidv8 v1.2.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/matoous/go-nanoid v1.5.1 // indirect + github.com/spf13/cast v1.7.1 // indirect + go.unistack.org/micro-proto/v4 v4.1.0 // indirect + golang.org/x/sys v0.29.0 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241216192217-9240e9c98484 // indirect + google.golang.org/grpc v1.69.4 // indirect + google.golang.org/protobuf v1.36.3 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum index 03a7fae..f7adb81 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,43 @@ -go.unistack.org/micro/v4 v4.0.1 h1:xo1IxbVfgh8i0eY0VeYa3cbb13u5n/Mxnp3FOgWD4Jo= -go.unistack.org/micro/v4 v4.0.1/go.mod h1:p/J5UcSJjfHsWGT31uKoghQ5rUQZzQJBAFy+Z4+ZVMs= -go.unistack.org/micro/v4 v4.0.6 h1:YFWvTh3VwyOd6NHYTQcf47n2TF5+p/EhpnbuBQX3qhk= -go.unistack.org/micro/v4 v4.0.6/go.mod h1:bVEYTlPi0EsdgZZt311bIroDg9ict7ky3C87dSCCAGk= -go.unistack.org/micro/v4 v4.0.18 h1:b7WFwem8Nz1xBrRg5FeLnm9CE5gJseHyf9j0BhkiXW0= -go.unistack.org/micro/v4 v4.0.18/go.mod h1:5+da5r835gP0WnNZbYUJDCvWpJ9Xc3IEGyp62e8o8R4= +github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= +github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= +github.com/ash3in/uuidv8 v1.2.0 h1:2oogGdtCPwaVtyvPPGin4TfZLtOGE5F+W++E880G6SI= +github.com/ash3in/uuidv8 v1.2.0/go.mod h1:BnU0wJBxnzdEKmVg4xckBkD+VZuecTFTUP3M0dWgyY4= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/matoous/go-nanoid v1.5.1 h1:aCjdvTyO9LLnTIi0fgdXhOPPvOHjpXN6Ik9DaNjIct4= +github.com/matoous/go-nanoid v1.5.1/go.mod h1:zyD2a71IubI24efhpvkJz+ZwfwagzgSO6UNiFsZKN7U= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= +github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +go.unistack.org/micro-proto/v4 v4.1.0 h1:qPwL2n/oqh9RE3RTTDgt28XK3QzV597VugQPaw9lKUk= +go.unistack.org/micro-proto/v4 v4.1.0/go.mod h1:ArmK7o+uFvxSY3dbJhKBBX4Pm1rhWdLEFf3LxBrMtec= +go.unistack.org/micro/v4 v4.1.1 h1:Cx2Uo5LN3J3lIxLv2jNYSqoVQbGShwMQgr4cffjqqVI= +go.unistack.org/micro/v4 v4.1.1/go.mod h1:lr3oYED8Ay1vjK68QqRw30QOtdk/ffpZqMFDasOUhKw= +golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= +golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241216192217-9240e9c98484 h1:Z7FRVJPSMaHQxD0uXU8WdgFh8PseLM8Q8NzhnpMrBhQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241216192217-9240e9c98484/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA= +google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A= +google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= +google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU= +google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/http.go b/http.go index bb83d6c..e909b75 100644 --- a/http.go +++ b/http.go @@ -304,7 +304,7 @@ func (h *httpClient) newCodec(ct string) (codec.Codec, error) { return nil, codec.ErrUnknownContentType } -func (h *httpClient) Init(opts ...options.Option) error { +func (h *httpClient) Init(opts ...client.Option) error { if len(opts) == 0 && h.init { return nil } @@ -332,11 +332,11 @@ func (h *httpClient) Options() client.Options { return h.opts } -func (h *httpClient) NewRequest(service, method string, req interface{}, opts ...options.Option) client.Request { +func (h *httpClient) NewRequest(service, method string, req interface{}, opts ...client.RequestOption) client.Request { return newHTTPRequest(service, method, req, h.opts.ContentType, opts...) } -func (h *httpClient) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...options.Option) error { +func (h *httpClient) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error { // make a copy of call opts callOpts := h.opts.CallOptions for _, opt := range opts { @@ -353,7 +353,8 @@ func (h *httpClient) Call(ctx context.Context, req client.Request, rsp interface } else { // got a deadline so no need to setup context // but we need to set the timeout we pass along - if err := options.Set(&callOpts, time.Until(d), ".RequestTimeout"); err != nil { + o := options.NewOption("RequestTimeout")(time.Until(d)) + if err := options.Apply(&callOpts, o); err != nil { return errors.New("go.micro.client", fmt.Sprintf("%v", err.Error()), 400) } } @@ -469,7 +470,7 @@ func (h *httpClient) Call(ctx context.Context, req client.Request, rsp interface return gerr } -func (h *httpClient) Stream(ctx context.Context, req client.Request, opts ...options.Option) (client.Stream, error) { +func (h *httpClient) Stream(ctx context.Context, req client.Request, opts ...client.CallOption) (client.Stream, error) { var err error // make a copy of call opts @@ -488,7 +489,8 @@ func (h *httpClient) Stream(ctx context.Context, req client.Request, opts ...opt } else { // got a deadline so no need to setup context // but we need to set the timeout we pass along - if err = options.Set(&callOpts, time.Until(d), ".StreamTimeout"); err != nil { + o := options.NewOption("StreamTimeout")(time.Until(d)) + if err := options.Apply(&callOpts, o); err != nil { return nil, errors.New("go.micro.client", fmt.Sprintf("%v", err.Error()), 400) } } @@ -618,7 +620,7 @@ func (h *httpClient) Name() string { return h.opts.Name } -func NewClient(opts ...options.Option) client.Client { +func NewClient(opts ...client.Option) client.Client { options := client.NewOptions(opts...) if len(options.ContentType) == 0 { @@ -666,7 +668,6 @@ func NewClient(opts ...options.Option) client.Client { } rc.httpcli = &http.Client{Transport: tr} } - c := client.Client(rc) - return c + return rc } diff --git a/options.go b/options.go index 03066e8..d860643 100644 --- a/options.go +++ b/options.go @@ -1,6 +1,7 @@ package http import ( + "go.unistack.org/micro/v4/client" "net" "net/http" @@ -30,6 +31,9 @@ type poolMaxStreams struct{} // PoolMaxStreams maximum streams on a connectioin func PoolMaxStreams(n int) options.Option { + return func(i interface{}) error { + + } return options.ContextOption(poolMaxStreams{}, n) } @@ -73,8 +77,8 @@ func HTTPDialer(d *net.Dialer) options.Option { type methodKey struct{} // Method pass method option to client Call -func Method(m string) options.Option { - return options.ContextOption(methodKey{}, m) +func Method(m string) client.CallOptions { + return options.Context(methodKey{}, m) } type pathKey struct{} diff --git a/request.go b/request.go index 47f3512..0622422 100644 --- a/request.go +++ b/request.go @@ -3,7 +3,6 @@ package http import ( "go.unistack.org/micro/v4/client" "go.unistack.org/micro/v4/codec" - "go.unistack.org/micro/v4/options" ) type httpRequest struct { @@ -14,7 +13,7 @@ type httpRequest struct { opts client.RequestOptions } -func newHTTPRequest(service, method string, request interface{}, contentType string, opts ...options.Option) client.Request { +func newHTTPRequest(service, method string, request interface{}, contentType string, opts ...client.RequestOption) client.Request { options := client.NewRequestOptions(opts...) if len(options.ContentType) == 0 { options.ContentType = contentType -- 2.49.1 From 334a10e26debb086533d655df6ec116df6c60be9 Mon Sep 17 00:00:00 2001 From: Evstigneev Denis Date: Fri, 21 Feb 2025 20:13:34 +0300 Subject: [PATCH 09/10] prepare options --- http.go | 4 ++-- options.go | 68 +++++++++++++++--------------------------------------- 2 files changed, 20 insertions(+), 52 deletions(-) diff --git a/http.go b/http.go index e909b75..42c9b45 100644 --- a/http.go +++ b/http.go @@ -6,7 +6,7 @@ import ( "bytes" "context" "fmt" - "io/ioutil" + "io" "net" "net/http" "net/url" @@ -199,7 +199,7 @@ func newRequest(ctx context.Context, log logger.Logger, addr string, req client. var hreq *http.Request if len(b) > 0 { - hreq, err = http.NewRequestWithContext(ctx, method, u.String(), ioutil.NopCloser(bytes.NewBuffer(b))) + hreq, err = http.NewRequestWithContext(ctx, method, u.String(), io.NopCloser(bytes.NewBuffer(b))) hreq.ContentLength = int64(len(b)) header.Set("Content-Length", fmt.Sprintf("%d", hreq.ContentLength)) } else { diff --git a/options.go b/options.go index d860643..20b220e 100644 --- a/options.go +++ b/options.go @@ -1,7 +1,6 @@ package http import ( - "go.unistack.org/micro/v4/client" "net" "net/http" @@ -27,104 +26,73 @@ var ( DefaultMaxSendMsgSize = 1024 * 1024 * 4 ) -type poolMaxStreams struct{} - // PoolMaxStreams maximum streams on a connectioin func PoolMaxStreams(n int) options.Option { - return func(i interface{}) error { - - } - return options.ContextOption(poolMaxStreams{}, n) + return options.NewOption("PoolMaxStreams")(n) } -type poolMaxIdle struct{} - // PoolMaxIdle maximum idle conns of a pool -func PoolMaxIdle(d int) options.Option { - return options.ContextOption(poolMaxIdle{}, d) +func PoolMaxIdle(n int) options.Option { + return options.NewOption("PoolMaxIdle")(n) } -type maxRecvMsgSizeKey struct{} - // MaxRecvMsgSize set the maximum size of message that client can receive. -func MaxRecvMsgSize(s int) options.Option { - return options.ContextOption(maxRecvMsgSizeKey{}, s) +func MaxRecvMsgSize(n int) options.Option { + return options.NewOption("MaxRecvMsgSize")(n) } -type maxSendMsgSizeKey struct{} - // MaxSendMsgSize set the maximum size of message that client can send. -func MaxSendMsgSize(s int) options.Option { - return options.ContextOption(maxSendMsgSizeKey{}, s) +func MaxSendMsgSize(n int) options.Option { + return options.NewOption("MaxSendMsgSize")(n) } -type httpClientKey struct{} - // nolint: golint // HTTPClient pass http.Client option to client Call func HTTPClient(c *http.Client) options.Option { - return options.ContextOption(httpClientKey{}, c) + return options.NewOption("HTTPClient")(c) } -type httpDialerKey struct{} - // nolint: golint // HTTPDialer pass net.Dialer option to client func HTTPDialer(d *net.Dialer) options.Option { - return options.ContextOption(httpDialerKey{}, d) + return options.NewOption("HTTPDialer")(d) } -type methodKey struct{} - // Method pass method option to client Call -func Method(m string) client.CallOptions { - return options.Context(methodKey{}, m) +func Method(m string) options.Option { + return options.NewOption("Method")(m) } -type pathKey struct{} - // Path spcecifies path option to client Call func Path(p string) options.Option { - return options.ContextOption(pathKey{}, p) + return options.NewOption("Path")(p) } -type bodyKey struct{} - // Body specifies body option to client Call func Body(b string) options.Option { - return options.ContextOption(bodyKey{}, b) + return options.NewOption("Body")(b) } -type errorMapKey struct{} - func ErrorMap(m map[string]interface{}) options.Option { - return options.ContextOption(errorMapKey{}, m) + return options.NewOption("ErrorMap")(m) } -type structTagsKey struct{} - // StructTags pass tags slice option to client Call func StructTags(tags []string) options.Option { - return options.ContextOption(structTagsKey{}, tags) + return options.NewOption("StructTags")(tags) } -type metadataKey struct{} - // Metadata pass metadata to client Call func Metadata(md metadata.Metadata) options.Option { - return options.ContextOption(metadataKey{}, md) + return options.NewOption("Metadata")(md) } -type cookieKey struct{} - // Cookie pass cookie to client Call func Cookie(cookies ...string) options.Option { - return options.ContextOption(cookieKey{}, cookies) + return options.NewOption("Cookie")(cookies) } -type headerKey struct{} - // Header pass cookie to client Call func Header(headers ...string) options.Option { - return options.ContextOption(headerKey{}, headers) + return options.NewOption("Header")(headers) } -- 2.49.1 From f351a9129d020153ecb62ecdd7b409fc720af3e4 Mon Sep 17 00:00:00 2001 From: Evstigneev Denis Date: Tue, 25 Feb 2025 13:03:57 +0300 Subject: [PATCH 10/10] revert and update options && fix linter --- go.mod | 4 +- go.sum | 4 +- http.go | 34 ++++++------ options.go | 157 +++++++++++++++++++++++++++++++++++++++++++---------- stream.go | 8 +-- util.go | 8 +-- 6 files changed, 156 insertions(+), 59 deletions(-) diff --git a/go.mod b/go.mod index 4c8ccb9..aa7a15f 100644 --- a/go.mod +++ b/go.mod @@ -2,9 +2,7 @@ module go.unistack.org/micro-client-http/v4 go 1.22.0 -toolchain go1.23.3 - -require go.unistack.org/micro/v4 v4.1.1 +require go.unistack.org/micro/v4 v4.1.2 require ( github.com/ash3in/uuidv8 v1.2.0 // indirect diff --git a/go.sum b/go.sum index f7adb81..c7c5c14 100644 --- a/go.sum +++ b/go.sum @@ -22,8 +22,8 @@ github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= go.unistack.org/micro-proto/v4 v4.1.0 h1:qPwL2n/oqh9RE3RTTDgt28XK3QzV597VugQPaw9lKUk= go.unistack.org/micro-proto/v4 v4.1.0/go.mod h1:ArmK7o+uFvxSY3dbJhKBBX4Pm1rhWdLEFf3LxBrMtec= -go.unistack.org/micro/v4 v4.1.1 h1:Cx2Uo5LN3J3lIxLv2jNYSqoVQbGShwMQgr4cffjqqVI= -go.unistack.org/micro/v4 v4.1.1/go.mod h1:lr3oYED8Ay1vjK68QqRw30QOtdk/ffpZqMFDasOUhKw= +go.unistack.org/micro/v4 v4.1.2 h1:9SOlPYyPNNFpg1A7BsvhDyQm3gysLH1AhWbDCp1hyoY= +go.unistack.org/micro/v4 v4.1.2/go.mod h1:lr3oYED8Ay1vjK68QqRw30QOtdk/ffpZqMFDasOUhKw= golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= diff --git a/http.go b/http.go index 42c9b45..d2952ca 100644 --- a/http.go +++ b/http.go @@ -115,7 +115,7 @@ func newRequest(ctx context.Context, log logger.Logger, addr string, req client. u, err = u.Parse(path) if err != nil { - return nil, errors.BadRequest("go.micro.client", err.Error()) + return nil, errors.BadRequest("go.micro.client", "%+v", err) } var nmsg interface{} @@ -126,12 +126,12 @@ func newRequest(ctx context.Context, log logger.Logger, addr string, req client. } if err != nil { - return nil, errors.BadRequest("go.micro.client", err.Error()) + return nil, errors.BadRequest("go.micro.client", "%+v", err) } u, err = url.Parse(fmt.Sprintf("%s://%s%s", scheme, host, path)) if err != nil { - return nil, errors.BadRequest("go.micro.client", err.Error()) + return nil, errors.BadRequest("go.micro.client", "%+v", err) } var cookies []*http.Cookie @@ -174,11 +174,11 @@ func newRequest(ctx context.Context, log logger.Logger, addr string, req client. for k, required := range vm { v, err = rutil.StructFieldByPath(msg, k) if err != nil { - return nil, errors.BadRequest("go.micro.client", err.Error()) + return nil, errors.BadRequest("go.micro.client", "%+v", err) } if rutil.IsZero(v) { if required == "true" { - return nil, errors.BadRequest("go.micro.client", fmt.Sprintf("required field %s not set", k)) + return nil, errors.BadRequest("go.micro.client", "required field %s not set", k) } continue } @@ -194,7 +194,7 @@ func newRequest(ctx context.Context, log logger.Logger, addr string, req client. b, err := cf.Marshal(nmsg) if err != nil { - return nil, errors.BadRequest("go.micro.client", err.Error()) + return nil, errors.BadRequest("go.micro.client", "%+v", err) } var hreq *http.Request @@ -207,7 +207,7 @@ func newRequest(ctx context.Context, log logger.Logger, addr string, req client. } if err != nil { - return nil, errors.BadRequest("go.micro.client", err.Error()) + return nil, errors.BadRequest("go.micro.client", "%+v", err) } hreq.Header = header @@ -230,7 +230,7 @@ func (h *httpClient) call(ctx context.Context, addr string, req client.Request, cf, err := h.newCodec(ct) if err != nil { - return errors.BadRequest("go.micro.client", err.Error()) + return errors.BadRequest("go.micro.client", "%+v", err) } hreq, err := newRequest(ctx, h.opts.Logger, addr, req, ct, cf, req.Body(), opts) if err != nil { @@ -243,14 +243,14 @@ func (h *httpClient) call(ctx context.Context, addr string, req client.Request, switch err := err.(type) { case *url.Error: if err, ok := err.Err.(net.Error); ok && err.Timeout() { - return errors.Timeout("go.micro.client", err.Error()) + return errors.Timeout("go.micro.client", "%+v", err) } case net.Error: if err.Timeout() { - return errors.Timeout("go.micro.client", err.Error()) + return errors.Timeout("go.micro.client", "%+v", err) } } - return errors.InternalServerError("go.micro.client", err.Error()) + return errors.InternalServerError("go.micro.client", "%+v", err) } defer hrsp.Body.Close() @@ -267,12 +267,12 @@ func (h *httpClient) stream(ctx context.Context, addr string, req client.Request // get codec cf, err := h.newCodec(ct) if err != nil { - return nil, errors.BadRequest("go.micro.client", err.Error()) + return nil, errors.BadRequest("go.micro.client", "%+v", err) } cc, err := (h.httpcli.Transport).(*http.Transport).DialContext(ctx, "tcp", addr) if err != nil { - return nil, errors.InternalServerError("go.micro.client", fmt.Sprintf("Error dialing: %v", err)) + return nil, errors.InternalServerError("go.micro.client", "Error dialing: %v", err) } return &httpStream{ @@ -396,7 +396,7 @@ func (h *httpClient) Call(ctx context.Context, req client.Request, rsp interface // call backoff first. Someone may want an initial start delay t, err := callOpts.Backoff(ctx, req, i) if err != nil { - return errors.InternalServerError("go.micro.client", err.Error()) + return errors.InternalServerError("go.micro.client", "%+v", err) } // only sleep if greater than 0 @@ -410,7 +410,7 @@ func (h *httpClient) Call(ctx context.Context, req client.Request, rsp interface // TODO apply any filtering here routes, err = h.opts.Lookup(ctx, req, callOpts) if err != nil { - return errors.InternalServerError("go.micro.client", err.Error()) + return errors.InternalServerError("go.micro.client", "%+v", err) } // balance the list of nodes @@ -532,7 +532,7 @@ func (h *httpClient) Stream(ctx context.Context, req client.Request, opts ...cli // call backoff first. Someone may want an initial start delay t, cerr := callOpts.Backoff(ctx, req, i) if cerr != nil { - return nil, errors.InternalServerError("go.micro.client", cerr.Error()) + return nil, errors.InternalServerError("go.micro.client", "%+v", cerr) } // only sleep if greater than 0 @@ -546,7 +546,7 @@ func (h *httpClient) Stream(ctx context.Context, req client.Request, opts ...cli // TODO apply any filtering here routes, err = h.opts.Lookup(ctx, req, callOpts) if err != nil { - return nil, errors.InternalServerError("go.micro.client", err.Error()) + return nil, errors.InternalServerError("go.micro.client", "%+v", err) } // balance the list of nodes diff --git a/options.go b/options.go index 20b220e..5772a21 100644 --- a/options.go +++ b/options.go @@ -1,11 +1,12 @@ package http import ( + "context" "net" "net/http" + "go.unistack.org/micro/v4/client" "go.unistack.org/micro/v4/metadata" - "go.unistack.org/micro/v4/options" ) var ( @@ -26,73 +27,171 @@ var ( DefaultMaxSendMsgSize = 1024 * 1024 * 4 ) +type poolMaxStreams struct{} + // PoolMaxStreams maximum streams on a connectioin -func PoolMaxStreams(n int) options.Option { - return options.NewOption("PoolMaxStreams")(n) +func PoolMaxStreams(n int) client.Option { + return func(o *client.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, poolMaxStreams{}, n) + } } +type poolMaxIdle struct{} + // PoolMaxIdle maximum idle conns of a pool -func PoolMaxIdle(n int) options.Option { - return options.NewOption("PoolMaxIdle")(n) +func PoolMaxIdle(d int) client.Option { + return func(o *client.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, poolMaxIdle{}, d) + } } +type maxRecvMsgSizeKey struct{} + // MaxRecvMsgSize set the maximum size of message that client can receive. -func MaxRecvMsgSize(n int) options.Option { - return options.NewOption("MaxRecvMsgSize")(n) +func MaxRecvMsgSize(s int) client.Option { + return func(o *client.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, maxRecvMsgSizeKey{}, s) + } } +type maxSendMsgSizeKey struct{} + // MaxSendMsgSize set the maximum size of message that client can send. -func MaxSendMsgSize(n int) options.Option { - return options.NewOption("MaxSendMsgSize")(n) +func MaxSendMsgSize(s int) client.Option { + return func(o *client.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, maxSendMsgSizeKey{}, s) + } } +type httpClientKey struct{} + // nolint: golint // HTTPClient pass http.Client option to client Call -func HTTPClient(c *http.Client) options.Option { - return options.NewOption("HTTPClient")(c) +func HTTPClient(c *http.Client) client.Option { + return func(o *client.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, httpClientKey{}, c) + } } +type httpDialerKey struct{} + // nolint: golint // HTTPDialer pass net.Dialer option to client -func HTTPDialer(d *net.Dialer) options.Option { - return options.NewOption("HTTPDialer")(d) +func HTTPDialer(d *net.Dialer) client.Option { + return func(o *client.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, httpDialerKey{}, d) + } } +type methodKey struct{} + // Method pass method option to client Call -func Method(m string) options.Option { - return options.NewOption("Method")(m) +func Method(m string) client.CallOption { + return func(o *client.CallOptions) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, methodKey{}, m) + } } +type pathKey struct{} + // Path spcecifies path option to client Call -func Path(p string) options.Option { - return options.NewOption("Path")(p) +func Path(p string) client.Option { + return func(o *client.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, pathKey{}, p) + } } +type bodyKey struct{} + // Body specifies body option to client Call -func Body(b string) options.Option { - return options.NewOption("Body")(b) +func Body(b string) client.Option { + return func(o *client.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, bodyKey{}, b) + } } -func ErrorMap(m map[string]interface{}) options.Option { - return options.NewOption("ErrorMap")(m) +type errorMapKey struct{} + +func ErrorMap(m map[string]interface{}) client.Option { + return func(o *client.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, errorMapKey{}, m) + } } +type structTagsKey struct{} + // StructTags pass tags slice option to client Call -func StructTags(tags []string) options.Option { - return options.NewOption("StructTags")(tags) +func StructTags(tags []string) client.Option { + return func(o *client.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, structTagsKey{}, tags) + } } +type metadataKey struct{} + // Metadata pass metadata to client Call -func Metadata(md metadata.Metadata) options.Option { - return options.NewOption("Metadata")(md) +func Metadata(md metadata.Metadata) client.Option { + return func(o *client.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, metadataKey{}, md) + } } +type cookieKey struct{} + // Cookie pass cookie to client Call -func Cookie(cookies ...string) options.Option { - return options.NewOption("Cookie")(cookies) +func Cookie(cookies ...string) client.Option { + return func(o *client.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, cookieKey{}, cookies) + } } +type headerKey struct{} + // Header pass cookie to client Call -func Header(headers ...string) options.Option { - return options.NewOption("Header")(headers) +func Header(headers ...string) client.Option { + return func(o *client.Options) { + if o.Context == nil { + o.Context = context.Background() + } + o.Context = context.WithValue(o.Context, headerKey{}, headers) + } } diff --git a/stream.go b/stream.go index 2a69b89..9f30103 100644 --- a/stream.go +++ b/stream.go @@ -90,7 +90,7 @@ func (h *httpStream) Recv(msg interface{}) error { hrsp, err := http.ReadResponse(h.reader, new(http.Request)) if err != nil { - return errors.InternalServerError("go.micro.client", err.Error()) + return errors.InternalServerError("go.micro.client", "%+v", err) } defer hrsp.Body.Close() @@ -136,7 +136,7 @@ func (h *httpStream) parseRsp(ctx context.Context, log logger.Logger, hrsp *http if log.V(logger.ErrorLevel) { log.Error(ctx, "failed to read body", err) } - return errors.InternalServerError("go.micro.client", string(buf)) + return errors.InternalServerError("go.micro.client", "%s", buf) } } @@ -146,7 +146,7 @@ func (h *httpStream) parseRsp(ctx context.Context, log logger.Logger, hrsp *http if hrsp.StatusCode < 400 { if err = cf.Unmarshal(buf, rsp); err != nil { - return errors.InternalServerError("go.micro.client", err.Error()) + return errors.InternalServerError("go.micro.client", "%+v", err) } return nil } @@ -163,7 +163,7 @@ func (h *httpStream) parseRsp(ctx context.Context, log logger.Logger, hrsp *http } if cerr := cf.Unmarshal(buf, rerr); cerr != nil { - return errors.InternalServerError("go.micro.client", cerr.Error()) + return errors.InternalServerError("go.micro.client", "%+v", cerr) } if err, ok = rerr.(error); !ok { diff --git a/util.go b/util.go index b0496c5..d463185 100644 --- a/util.go +++ b/util.go @@ -284,7 +284,7 @@ func (h *httpClient) parseRsp(ctx context.Context, hrsp *http.Response, rsp inte if h.opts.Logger.V(logger.ErrorLevel) { h.opts.Logger.Error(ctx, "failed to read body", err) } - return errors.InternalServerError("go.micro.client", string(buf)) + return errors.InternalServerError("go.micro.client", "%s", buf) } } @@ -293,7 +293,7 @@ func (h *httpClient) parseRsp(ctx context.Context, hrsp *http.Response, rsp inte if h.opts.Logger.V(logger.DebugLevel) { h.opts.Logger.Debug(ctx, fmt.Sprintf("response with %v unknown content-type %s %s", hrsp.Header, ct, buf)) } - return errors.InternalServerError("go.micro.client", cerr.Error()) + return errors.InternalServerError("go.micro.client", "%+v", cerr) } if h.opts.Logger.V(logger.DebugLevel) { @@ -303,7 +303,7 @@ func (h *httpClient) parseRsp(ctx context.Context, hrsp *http.Response, rsp inte // succeseful response if hrsp.StatusCode < 400 { if err = cf.Unmarshal(buf, rsp); err != nil { - return errors.InternalServerError("go.micro.client", err.Error()) + return errors.InternalServerError("go.micro.client", "%+v", err) } return nil } @@ -323,7 +323,7 @@ func (h *httpClient) parseRsp(ctx context.Context, hrsp *http.Response, rsp inte } if cerr := cf.Unmarshal(buf, rerr); cerr != nil { - return errors.InternalServerError("go.micro.client", cerr.Error()) + return errors.InternalServerError("go.micro.client", "%+v", cerr) } if err, ok = rerr.(error); !ok { -- 2.49.1