go-micro.dev/v5@v5.12.0/server/grpc/extractor.go (about)

     1  package grpc
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"strings"
     7  
     8  	"go-micro.dev/v5/registry"
     9  )
    10  
    11  func extractValue(v reflect.Type, d int) *registry.Value {
    12  	if d == 3 {
    13  		return nil
    14  	}
    15  	if v == nil {
    16  		return nil
    17  	}
    18  
    19  	if v.Kind() == reflect.Ptr {
    20  		v = v.Elem()
    21  	}
    22  
    23  	arg := &registry.Value{
    24  		Name: v.Name(),
    25  		Type: v.Name(),
    26  	}
    27  
    28  	switch v.Kind() {
    29  	case reflect.Struct:
    30  		for i := 0; i < v.NumField(); i++ {
    31  			f := v.Field(i)
    32  			if f.PkgPath != "" {
    33  				continue
    34  			}
    35  			val := extractValue(f.Type, d+1)
    36  			if val == nil {
    37  				continue
    38  			}
    39  
    40  			// if we can find a json tag use it
    41  			if tags := f.Tag.Get("json"); len(tags) > 0 {
    42  				parts := strings.Split(tags, ",")
    43  				if parts[0] == "-" || parts[0] == "omitempty" {
    44  					continue
    45  				}
    46  				val.Name = parts[0]
    47  			}
    48  
    49  			// if there's no name default it
    50  			if len(val.Name) == 0 {
    51  				val.Name = v.Field(i).Name
    52  			}
    53  
    54  			arg.Values = append(arg.Values, val)
    55  		}
    56  	case reflect.Slice:
    57  		p := v.Elem()
    58  		if p.Kind() == reflect.Ptr {
    59  			p = p.Elem()
    60  		}
    61  		arg.Type = "[]" + p.Name()
    62  	}
    63  
    64  	return arg
    65  }
    66  
    67  func extractEndpoint(method reflect.Method) *registry.Endpoint {
    68  	if method.PkgPath != "" {
    69  		return nil
    70  	}
    71  
    72  	var rspType, reqType reflect.Type
    73  	var stream bool
    74  	mt := method.Type
    75  
    76  	switch mt.NumIn() {
    77  	case 3:
    78  		reqType = mt.In(1)
    79  		rspType = mt.In(2)
    80  	case 4:
    81  		reqType = mt.In(2)
    82  		rspType = mt.In(3)
    83  	default:
    84  		return nil
    85  	}
    86  
    87  	// are we dealing with a stream?
    88  	switch rspType.Kind() {
    89  	case reflect.Func, reflect.Interface:
    90  		stream = true
    91  	}
    92  
    93  	request := extractValue(reqType, 0)
    94  	response := extractValue(rspType, 0)
    95  
    96  	ep := &registry.Endpoint{
    97  		Name:     method.Name,
    98  		Request:  request,
    99  		Response: response,
   100  		Metadata: make(map[string]string),
   101  	}
   102  
   103  	if stream {
   104  		ep.Metadata = map[string]string{
   105  			"stream": fmt.Sprintf("%v", stream),
   106  		}
   107  	}
   108  
   109  	return ep
   110  }
   111  
   112  func extractSubValue(typ reflect.Type) *registry.Value {
   113  	var reqType reflect.Type
   114  	switch typ.NumIn() {
   115  	case 1:
   116  		reqType = typ.In(0)
   117  	case 2:
   118  		reqType = typ.In(1)
   119  	case 3:
   120  		reqType = typ.In(2)
   121  	default:
   122  		return nil
   123  	}
   124  	return extractValue(reqType, 0)
   125  }