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 }