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