github.com/nyan233/littlerpc@v0.4.6-0.20230316182519-0c8d5c48abaf/core/server/reflection.go (about)

     1  package server
     2  
     3  import (
     4  	"context"
     5  	"github.com/nyan233/littlerpc/core/common/errorhandler"
     6  	"github.com/nyan233/littlerpc/core/common/metadata"
     7  	"github.com/nyan233/littlerpc/core/middle/codec"
     8  	"github.com/nyan233/littlerpc/core/middle/packer"
     9  	"reflect"
    10  	_ "unsafe"
    11  )
    12  
    13  var (
    14  	//go:linkname codecViewer github.com/nyan233/littlerpc/core/middle/codec.codecCollection
    15  	codecViewer map[string]codec.Codec
    16  	//go:linkname packerViewer github.com/nyan233/littlerpc/core/middle/packer.packerCollection
    17  	packerViewer map[string]packer.Packer
    18  )
    19  
    20  type MethodTable struct {
    21  	SourceName string
    22  	Table      []string
    23  }
    24  
    25  // ArgumentType 参数类型 == map[string]interface{}表示struct,interface{}里的参数也同理 == string时表示其它类型
    26  type ArgumentType struct {
    27  	Kind string      `json:"kind"`
    28  	Type interface{} `json:"type"`
    29  }
    30  
    31  // LittleRpcReflection 反射服务
    32  type LittleRpcReflection struct {
    33  	rpcServer *Server
    34  }
    35  
    36  func (l *LittleRpcReflection) MethodTable(ctx context.Context, sourceName string) (*MethodTable, error) {
    37  	source, ok := l.rpcServer.sources.LoadOk(sourceName)
    38  	if !ok {
    39  		return nil, errorhandler.ServiceNotfound
    40  	}
    41  	mt := &MethodTable{
    42  		SourceName: sourceName,
    43  		Table:      nil,
    44  	}
    45  	for methodName := range source.ProcessSet {
    46  		mt.Table = append(mt.Table, methodName)
    47  	}
    48  	return mt, nil
    49  }
    50  
    51  func (l *LittleRpcReflection) AllInstance(ctx context.Context) (map[string]string, error) {
    52  	mp := make(map[string]string, 4)
    53  	l.rpcServer.sources.Range(func(key string, value *metadata.Source) bool {
    54  		mp[key] = value.InstanceType.Name()
    55  		return true
    56  	})
    57  	return mp, nil
    58  }
    59  
    60  func (l *LittleRpcReflection) AllCodec(ctx context.Context) ([]string, error) {
    61  	codecSchemeSet := make([]string, 0, len(codecViewer))
    62  	for k := range codecViewer {
    63  		codecSchemeSet = append(codecSchemeSet, k)
    64  	}
    65  	return codecSchemeSet, nil
    66  }
    67  
    68  func (l *LittleRpcReflection) AllPacker(ctx context.Context) ([]string, error) {
    69  	packerSchemeSet := make([]string, 0, len(packerViewer))
    70  	for k := range packerViewer {
    71  		packerSchemeSet = append(packerSchemeSet, k)
    72  	}
    73  	return packerSchemeSet, nil
    74  }
    75  
    76  func (l *LittleRpcReflection) MethodArgumentType(ctx context.Context, serviceName string) ([]ArgumentType, error) {
    77  	service, ok := l.rpcServer.services.LoadOk(serviceName)
    78  	if !ok {
    79  		return nil, errorhandler.ServiceNotfound
    80  	}
    81  	argDesc := make([]ArgumentType, 0, 4)
    82  	typ := service.Value.Type()
    83  	for i := 0; i < typ.NumIn(); i++ {
    84  		in := typ.In(i)
    85  		argDesc = append(argDesc, getArgumentType(in))
    86  	}
    87  	return argDesc, nil
    88  }
    89  
    90  func getArgumentType(typ reflect.Type) ArgumentType {
    91  	switch typ.Kind() {
    92  	case reflect.Struct:
    93  		fieldMap := make(map[string]interface{}, typ.NumField())
    94  		for i := 0; i < typ.NumField(); i++ {
    95  			field := typ.Field(i)
    96  			fieldMap[field.Name] = getArgumentType(field.Type)
    97  		}
    98  		return ArgumentType{
    99  			Kind: "struct",
   100  			Type: fieldMap,
   101  		}
   102  	case reflect.Interface:
   103  		return ArgumentType{
   104  			Kind: "interface",
   105  			Type: typ.PkgPath() + "." + typ.Name(),
   106  		}
   107  	case reflect.Slice:
   108  		return ArgumentType{
   109  			Kind: "array",
   110  			Type: getTypeName(typ),
   111  		}
   112  	case reflect.Map:
   113  		return ArgumentType{
   114  			Kind: "map",
   115  			Type: struct {
   116  				Key   string
   117  				Value string
   118  			}{
   119  				Key:   getTypeName(typ.Key()),
   120  				Value: getTypeName(typ.Elem()),
   121  			},
   122  		}
   123  	case reflect.String:
   124  		return ArgumentType{
   125  			Kind: "string",
   126  			Type: typ.Name(),
   127  		}
   128  	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int,
   129  		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   130  		return ArgumentType{
   131  			Kind: "integer",
   132  			Type: typ.Name(),
   133  		}
   134  	case reflect.Pointer:
   135  		return getArgumentType(typ.Elem())
   136  	default:
   137  		return ArgumentType{
   138  			Kind: "unknown",
   139  			Type: nil,
   140  		}
   141  	}
   142  }
   143  
   144  func getTypeName(typ reflect.Type) string {
   145  	switch typ.Kind() {
   146  	case reflect.Slice:
   147  		return "[]" + getTypeName(typ.Elem())
   148  	case reflect.Pointer:
   149  		return "*" + getTypeName(typ.Elem())
   150  	case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int,
   151  		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   152  		return "integer"
   153  	case reflect.Interface:
   154  		return typ.PkgPath() + "." + typ.Name()
   155  	case reflect.Map:
   156  		return "Map[" + getTypeName(typ.Key()) + "," + getTypeName(typ.Elem()) + "]"
   157  	default:
   158  		return typ.Name()
   159  	}
   160  }