Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
e889545210 | |||
|
526e414d60 | ||
db423dff58 | |||
542d4cec00 | |||
0ecd1da0dc | |||
0a8755ecb7 | |||
9c29d92d7f | |||
b871c1be38 | |||
74bb12e75e | |||
49a95c183b | |||
5e6bd93a6b | |||
9ef26caf40 | |||
b3e58d2cb6 |
19
go.mod
19
go.mod
@@ -5,17 +5,18 @@ go 1.18
|
|||||||
require (
|
require (
|
||||||
go.unistack.org/micro-codec-yaml/v3 v3.10.0
|
go.unistack.org/micro-codec-yaml/v3 v3.10.0
|
||||||
go.unistack.org/micro-proto/v3 v3.3.1
|
go.unistack.org/micro-proto/v3 v3.3.1
|
||||||
go.unistack.org/micro/v3 v3.10.42
|
go.unistack.org/micro/v3 v3.10.52
|
||||||
golang.org/x/net v0.14.0
|
golang.org/x/net v0.22.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
github.com/google/gnostic v0.6.9 // indirect
|
github.com/google/gnostic v0.7.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e // indirect
|
github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect
|
||||||
google.golang.org/grpc v1.57.0 // indirect
|
golang.org/x/sys v0.18.0 // indirect
|
||||||
google.golang.org/protobuf v1.31.0 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
google.golang.org/grpc v1.62.1 // indirect
|
||||||
|
google.golang.org/protobuf v1.33.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||||
)
|
)
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
package health // import "go.unistack.org/micro-server-http/v3/handler/health"
|
package health_handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
package meter // import "go.unistack.org/micro-server-http/v3/handler/meter"
|
package meter_handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
codecpb "go.unistack.org/micro-proto/v3/codec"
|
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/logger"
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v3/metadata"
|
||||||
"go.unistack.org/micro/v3/meter"
|
"go.unistack.org/micro/v3/meter"
|
||||||
@@ -42,9 +41,10 @@ type Handler struct {
|
|||||||
type Option func(*Options)
|
type Option func(*Options)
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
Meter meter.Meter
|
Meter meter.Meter
|
||||||
Name string
|
Name string
|
||||||
MeterOptions []meter.Option
|
MeterOptions []meter.Option
|
||||||
|
DisableCompress bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func Meter(m meter.Meter) Option {
|
func Meter(m meter.Meter) Option {
|
||||||
@@ -59,6 +59,12 @@ func Name(name string) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DisableCompress(g bool) Option {
|
||||||
|
return func(o *Options) {
|
||||||
|
o.DisableCompress = g
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func MeterOptions(opts ...meter.Option) Option {
|
func MeterOptions(opts ...meter.Option) Option {
|
||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
o.MeterOptions = append(o.MeterOptions, opts...)
|
o.MeterOptions = append(o.MeterOptions, opts...)
|
||||||
@@ -66,7 +72,7 @@ func MeterOptions(opts ...meter.Option) Option {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewOptions(opts ...Option) Options {
|
func NewOptions(opts ...Option) Options {
|
||||||
options := Options{Meter: meter.DefaultMeter}
|
options := Options{Meter: meter.DefaultMeter, DisableCompress: false}
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&options)
|
o(&options)
|
||||||
}
|
}
|
||||||
@@ -81,7 +87,7 @@ func NewHandler(opts ...Option) *Handler {
|
|||||||
func (h *Handler) Metrics(ctx context.Context, req *codecpb.Frame, rsp *codecpb.Frame) error {
|
func (h *Handler) Metrics(ctx context.Context, req *codecpb.Frame, rsp *codecpb.Frame) error {
|
||||||
log, ok := logger.FromContext(ctx)
|
log, ok := logger.FromContext(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
log = logger.DefaultLogger()
|
log = logger.DefaultLogger
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := bufPool.Get().(*bytes.Buffer)
|
buf := bufPool.Get().(*bytes.Buffer)
|
||||||
@@ -90,8 +96,9 @@ func (h *Handler) Metrics(ctx context.Context, req *codecpb.Frame, rsp *codecpb.
|
|||||||
|
|
||||||
w := io.Writer(buf)
|
w := io.Writer(buf)
|
||||||
|
|
||||||
if md, ok := metadata.FromIncomingContext(ctx); gzipAccepted(md) && ok {
|
if md, ok := metadata.FromOutgoingContext(ctx); gzipAccepted(md) && ok && !h.opts.DisableCompress {
|
||||||
md.Set(contentEncodingHeader, "gzip")
|
omd, _ := metadata.FromOutgoingContext(ctx)
|
||||||
|
omd.Set(contentEncodingHeader, "gzip")
|
||||||
gz := gzipPool.Get().(*gzip.Writer)
|
gz := gzipPool.Get().(*gzip.Writer)
|
||||||
defer gzipPool.Put(gz)
|
defer gzipPool.Put(gz)
|
||||||
|
|
||||||
@@ -99,10 +106,11 @@ func (h *Handler) Metrics(ctx context.Context, req *codecpb.Frame, rsp *codecpb.
|
|||||||
defer gz.Close()
|
defer gz.Close()
|
||||||
|
|
||||||
w = gz
|
w = gz
|
||||||
|
gz.Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.opts.Meter.Write(w, h.opts.MeterOptions...); err != nil {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
package pprof
|
package pprof_handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"expvar"
|
"expvar"
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
package swaggerui // import "go.unistack.org/micro-server-http/v3/handler/swagger-ui"
|
package swaggerui_handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
package swagger
|
package swagger_handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/fs"
|
"io/fs"
|
||||||
|
58
http.go
58
http.go
@@ -191,6 +191,11 @@ func (h *Server) NewHandler(handler interface{}, opts ...server.HandlerOption) s
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
registerCORS := false
|
||||||
|
if v, ok := options.Context.Value(registerCORSHandlerKey{}).(bool); ok && v {
|
||||||
|
registerCORS = true
|
||||||
|
}
|
||||||
|
|
||||||
for hn, md := range options.Metadata {
|
for hn, md := range options.Metadata {
|
||||||
var method reflect.Method
|
var method reflect.Method
|
||||||
mname := hn[strings.Index(hn, ".")+1:]
|
mname := hn[strings.Index(hn, ".")+1:]
|
||||||
@@ -223,13 +228,22 @@ func (h *Server) NewHandler(handler interface{}, opts ...server.HandlerOption) s
|
|||||||
pth := &patHandler{mtype: mtype, name: name, rcvr: rcvr}
|
pth := &patHandler{mtype: mtype, name: name, rcvr: rcvr}
|
||||||
hdlr.name = name
|
hdlr.name = name
|
||||||
|
|
||||||
if err := hdlr.handlers.Insert([]string{md["Method"]}, md["Path"], pth); err != nil {
|
methods := []string{md["Method"]}
|
||||||
h.opts.Logger.Errorf(h.opts.Context, "cant add handler for %s %s", md["Method"], md["Path"])
|
if registerCORS {
|
||||||
|
methods = append(methods, http.MethodOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := hdlr.handlers.Insert(methods, md["Path"], pth); err != nil {
|
||||||
|
h.opts.Logger.Errorf(h.opts.Context, "cant add handler for %v %s", methods, md["Path"])
|
||||||
}
|
}
|
||||||
|
|
||||||
if h.registerRPC {
|
if h.registerRPC {
|
||||||
h.opts.Logger.Infof(h.opts.Context, "register rpc handler for http.MethodPost %s /%s", hn, hn)
|
methods := []string{http.MethodPost}
|
||||||
if err := hdlr.handlers.Insert([]string{http.MethodPost}, "/"+hn, pth); err != nil {
|
if registerCORS {
|
||||||
|
methods = append(methods, http.MethodOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := hdlr.handlers.Insert(methods, "/"+hn, pth); err != nil {
|
||||||
h.opts.Logger.Errorf(h.opts.Context, "cant add rpc handler for http.MethodPost %s /%s", hn, hn)
|
h.opts.Logger.Errorf(h.opts.Context, "cant add rpc handler for http.MethodPost %s /%s", hn, hn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -273,13 +287,23 @@ func (h *Server) NewHandler(handler interface{}, opts ...server.HandlerOption) s
|
|||||||
pth := &patHandler{mtype: mtype, name: name, rcvr: rcvr}
|
pth := &patHandler{mtype: mtype, name: name, rcvr: rcvr}
|
||||||
hdlr.name = name
|
hdlr.name = name
|
||||||
|
|
||||||
if err := hdlr.handlers.Insert([]string{md.Method}, md.Path, pth); err != nil {
|
methods := []string{md.Method}
|
||||||
|
if registerCORS {
|
||||||
|
methods = append(methods, http.MethodOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := hdlr.handlers.Insert(methods, md.Path, pth); err != nil {
|
||||||
h.opts.Logger.Errorf(h.opts.Context, "cant add handler for %s %s", md.Method, md.Path)
|
h.opts.Logger.Errorf(h.opts.Context, "cant add handler for %s %s", md.Method, md.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
if h.registerRPC {
|
if h.registerRPC {
|
||||||
|
methods := []string{http.MethodPost}
|
||||||
|
if registerCORS {
|
||||||
|
methods = append(methods, http.MethodOptions)
|
||||||
|
}
|
||||||
|
|
||||||
h.opts.Logger.Infof(h.opts.Context, "register rpc handler for http.MethodPost %s /%s", hn, hn)
|
h.opts.Logger.Infof(h.opts.Context, "register rpc handler for http.MethodPost %s /%s", hn, hn)
|
||||||
if err := hdlr.handlers.Insert([]string{http.MethodPost}, "/"+hn, pth); err != nil {
|
if err := hdlr.handlers.Insert(methods, "/"+hn, pth); err != nil {
|
||||||
h.opts.Logger.Errorf(h.opts.Context, "cant add rpc handler for http.MethodPost %s /%s", hn, hn)
|
h.opts.Logger.Errorf(h.opts.Context, "cant add rpc handler for http.MethodPost %s /%s", hn, hn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -493,7 +517,7 @@ func (h *Server) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if config.Logger.V(logger.InfoLevel) {
|
if config.Logger.V(logger.InfoLevel) {
|
||||||
config.Logger.Infof(config.Context, "Listening on %s", ts.Addr().String())
|
config.Logger.Info(config.Context, "Listening on "+ts.Addr().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
h.Lock()
|
h.Lock()
|
||||||
@@ -537,7 +561,7 @@ func (h *Server) Start() error {
|
|||||||
|
|
||||||
if err := config.RegisterCheck(h.opts.Context); err != nil {
|
if err := config.RegisterCheck(h.opts.Context); err != nil {
|
||||||
if config.Logger.V(logger.ErrorLevel) {
|
if config.Logger.V(logger.ErrorLevel) {
|
||||||
config.Logger.Errorf(config.Context, "Server %s-%s register check error: %s", config.Name, config.ID, err)
|
config.Logger.Error(config.Context, fmt.Sprintf("Server %s-%s register check error", config.Name, config.ID) err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err = h.Register(); err != nil {
|
if err = h.Register(); err != nil {
|
||||||
@@ -562,12 +586,14 @@ func (h *Server) Start() error {
|
|||||||
var ok bool
|
var ok bool
|
||||||
if hs, ok = h.opts.Context.Value(serverKey{}).(*http.Server); ok && hs != nil {
|
if hs, ok = h.opts.Context.Value(serverKey{}).(*http.Server); ok && hs != nil {
|
||||||
hs.Handler = fn
|
hs.Handler = fn
|
||||||
|
} else {
|
||||||
|
hs = &http.Server{Handler: fn}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
if cerr := hs.Serve(ts); cerr != nil && !errors.Is(cerr, net.ErrClosed) {
|
if cerr := hs.Serve(ts); cerr != nil && !errors.Is(cerr, net.ErrClosed) {
|
||||||
h.opts.Logger.Error(h.opts.Context, cerr)
|
h.opts.Logger.Error(h.opts.Context, "serve error", cerr)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -595,28 +621,28 @@ func (h *Server) Start() error {
|
|||||||
// nolint: nestif
|
// nolint: nestif
|
||||||
if rerr != nil && registered {
|
if rerr != nil && registered {
|
||||||
if config.Logger.V(logger.ErrorLevel) {
|
if config.Logger.V(logger.ErrorLevel) {
|
||||||
config.Logger.Errorf(config.Context, "Server %s-%s register check error: %s, deregister it", config.Name, config.ID, rerr)
|
config.Logger.Error(config.Context,fmt.Sprintf("Server %s-%s register check error, deregister it", config.Name, config.ID), rerr)
|
||||||
}
|
}
|
||||||
// deregister self in case of error
|
// deregister self in case of error
|
||||||
if err := h.Deregister(); err != nil {
|
if err := h.Deregister(); err != nil {
|
||||||
if config.Logger.V(logger.ErrorLevel) {
|
if config.Logger.V(logger.ErrorLevel) {
|
||||||
config.Logger.Errorf(config.Context, "Server %s-%s deregister error: %s", config.Name, config.ID, err)
|
config.Logger.Error(config.Context, fmt.Sprintf("Server %s-%s deregister error", config.Name, config.ID), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if rerr != nil && !registered {
|
} else if rerr != nil && !registered {
|
||||||
if config.Logger.V(logger.ErrorLevel) {
|
if config.Logger.V(logger.ErrorLevel) {
|
||||||
config.Logger.Errorf(config.Context, "Server %s-%s register check error: %s", config.Name, config.ID, rerr)
|
config.Logger.Error(config.Context, fmt.Sprintf("Server %s-%s register check error", config.Name, config.ID), rerr)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := h.Register(); err != nil {
|
if err := h.Register(); err != nil {
|
||||||
if config.Logger.V(logger.ErrorLevel) {
|
if config.Logger.V(logger.ErrorLevel) {
|
||||||
config.Logger.Errorf(config.Context, "Server %s-%s register error: %s", config.Name, config.ID, err)
|
config.Logger.Error(config.Context, fmt.Sprintf("Server %s-%s register error: %s", config.Name, config.ID), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.Register(); err != nil {
|
if err := h.Register(); err != nil {
|
||||||
config.Logger.Errorf(config.Context, "Server register error: %s", err)
|
config.Logger.Error(config.Context, "Server register error", err)
|
||||||
}
|
}
|
||||||
// wait for exit
|
// wait for exit
|
||||||
case ch = <-h.exit:
|
case ch = <-h.exit:
|
||||||
@@ -626,11 +652,11 @@ func (h *Server) Start() error {
|
|||||||
|
|
||||||
// deregister
|
// deregister
|
||||||
if err := h.Deregister(); err != nil {
|
if err := h.Deregister(); err != nil {
|
||||||
config.Logger.Errorf(config.Context, "Server deregister error: %s", err)
|
config.Logger.Error(config.Context, "Server deregister error", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := config.Broker.Disconnect(config.Context); err != nil {
|
if err := config.Broker.Disconnect(config.Context); err != nil {
|
||||||
config.Logger.Errorf(config.Context, "Broker disconnect error: %s", err)
|
config.Logger.Error(config.Context, "Broker disconnect error", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), h.opts.GracefulTimeout)
|
ctx, cancel := context.WithTimeout(context.Background(), h.opts.GracefulTimeout)
|
||||||
|
@@ -133,6 +133,13 @@ func RegisterRPCHandler(b bool) server.Option {
|
|||||||
return server.SetOption(registerRPCHandlerKey{}, b)
|
return server.SetOption(registerRPCHandlerKey{}, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type registerCORSHandlerKey struct{}
|
||||||
|
|
||||||
|
// RegisterCORSHandler registers cors endpoints with /ServiceName.ServiceEndpoint method POPTIONSOST
|
||||||
|
func RegisterCORSHandler(b bool) server.HandlerOption {
|
||||||
|
return server.SetHandlerOption(registerCORSHandlerKey{}, b)
|
||||||
|
}
|
||||||
|
|
||||||
type handlerEndpointsKey struct{}
|
type handlerEndpointsKey struct{}
|
||||||
|
|
||||||
type EndpointMetadata struct {
|
type EndpointMetadata struct {
|
||||||
|
Reference in New Issue
Block a user