From 43a19aca6520e644c9f75da0479e4ed761e982eb Mon Sep 17 00:00:00 2001 From: Gorbunov Kirill Andreevich Date: Mon, 11 Mar 2024 13:01:42 +0300 Subject: [PATCH 1/3] gzip for v3 #153 --- handler/meter/meter.go | 63 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/handler/meter/meter.go b/handler/meter/meter.go index f92830e..76974ce 100644 --- a/handler/meter/meter.go +++ b/handler/meter/meter.go @@ -2,13 +2,36 @@ package meter // import "go.unistack.org/micro-server-http/v3/handler/meter" import ( "bytes" + "compress/gzip" "context" + "io" + "strings" + "sync" codecpb "go.unistack.org/micro-proto/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/meter" ) +const ( + contentEncodingHeader = "Content-Encoding" + acceptEncodingHeader = "Accept-Encoding" +) + +var gzipPool = sync.Pool{ + New: func() interface{} { + return gzip.NewWriter(nil) + }, +} + +var bufPool = sync.Pool{ + New: func() interface{} { + return bytes.NewBuffer(nil) + }, +} + // guard to fail early var _ MeterServiceServer = &Handler{} @@ -56,12 +79,46 @@ func NewHandler(opts ...Option) *Handler { } func (h *Handler) Metrics(ctx context.Context, req *codecpb.Frame, rsp *codecpb.Frame) error { - buf := bytes.NewBuffer(nil) - if err := h.opts.Meter.Write(buf, h.opts.MeterOptions...); err != nil { - return errors.InternalServerError(h.opts.Name, "%v", err) + log, ok := logger.FromContext(ctx) + if !ok { + log = logger.DefaultLogger() + } + + buf := bufPool.Get().(*bytes.Buffer) + defer bufPool.Put(buf) + buf.Reset() + + w := io.Writer(buf) + + if md, ok := metadata.FromIncomingContext(ctx); gzipAccepted(md) && ok { + md.Set(contentEncodingHeader, "gzip") + gz := gzipPool.Get().(*gzip.Writer) + defer gzipPool.Put(gz) + + gz.Reset(w) + defer gz.Close() + + w = gz + } + + if err := h.opts.Meter.Write(w, h.opts.MeterOptions...); err != nil { + log.Error(ctx, errors.InternalServerError(h.opts.Name, "%v", err)) + return nil } rsp.Data = buf.Bytes() return nil } + +// gzipAccepted returns whether the client will accept gzip-encoded content. +func gzipAccepted(md metadata.Metadata) bool { + a, ok := md.Get(acceptEncodingHeader) + if !ok { + return false + } + if strings.Contains(a, "gzip") { + return true + } + return false +} -- 2.45.2 From 3637243ab0141032eaac5e7c617105674620ff7b Mon Sep 17 00:00:00 2001 From: Gorbunov Kirill Andreevich Date: Mon, 18 Mar 2024 16:06:09 +0300 Subject: [PATCH 2/3] add flush --- handler/meter/meter.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/handler/meter/meter.go b/handler/meter/meter.go index 76974ce..578c4bc 100644 --- a/handler/meter/meter.go +++ b/handler/meter/meter.go @@ -92,6 +92,7 @@ func (h *Handler) Metrics(ctx context.Context, req *codecpb.Frame, rsp *codecpb. if md, ok := metadata.FromIncomingContext(ctx); gzipAccepted(md) && ok { md.Set(contentEncodingHeader, "gzip") + ctx = metadata.NewIncomingContext(ctx, md) gz := gzipPool.Get().(*gzip.Writer) defer gzipPool.Put(gz) @@ -99,6 +100,7 @@ func (h *Handler) Metrics(ctx context.Context, req *codecpb.Frame, rsp *codecpb. defer gz.Close() w = gz + gz.Flush() } if err := h.opts.Meter.Write(w, h.opts.MeterOptions...); err != nil { -- 2.45.2 From 4a5762871ee138e9682fdd2188d797616630223d Mon Sep 17 00:00:00 2001 From: Gorbunov Kirill Andreevich Date: Mon, 18 Mar 2024 16:08:11 +0300 Subject: [PATCH 3/3] add flush --- handler/meter/meter.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/handler/meter/meter.go b/handler/meter/meter.go index 578c4bc..7d327cf 100644 --- a/handler/meter/meter.go +++ b/handler/meter/meter.go @@ -9,7 +9,6 @@ import ( "sync" codecpb "go.unistack.org/micro-proto/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/meter" @@ -81,7 +80,7 @@ func NewHandler(opts ...Option) *Handler { func (h *Handler) Metrics(ctx context.Context, req *codecpb.Frame, rsp *codecpb.Frame) error { log, ok := logger.FromContext(ctx) if !ok { - log = logger.DefaultLogger() + log = logger.DefaultLogger } buf := bufPool.Get().(*bytes.Buffer) @@ -104,7 +103,7 @@ func (h *Handler) Metrics(ctx context.Context, req *codecpb.Frame, rsp *codecpb. } if err := h.opts.Meter.Write(w, h.opts.MeterOptions...); err != nil { - log.Error(ctx, errors.InternalServerError(h.opts.Name, "%v", err)) + log.Error(ctx, "http/meter: write failed", err) return nil } -- 2.45.2