github.com/volts-dev/volts@v0.0.0-20240120094013-5e9c65924106/router/subscriber.go (about) 1 package router 2 3 import ( 4 "context" 5 "fmt" 6 "hash/crc32" 7 "reflect" 8 "strings" 9 10 "github.com/volts-dev/utils" 11 "github.com/volts-dev/volts/registry" 12 ) 13 14 type ( 15 SubscriberOption func(*SubscriberConfig) 16 17 SubscriberConfig struct { 18 Context context.Context 19 Queue string 20 // AutoAck defaults to true. When a handler returns 21 // with a nil error the message is acked. 22 AutoAck bool 23 Internal bool 24 } 25 /* 26 handler struct { 27 method reflect.Value 28 reqType reflect.Type 29 ctxType reflect.Type 30 } 31 */ 32 subscriber struct { 33 topic string 34 rcvr reflect.Value 35 typ reflect.Type 36 subscriber interface{} // 原型 subscriber 37 handlers []*handler 38 endpoints []*registry.Endpoint 39 config SubscriberConfig 40 } 41 42 TSubscriberContext struct { 43 } 44 // Subscriber interface represents a subscription to a given topic using 45 // a specific subscriber function or object with endpoints. It mirrors 46 // the handler in its behavior. 47 ISubscriber interface { 48 Topic() string 49 Subscriber() interface{} // 原型 50 Endpoints() []*registry.Endpoint 51 Handlers() []*handler 52 Config() SubscriberConfig 53 } 54 ) 55 56 func validateSubscriber(sub ISubscriber) error { 57 return nil 58 } 59 60 func extractValue(v reflect.Type, d int) *registry.Value { 61 if d == 3 { 62 return nil 63 } 64 if v == nil { 65 return nil 66 } 67 68 if v.Kind() == reflect.Ptr { 69 v = v.Elem() 70 } 71 72 arg := ®istry.Value{ 73 Name: v.Name(), 74 Type: v.Name(), 75 } 76 77 switch v.Kind() { 78 case reflect.Struct: 79 for i := 0; i < v.NumField(); i++ { 80 f := v.Field(i) 81 val := extractValue(f.Type, d+1) 82 if val == nil { 83 continue 84 } 85 86 // if we can find a json tag use it 87 if tags := f.Tag.Get("json"); len(tags) > 0 { 88 parts := strings.Split(tags, ",") 89 val.Name = parts[0] 90 } 91 92 // if there's no name default it 93 if len(val.Name) == 0 { 94 val.Name = v.Field(i).Name 95 } 96 97 arg.Values = append(arg.Values, val) 98 } 99 case reflect.Slice: 100 p := v.Elem() 101 if p.Kind() == reflect.Ptr { 102 p = p.Elem() 103 } 104 arg.Type = "[]" + p.Name() 105 val := extractValue(v.Elem(), d+1) 106 if val != nil { 107 arg.Values = append(arg.Values, val) 108 } 109 } 110 111 return arg 112 } 113 114 func extractSubValue(typ reflect.Type) *registry.Value { 115 var reqType reflect.Type 116 switch typ.NumIn() { 117 case 1: 118 reqType = typ.In(0) 119 case 2: 120 reqType = typ.In(1) 121 case 3: 122 reqType = typ.In(2) 123 default: 124 return nil 125 } 126 return extractValue(reqType, 0) 127 } 128 129 func newSubscriber(topic string, sub any, opts ...SubscriberOption) ISubscriber { 130 cfg := SubscriberConfig{ 131 AutoAck: true, 132 } 133 134 for _, o := range opts { 135 o(&cfg) 136 } 137 138 handlers, endpoints := parseSubscriber(topic, sub, opts...) 139 return &subscriber{ 140 rcvr: reflect.ValueOf(sub), 141 typ: reflect.TypeOf(sub), 142 topic: topic, 143 subscriber: sub, 144 handlers: handlers, 145 endpoints: endpoints, 146 config: cfg, 147 } 148 } 149 150 func parseSubscriber(topic string, sub any, opts ...SubscriberOption) (handlers []*handler, endpoints []*registry.Endpoint) { 151 var hd *handler 152 switch v := sub.(type) { 153 case func(*TSubscriberContext): 154 hd = &handler{ 155 Id: int(crc32.ChecksumIEEE([]byte(topic))), 156 Manager: deflautHandlerManager, 157 Config: &ControllerConfig{}, 158 Type: SubscriberHandler, 159 pos: -1, 160 161 ctrlType: reflect.TypeOf(v), 162 ctrlValue: reflect.ValueOf(v), 163 } 164 165 hd.TransportType = SubscribeHandler 166 hd.funcs = append(hd.funcs, &handle{IsFunc: true, SubFunc: v}) 167 168 handlers = append(handlers, hd) 169 endpoints = append(endpoints, ®istry.Endpoint{ 170 Name: "Func", 171 Request: extractSubValue(hd.ctrlType), 172 Metadata: map[string]string{ 173 "topic": topic, 174 "subscriber": "true", 175 }, 176 }) 177 178 return 179 default: 180 // init Value and Type 181 ctrlValue, ok := sub.(reflect.Value) 182 if !ok { 183 ctrlValue = reflect.ValueOf(sub) 184 } 185 ctrlType := ctrlValue.Type() 186 kind := ctrlType.Kind() 187 switch kind { 188 case reflect.Struct, reflect.Ptr: 189 // transfer prt to struct 190 if kind == reflect.Ptr { 191 ctrlValue = ctrlValue.Elem() 192 ctrlType = ctrlType.Elem() 193 } 194 // 获取控制器名称 195 var objName string 196 if v, ok := sub.(IString); ok { 197 objName = v.String() 198 } else { 199 objName = utils.DotCasedName(utils.Obj2Name(v)) 200 } 201 202 var name string 203 var method reflect.Value 204 for i := 0; i < ctrlType.NumMethod(); i++ { 205 // get the method information from the ctrl Type 206 name = ctrlType.Method(i).Name 207 method = ctrlType.Method(i).Func 208 209 // 忽略非handler方法 210 if method.Type().NumIn() <= 1 { 211 continue 212 } 213 214 if method.CanInterface() { 215 hds, eps := parseSubscriber(objName+"."+name, method, opts...) 216 217 handlers = append(handlers, hds...) 218 endpoints = append(endpoints, eps...) 219 } 220 221 } 222 // the end of the struct mapping 223 return 224 case reflect.Func: 225 // Method must be exported. 226 if ctrlType.PkgPath() != "" { 227 log.Fatalf("Method %s must be exported", v) 228 return 229 } 230 231 hd = &handler{ 232 Id: int(crc32.ChecksumIEEE([]byte(topic))), 233 Manager: deflautHandlerManager, 234 Config: &ControllerConfig{}, 235 Type: SubscriberHandler, 236 pos: -1, 237 238 ctrlType: ctrlValue.Type(), 239 ctrlValue: ctrlValue, 240 } 241 hd.Name = fmt.Sprintf("%s-%d", topic, hd.Id) 242 243 handlers = append(handlers, hd) 244 endpoints = append(endpoints, ®istry.Endpoint{ 245 Name: hd.Name, 246 Request: extractSubValue(hd.ctrlType), 247 Metadata: map[string]string{ 248 "topic": topic, 249 "subscriber": "true", 250 }, 251 }) 252 default: 253 log.Fatal("controller must be func or bound method") 254 } 255 } 256 257 return handlers, endpoints 258 } 259 260 func (s *subscriber) Topic() string { 261 return s.topic 262 } 263 264 func (s *subscriber) Subscriber() interface{} { 265 return s.subscriber 266 } 267 268 func (s *subscriber) Endpoints() []*registry.Endpoint { 269 return s.endpoints 270 } 271 func (s *subscriber) Handlers() []*handler { 272 return s.handlers 273 } 274 275 func (s *subscriber) Config() SubscriberConfig { 276 return s.config 277 }