github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/service/server/grpc/subscriber.go (about) 1 // Copyright 2020 Asim Aslam 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // Original source: github.com/micro/go-micro/v3/server/grpc/subscriber.go 16 17 package grpc 18 19 import ( 20 "context" 21 "fmt" 22 "reflect" 23 "runtime/debug" 24 "strings" 25 26 "github.com/tickoalcantara12/micro/v3/service/broker" 27 "github.com/tickoalcantara12/micro/v3/service/context/metadata" 28 "github.com/tickoalcantara12/micro/v3/service/errors" 29 "github.com/tickoalcantara12/micro/v3/service/logger" 30 "github.com/tickoalcantara12/micro/v3/service/registry" 31 "github.com/tickoalcantara12/micro/v3/service/server" 32 ) 33 34 const ( 35 subSig = "func(context.Context, interface{}) error" 36 ) 37 38 type handler struct { 39 method reflect.Value 40 reqType reflect.Type 41 ctxType reflect.Type 42 } 43 44 type subscriber struct { 45 topic string 46 rcvr reflect.Value 47 typ reflect.Type 48 subscriber interface{} 49 handlers []*handler 50 endpoints []*registry.Endpoint 51 opts server.SubscriberOptions 52 } 53 54 func newSubscriber(topic string, sub interface{}, opts ...server.SubscriberOption) server.Subscriber { 55 options := server.SubscriberOptions{ 56 AutoAck: true, 57 } 58 59 for _, o := range opts { 60 o(&options) 61 } 62 63 var endpoints []*registry.Endpoint 64 var handlers []*handler 65 66 if typ := reflect.TypeOf(sub); typ.Kind() == reflect.Func { 67 h := &handler{ 68 method: reflect.ValueOf(sub), 69 } 70 71 switch typ.NumIn() { 72 case 1: 73 h.reqType = typ.In(0) 74 case 2: 75 h.ctxType = typ.In(0) 76 h.reqType = typ.In(1) 77 } 78 79 handlers = append(handlers, h) 80 81 endpoints = append(endpoints, ®istry.Endpoint{ 82 Name: "Func", 83 Request: extractSubValue(typ), 84 Metadata: map[string]string{ 85 "topic": topic, 86 "subscriber": "true", 87 }, 88 }) 89 } else { 90 hdlr := reflect.ValueOf(sub) 91 name := reflect.Indirect(hdlr).Type().Name() 92 93 for m := 0; m < typ.NumMethod(); m++ { 94 method := typ.Method(m) 95 h := &handler{ 96 method: method.Func, 97 } 98 99 switch method.Type.NumIn() { 100 case 2: 101 h.reqType = method.Type.In(1) 102 case 3: 103 h.ctxType = method.Type.In(1) 104 h.reqType = method.Type.In(2) 105 } 106 107 handlers = append(handlers, h) 108 109 endpoints = append(endpoints, ®istry.Endpoint{ 110 Name: name + "." + method.Name, 111 Request: extractSubValue(method.Type), 112 Metadata: map[string]string{ 113 "topic": topic, 114 "subscriber": "true", 115 }, 116 }) 117 } 118 } 119 120 return &subscriber{ 121 rcvr: reflect.ValueOf(sub), 122 typ: reflect.TypeOf(sub), 123 topic: topic, 124 subscriber: sub, 125 handlers: handlers, 126 endpoints: endpoints, 127 opts: options, 128 } 129 } 130 131 func validateSubscriber(sub server.Subscriber) error { 132 typ := reflect.TypeOf(sub.Subscriber()) 133 var argType reflect.Type 134 135 if typ.Kind() == reflect.Func { 136 name := "Func" 137 switch typ.NumIn() { 138 case 2: 139 argType = typ.In(1) 140 default: 141 return fmt.Errorf("subscriber %v takes wrong number of args: %v required signature %s", name, typ.NumIn(), subSig) 142 } 143 if !isExportedOrBuiltinType(argType) { 144 return fmt.Errorf("subscriber %v argument type not exported: %v", name, argType) 145 } 146 if typ.NumOut() != 1 { 147 return fmt.Errorf("subscriber %v has wrong number of outs: %v require signature %s", 148 name, typ.NumOut(), subSig) 149 } 150 if returnType := typ.Out(0); returnType != typeOfError { 151 return fmt.Errorf("subscriber %v returns %v not error", name, returnType.String()) 152 } 153 } else { 154 hdlr := reflect.ValueOf(sub.Subscriber()) 155 name := reflect.Indirect(hdlr).Type().Name() 156 157 for m := 0; m < typ.NumMethod(); m++ { 158 method := typ.Method(m) 159 160 switch method.Type.NumIn() { 161 case 3: 162 argType = method.Type.In(2) 163 default: 164 return fmt.Errorf("subscriber %v.%v takes wrong number of args: %v required signature %s", 165 name, method.Name, method.Type.NumIn(), subSig) 166 } 167 168 if !isExportedOrBuiltinType(argType) { 169 return fmt.Errorf("%v argument type not exported: %v", name, argType) 170 } 171 if method.Type.NumOut() != 1 { 172 return fmt.Errorf( 173 "subscriber %v.%v has wrong number of outs: %v require signature %s", 174 name, method.Name, method.Type.NumOut(), subSig) 175 } 176 if returnType := method.Type.Out(0); returnType != typeOfError { 177 return fmt.Errorf("subscriber %v.%v returns %v not error", name, method.Name, returnType.String()) 178 } 179 } 180 } 181 182 return nil 183 } 184 185 func (g *grpcServer) createSubHandler(sb *subscriber, opts server.Options) broker.Handler { 186 return func(msg *broker.Message) (err error) { 187 188 defer func() { 189 if r := recover(); r != nil { 190 if logger.V(logger.ErrorLevel, logger.DefaultLogger) { 191 logger.Error("panic recovered: ", r) 192 logger.Error(string(debug.Stack())) 193 } 194 err = errors.InternalServerError(g.opts.Name+".subscriber", "panic recovered: %v", r) 195 } 196 }() 197 198 // if we don't have headers, create empty map 199 if msg.Header == nil { 200 msg.Header = make(map[string]string) 201 } 202 203 ct := msg.Header["Content-Type"] 204 if len(ct) == 0 { 205 msg.Header["Content-Type"] = defaultContentType 206 ct = defaultContentType 207 } 208 cf, err := g.newGRPCCodec(ct) 209 if err != nil { 210 return err 211 } 212 213 hdr := make(map[string]string, len(msg.Header)) 214 for k, v := range msg.Header { 215 hdr[k] = v 216 } 217 delete(hdr, "Content-Type") 218 ctx := metadata.NewContext(context.Background(), hdr) 219 220 results := make(chan error, len(sb.handlers)) 221 222 for i := 0; i < len(sb.handlers); i++ { 223 handler := sb.handlers[i] 224 225 var isVal bool 226 var req reflect.Value 227 228 if handler.reqType.Kind() == reflect.Ptr { 229 req = reflect.New(handler.reqType.Elem()) 230 } else { 231 req = reflect.New(handler.reqType) 232 isVal = true 233 } 234 if isVal { 235 req = req.Elem() 236 } 237 238 if err = cf.Unmarshal(msg.Body, req.Interface()); err != nil { 239 return err 240 } 241 242 fn := func(ctx context.Context, msg server.Message) error { 243 var vals []reflect.Value 244 if sb.typ.Kind() != reflect.Func { 245 vals = append(vals, sb.rcvr) 246 } 247 if handler.ctxType != nil { 248 vals = append(vals, reflect.ValueOf(ctx)) 249 } 250 251 vals = append(vals, reflect.ValueOf(msg.Payload())) 252 253 returnValues := handler.method.Call(vals) 254 if rerr := returnValues[0].Interface(); rerr != nil { 255 return rerr.(error) 256 } 257 return nil 258 } 259 260 for i := len(opts.SubWrappers); i > 0; i-- { 261 fn = opts.SubWrappers[i-1](fn) 262 } 263 264 if g.wg != nil { 265 g.wg.Add(1) 266 } 267 go func() { 268 if g.wg != nil { 269 defer g.wg.Done() 270 } 271 err := fn(ctx, &rpcMessage{ 272 topic: sb.topic, 273 contentType: ct, 274 payload: req.Interface(), 275 header: msg.Header, 276 body: msg.Body, 277 }) 278 results <- err 279 }() 280 } 281 var errors []string 282 for i := 0; i < len(sb.handlers); i++ { 283 if rerr := <-results; rerr != nil { 284 errors = append(errors, rerr.Error()) 285 } 286 } 287 if len(errors) > 0 { 288 err = fmt.Errorf("subscriber error: %s", strings.Join(errors, "\n")) 289 } 290 291 return err 292 } 293 } 294 295 func (s *subscriber) Topic() string { 296 return s.topic 297 } 298 299 func (s *subscriber) Subscriber() interface{} { 300 return s.subscriber 301 } 302 303 func (s *subscriber) Endpoints() []*registry.Endpoint { 304 return s.endpoints 305 } 306 307 func (s *subscriber) Options() server.SubscriberOptions { 308 return s.opts 309 }