gitee.com/sasukebo/go-micro/v4@v4.7.1/util/wrapper/wrapper.go (about)

     1  package wrapper
     2  
     3  import (
     4  	"context"
     5  	"strings"
     6  
     7  	"gitee.com/sasukebo/go-micro/v4/auth"
     8  	"gitee.com/sasukebo/go-micro/v4/client"
     9  	"gitee.com/sasukebo/go-micro/v4/debug/stats"
    10  	"gitee.com/sasukebo/go-micro/v4/debug/trace"
    11  	"gitee.com/sasukebo/go-micro/v4/metadata"
    12  	"gitee.com/sasukebo/go-micro/v4/server"
    13  )
    14  
    15  type fromServiceWrapper struct {
    16  	client.Client
    17  
    18  	// headers to inject
    19  	headers metadata.Metadata
    20  }
    21  
    22  var (
    23  	HeaderPrefix = "Micro-"
    24  )
    25  
    26  func (f *fromServiceWrapper) setHeaders(ctx context.Context) context.Context {
    27  	// don't overwrite keys
    28  	return metadata.MergeContext(ctx, f.headers, false)
    29  }
    30  
    31  func (f *fromServiceWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
    32  	ctx = f.setHeaders(ctx)
    33  	return f.Client.Call(ctx, req, rsp, opts...)
    34  }
    35  
    36  func (f *fromServiceWrapper) Stream(ctx context.Context, req client.Request, opts ...client.CallOption) (client.Stream, error) {
    37  	ctx = f.setHeaders(ctx)
    38  	return f.Client.Stream(ctx, req, opts...)
    39  }
    40  
    41  func (f *fromServiceWrapper) Publish(ctx context.Context, p client.Message, opts ...client.PublishOption) error {
    42  	ctx = f.setHeaders(ctx)
    43  	return f.Client.Publish(ctx, p, opts...)
    44  }
    45  
    46  // FromService wraps a client to inject service and auth metadata
    47  func FromService(name string, c client.Client) client.Client {
    48  	return &fromServiceWrapper{
    49  		c,
    50  		metadata.Metadata{
    51  			HeaderPrefix + "From-Service": name,
    52  		},
    53  	}
    54  }
    55  
    56  // HandlerStats wraps a server handler to generate request/error stats
    57  func HandlerStats(stats stats.Stats) server.HandlerWrapper {
    58  	// return a handler wrapper
    59  	return func(h server.HandlerFunc) server.HandlerFunc {
    60  		// return a function that returns a function
    61  		return func(ctx context.Context, req server.Request, rsp interface{}) error {
    62  			// execute the handler
    63  			err := h(ctx, req, rsp)
    64  			// record the stats
    65  			stats.Record(err)
    66  			// return the error
    67  			return err
    68  		}
    69  	}
    70  }
    71  
    72  type traceWrapper struct {
    73  	client.Client
    74  
    75  	name  string
    76  	trace trace.Tracer
    77  }
    78  
    79  func (c *traceWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
    80  	newCtx, s := c.trace.Start(ctx, req.Service()+"."+req.Endpoint())
    81  
    82  	s.Type = trace.SpanTypeRequestOutbound
    83  	err := c.Client.Call(newCtx, req, rsp, opts...)
    84  	if err != nil {
    85  		s.Metadata["error"] = err.Error()
    86  	}
    87  
    88  	// finish the trace
    89  	c.trace.Finish(s)
    90  
    91  	return err
    92  }
    93  
    94  // TraceCall is a call tracing wrapper
    95  func TraceCall(name string, t trace.Tracer, c client.Client) client.Client {
    96  	return &traceWrapper{
    97  		name:   name,
    98  		trace:  t,
    99  		Client: c,
   100  	}
   101  }
   102  
   103  // TraceHandler wraps a server handler to perform tracing
   104  func TraceHandler(t trace.Tracer) server.HandlerWrapper {
   105  	// return a handler wrapper
   106  	return func(h server.HandlerFunc) server.HandlerFunc {
   107  		// return a function that returns a function
   108  		return func(ctx context.Context, req server.Request, rsp interface{}) error {
   109  			// don't store traces for debug
   110  			if strings.HasPrefix(req.Endpoint(), "Debug.") {
   111  				return h(ctx, req, rsp)
   112  			}
   113  
   114  			// get the span
   115  			newCtx, s := t.Start(ctx, req.Service()+"."+req.Endpoint())
   116  			s.Type = trace.SpanTypeRequestInbound
   117  
   118  			err := h(newCtx, req, rsp)
   119  			if err != nil {
   120  				s.Metadata["error"] = err.Error()
   121  			}
   122  
   123  			// finish
   124  			t.Finish(s)
   125  
   126  			return err
   127  		}
   128  	}
   129  }
   130  
   131  func AuthCall(a func() auth.Auth, c client.Client) client.Client {
   132  	return &authWrapper{Client: c, auth: a}
   133  }
   134  
   135  type authWrapper struct {
   136  	client.Client
   137  	auth func() auth.Auth
   138  }
   139  
   140  func (a *authWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
   141  	// parse the options
   142  	var options client.CallOptions
   143  	for _, o := range opts {
   144  		o(&options)
   145  	}
   146  
   147  	// check to see if the authorization header has already been set.
   148  	// We dont't override the header unless the ServiceToken option has
   149  	// been specified or the header wasn't provided
   150  	if _, ok := metadata.Get(ctx, "Authorization"); ok && !options.ServiceToken {
   151  		return a.Client.Call(ctx, req, rsp, opts...)
   152  	}
   153  
   154  	// if auth is nil we won't be able to get an access token, so we execute
   155  	// the request without one.
   156  	aa := a.auth()
   157  	if aa == nil {
   158  		return a.Client.Call(ctx, req, rsp, opts...)
   159  	}
   160  
   161  	// set the namespace header if it has not been set (e.g. on a service to service request)
   162  	if _, ok := metadata.Get(ctx, "Micro-Namespace"); !ok {
   163  		ctx = metadata.Set(ctx, "Micro-Namespace", aa.Options().Namespace)
   164  	}
   165  
   166  	// check to see if we have a valid access token
   167  	aaOpts := aa.Options()
   168  	if aaOpts.Token != nil && !aaOpts.Token.Expired() {
   169  		ctx = metadata.Set(ctx, "Authorization", auth.BearerScheme+aaOpts.Token.AccessToken)
   170  		return a.Client.Call(ctx, req, rsp, opts...)
   171  	}
   172  
   173  	// call without an auth token
   174  	return a.Client.Call(ctx, req, rsp, opts...)
   175  }