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