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