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, &registry.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, &registry.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  }