github.com/micro/go-micro/v2@v2.9.1/server/subscriber.go (about) 1 package server 2 3 import ( 4 "fmt" 5 "reflect" 6 7 "github.com/micro/go-micro/v2/registry" 8 ) 9 10 const ( 11 subSig = "func(context.Context, interface{}) error" 12 ) 13 14 type handler struct { 15 method reflect.Value 16 reqType reflect.Type 17 ctxType reflect.Type 18 } 19 20 type subscriber struct { 21 topic string 22 rcvr reflect.Value 23 typ reflect.Type 24 subscriber interface{} 25 handlers []*handler 26 endpoints []*registry.Endpoint 27 opts SubscriberOptions 28 } 29 30 func newSubscriber(topic string, sub interface{}, opts ...SubscriberOption) Subscriber { 31 options := SubscriberOptions{ 32 AutoAck: true, 33 } 34 35 for _, o := range opts { 36 o(&options) 37 } 38 39 var endpoints []*registry.Endpoint 40 var handlers []*handler 41 42 if typ := reflect.TypeOf(sub); typ.Kind() == reflect.Func { 43 h := &handler{ 44 method: reflect.ValueOf(sub), 45 } 46 47 switch typ.NumIn() { 48 case 1: 49 h.reqType = typ.In(0) 50 case 2: 51 h.ctxType = typ.In(0) 52 h.reqType = typ.In(1) 53 } 54 55 handlers = append(handlers, h) 56 57 endpoints = append(endpoints, ®istry.Endpoint{ 58 Name: "Func", 59 Request: extractSubValue(typ), 60 Metadata: map[string]string{ 61 "topic": topic, 62 "subscriber": "true", 63 }, 64 }) 65 } else { 66 hdlr := reflect.ValueOf(sub) 67 name := reflect.Indirect(hdlr).Type().Name() 68 69 for m := 0; m < typ.NumMethod(); m++ { 70 method := typ.Method(m) 71 h := &handler{ 72 method: method.Func, 73 } 74 75 switch method.Type.NumIn() { 76 case 2: 77 h.reqType = method.Type.In(1) 78 case 3: 79 h.ctxType = method.Type.In(1) 80 h.reqType = method.Type.In(2) 81 } 82 83 handlers = append(handlers, h) 84 85 endpoints = append(endpoints, ®istry.Endpoint{ 86 Name: name + "." + method.Name, 87 Request: extractSubValue(method.Type), 88 Metadata: map[string]string{ 89 "topic": topic, 90 "subscriber": "true", 91 }, 92 }) 93 } 94 } 95 96 return &subscriber{ 97 rcvr: reflect.ValueOf(sub), 98 typ: reflect.TypeOf(sub), 99 topic: topic, 100 subscriber: sub, 101 handlers: handlers, 102 endpoints: endpoints, 103 opts: options, 104 } 105 } 106 107 func validateSubscriber(sub Subscriber) error { 108 typ := reflect.TypeOf(sub.Subscriber()) 109 var argType reflect.Type 110 111 if typ.Kind() == reflect.Func { 112 name := "Func" 113 switch typ.NumIn() { 114 case 2: 115 argType = typ.In(1) 116 default: 117 return fmt.Errorf("subscriber %v takes wrong number of args: %v required signature %s", name, typ.NumIn(), subSig) 118 } 119 if !isExportedOrBuiltinType(argType) { 120 return fmt.Errorf("subscriber %v argument type not exported: %v", name, argType) 121 } 122 if typ.NumOut() != 1 { 123 return fmt.Errorf("subscriber %v has wrong number of outs: %v require signature %s", 124 name, typ.NumOut(), subSig) 125 } 126 if returnType := typ.Out(0); returnType != typeOfError { 127 return fmt.Errorf("subscriber %v returns %v not error", name, returnType.String()) 128 } 129 } else { 130 hdlr := reflect.ValueOf(sub.Subscriber()) 131 name := reflect.Indirect(hdlr).Type().Name() 132 133 for m := 0; m < typ.NumMethod(); m++ { 134 method := typ.Method(m) 135 136 switch method.Type.NumIn() { 137 case 3: 138 argType = method.Type.In(2) 139 default: 140 return fmt.Errorf("subscriber %v.%v takes wrong number of args: %v required signature %s", 141 name, method.Name, method.Type.NumIn(), subSig) 142 } 143 144 if !isExportedOrBuiltinType(argType) { 145 return fmt.Errorf("%v argument type not exported: %v", name, argType) 146 } 147 if method.Type.NumOut() != 1 { 148 return fmt.Errorf( 149 "subscriber %v.%v has wrong number of outs: %v require signature %s", 150 name, method.Name, method.Type.NumOut(), subSig) 151 } 152 if returnType := method.Type.Out(0); returnType != typeOfError { 153 return fmt.Errorf("subscriber %v.%v returns %v not error", name, method.Name, returnType.String()) 154 } 155 } 156 } 157 158 return nil 159 } 160 161 func (s *subscriber) Topic() string { 162 return s.topic 163 } 164 165 func (s *subscriber) Subscriber() interface{} { 166 return s.subscriber 167 } 168 169 func (s *subscriber) Endpoints() []*registry.Endpoint { 170 return s.endpoints 171 } 172 173 func (s *subscriber) Options() SubscriberOptions { 174 return s.opts 175 }