Middleware/metadata v2 (#1050)
* add middleware metadata * add transport header * add transport carrier Co-authored-by: longXboy <longxboy@gmail.com>pull/1054/head
parent
7f2e3becbe
commit
8d8cd8c8a8
@ -0,0 +1,46 @@ |
|||||||
|
package metadata |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
"fmt" |
||||||
|
) |
||||||
|
|
||||||
|
type serverMetadataKey struct{} |
||||||
|
|
||||||
|
// NewServerContext creates a new context with client md attached.
|
||||||
|
func NewServerContext(ctx context.Context, md Metadata) context.Context { |
||||||
|
return context.WithValue(ctx, serverMetadataKey{}, md) |
||||||
|
} |
||||||
|
|
||||||
|
// FromServerContext returns the server metadata in ctx if it exists.
|
||||||
|
func FromServerContext(ctx context.Context) (Metadata, bool) { |
||||||
|
md, ok := ctx.Value(serverMetadataKey{}).(Metadata) |
||||||
|
return md, ok |
||||||
|
} |
||||||
|
|
||||||
|
type clientMetadataKey struct{} |
||||||
|
|
||||||
|
// NewClientContext creates a new context with client md attached.
|
||||||
|
func NewClientContext(ctx context.Context, md Metadata) context.Context { |
||||||
|
return context.WithValue(ctx, clientMetadataKey{}, md) |
||||||
|
} |
||||||
|
|
||||||
|
// FromClientContext returns the client metadata in ctx if it exists.
|
||||||
|
func FromClientContext(ctx context.Context) (Metadata, bool) { |
||||||
|
md, ok := ctx.Value(clientMetadataKey{}).(Metadata) |
||||||
|
return md, ok |
||||||
|
} |
||||||
|
|
||||||
|
// AppendToClientContext returns a new context with the provided kv merged
|
||||||
|
// with any existing metadata in the context.
|
||||||
|
func AppendToClientContext(ctx context.Context, kv ...string) context.Context { |
||||||
|
if len(kv)%2 == 1 { |
||||||
|
panic(fmt.Sprintf("metadata: AppendToOutgoingContext got an odd number of input pairs for metadata: %d", len(kv))) |
||||||
|
} |
||||||
|
md, _ := FromClientContext(ctx) |
||||||
|
md = md.Clone() |
||||||
|
for i := 0; i < len(kv); i += 2 { |
||||||
|
md.Set(kv[i], kv[i+1]) |
||||||
|
} |
||||||
|
return NewClientContext(ctx, md) |
||||||
|
} |
@ -0,0 +1,95 @@ |
|||||||
|
package metadata |
||||||
|
|
||||||
|
import ( |
||||||
|
"context" |
||||||
|
"strings" |
||||||
|
|
||||||
|
"github.com/go-kratos/kratos/v2/metadata" |
||||||
|
"github.com/go-kratos/kratos/v2/middleware" |
||||||
|
"github.com/go-kratos/kratos/v2/transport" |
||||||
|
) |
||||||
|
|
||||||
|
// Option is metadata option.
|
||||||
|
type Option func(*options) |
||||||
|
|
||||||
|
type options struct { |
||||||
|
prefix []string |
||||||
|
md metadata.Metadata |
||||||
|
} |
||||||
|
|
||||||
|
// WithConstants is option with constant metadata key value.
|
||||||
|
func WithConstants(md metadata.Metadata) Option { |
||||||
|
return func(o *options) { |
||||||
|
o.md = md |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// WithPropagatedPrefix is option with global propagated key prefix.
|
||||||
|
func WithPropagatedPrefix(prefix ...string) Option { |
||||||
|
return func(o *options) { |
||||||
|
o.prefix = prefix |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Server is middleware client-side metadata.
|
||||||
|
func Server(opts ...Option) middleware.Middleware { |
||||||
|
options := options{ |
||||||
|
prefix: []string{"x-md-global-", "x-md-local-"}, |
||||||
|
} |
||||||
|
for _, o := range opts { |
||||||
|
o(&options) |
||||||
|
} |
||||||
|
return func(handler middleware.Handler) middleware.Handler { |
||||||
|
return func(ctx context.Context, req interface{}) (reply interface{}, err error) { |
||||||
|
if tr, ok := transport.FromServerContext(ctx); ok { |
||||||
|
md := metadata.Metadata{} |
||||||
|
for _, k := range tr.Header().Keys() { |
||||||
|
key := strings.ToLower(k) |
||||||
|
for _, prefix := range options.prefix { |
||||||
|
if strings.HasPrefix(key, prefix) { |
||||||
|
md.Set(k, tr.Header().Get(k)) |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
ctx = metadata.NewServerContext(ctx, md) |
||||||
|
} |
||||||
|
return handler(ctx, req) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Client is middleware client-side metadata.
|
||||||
|
func Client(opts ...Option) middleware.Middleware { |
||||||
|
options := options{ |
||||||
|
prefix: []string{"x-md-global-"}, |
||||||
|
} |
||||||
|
for _, o := range opts { |
||||||
|
o(&options) |
||||||
|
} |
||||||
|
return func(handler middleware.Handler) middleware.Handler { |
||||||
|
return func(ctx context.Context, req interface{}) (reply interface{}, err error) { |
||||||
|
if tr, ok := transport.FromClientContext(ctx); ok { |
||||||
|
for k, v := range options.md { |
||||||
|
tr.Header().Set(k, v) |
||||||
|
} |
||||||
|
if md, ok := metadata.FromClientContext(ctx); ok { |
||||||
|
for k, v := range md { |
||||||
|
tr.Header().Set(k, v) |
||||||
|
} |
||||||
|
} |
||||||
|
if md, ok := metadata.FromServerContext(ctx); ok { |
||||||
|
for k, v := range md { |
||||||
|
for _, prefix := range options.prefix { |
||||||
|
if strings.HasPrefix(k, prefix) { |
||||||
|
tr.Header().Set(k, v) |
||||||
|
break |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return handler(ctx, req) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue