github.com/annwntech/go-micro/v2@v2.9.5/server/grpc/server.go (about) 1 package grpc 2 3 // Copyright 2009 The Go Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file. 6 // 7 // Meh, we need to get rid of this shit 8 9 import ( 10 "context" 11 "errors" 12 "reflect" 13 "sync" 14 "unicode" 15 "unicode/utf8" 16 17 "github.com/annwntech/go-micro/v2/logger" 18 "github.com/annwntech/go-micro/v2/server" 19 ) 20 21 var ( 22 // Precompute the reflect type for error. Can't use error directly 23 // because Typeof takes an empty interface value. This is annoying. 24 typeOfError = reflect.TypeOf((*error)(nil)).Elem() 25 ) 26 27 type methodType struct { 28 method reflect.Method 29 ArgType reflect.Type 30 ReplyType reflect.Type 31 ContextType reflect.Type 32 stream bool 33 } 34 35 type service struct { 36 name string // name of service 37 rcvr reflect.Value // receiver of methods for the service 38 typ reflect.Type // type of the receiver 39 method map[string]*methodType // registered methods 40 } 41 42 // server represents an RPC Server. 43 type rServer struct { 44 mu sync.Mutex // protects the serviceMap 45 serviceMap map[string]*service 46 } 47 48 // Is this an exported - upper case - name? 49 func isExported(name string) bool { 50 rune, _ := utf8.DecodeRuneInString(name) 51 return unicode.IsUpper(rune) 52 } 53 54 // Is this type exported or a builtin? 55 func isExportedOrBuiltinType(t reflect.Type) bool { 56 for t.Kind() == reflect.Ptr { 57 t = t.Elem() 58 } 59 // PkgPath will be non-empty even for an exported type, 60 // so we need to check the type name as well. 61 return isExported(t.Name()) || t.PkgPath() == "" 62 } 63 64 // prepareEndpoint() returns a methodType for the provided method or nil 65 // in case if the method was unsuitable. 66 func prepareEndpoint(method reflect.Method) *methodType { 67 mtype := method.Type 68 mname := method.Name 69 var replyType, argType, contextType reflect.Type 70 var stream bool 71 72 // Endpoint() must be exported. 73 if method.PkgPath != "" { 74 return nil 75 } 76 77 switch mtype.NumIn() { 78 case 3: 79 // assuming streaming 80 argType = mtype.In(2) 81 contextType = mtype.In(1) 82 stream = true 83 case 4: 84 // method that takes a context 85 argType = mtype.In(2) 86 replyType = mtype.In(3) 87 contextType = mtype.In(1) 88 default: 89 if logger.V(logger.ErrorLevel, logger.DefaultLogger) { 90 logger.Errorf("method %v of %v has wrong number of ins: %v", mname, mtype, mtype.NumIn()) 91 } 92 return nil 93 } 94 95 if stream { 96 // check stream type 97 streamType := reflect.TypeOf((*server.Stream)(nil)).Elem() 98 if !argType.Implements(streamType) { 99 if logger.V(logger.ErrorLevel, logger.DefaultLogger) { 100 logger.Errorf("%v argument does not implement Streamer interface: %v", mname, argType) 101 } 102 return nil 103 } 104 } else { 105 // if not stream check the replyType 106 107 // First arg need not be a pointer. 108 if !isExportedOrBuiltinType(argType) { 109 if logger.V(logger.ErrorLevel, logger.DefaultLogger) { 110 logger.Errorf("%v argument type not exported: %v", mname, argType) 111 } 112 return nil 113 } 114 115 if replyType.Kind() != reflect.Ptr { 116 if logger.V(logger.ErrorLevel, logger.DefaultLogger) { 117 logger.Errorf("method %v reply type not a pointer: %v", mname, replyType) 118 } 119 return nil 120 } 121 122 // Reply type must be exported. 123 if !isExportedOrBuiltinType(replyType) { 124 if logger.V(logger.ErrorLevel, logger.DefaultLogger) { 125 logger.Errorf("method %v reply type not exported: %v", mname, replyType) 126 } 127 return nil 128 } 129 } 130 131 // Endpoint() needs one out. 132 if mtype.NumOut() != 1 { 133 if logger.V(logger.ErrorLevel, logger.DefaultLogger) { 134 logger.Errorf("method %v has wrong number of outs: %v", mname, mtype.NumOut()) 135 } 136 return nil 137 } 138 // The return type of the method must be error. 139 if returnType := mtype.Out(0); returnType != typeOfError { 140 if logger.V(logger.ErrorLevel, logger.DefaultLogger) { 141 logger.Errorf("method %v returns %v not error", mname, returnType.String()) 142 } 143 return nil 144 } 145 return &methodType{method: method, ArgType: argType, ReplyType: replyType, ContextType: contextType, stream: stream} 146 } 147 148 func (server *rServer) register(rcvr interface{}) error { 149 server.mu.Lock() 150 defer server.mu.Unlock() 151 if server.serviceMap == nil { 152 server.serviceMap = make(map[string]*service) 153 } 154 s := new(service) 155 s.typ = reflect.TypeOf(rcvr) 156 s.rcvr = reflect.ValueOf(rcvr) 157 sname := reflect.Indirect(s.rcvr).Type().Name() 158 if sname == "" { 159 logger.Fatalf("rpc: no service name for type %v", s.typ.String()) 160 } 161 if !isExported(sname) { 162 s := "rpc Register: type " + sname + " is not exported" 163 if logger.V(logger.ErrorLevel, logger.DefaultLogger) { 164 logger.Error(s) 165 } 166 return errors.New(s) 167 } 168 if _, present := server.serviceMap[sname]; present { 169 return errors.New("rpc: service already defined: " + sname) 170 } 171 s.name = sname 172 s.method = make(map[string]*methodType) 173 174 // Install the methods 175 for m := 0; m < s.typ.NumMethod(); m++ { 176 method := s.typ.Method(m) 177 if mt := prepareEndpoint(method); mt != nil { 178 s.method[method.Name] = mt 179 } 180 } 181 182 if len(s.method) == 0 { 183 s := "rpc Register: type " + sname + " has no exported methods of suitable type" 184 if logger.V(logger.ErrorLevel, logger.DefaultLogger) { 185 logger.Error(s) 186 } 187 return errors.New(s) 188 } 189 server.serviceMap[s.name] = s 190 return nil 191 } 192 193 func (m *methodType) prepareContext(ctx context.Context) reflect.Value { 194 if contextv := reflect.ValueOf(ctx); contextv.IsValid() { 195 return contextv 196 } 197 return reflect.Zero(m.ContextType) 198 }