gitee.com/liuxuezhan/go-micro-v1.18.0@v1.0.0/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 "gitee.com/liuxuezhan/go-micro-v1.18.0/server" 18 "gitee.com/liuxuezhan/go-micro-v1.18.0/util/log" 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 log.Log("method", mname, "of", mtype, "has wrong number of ins:", mtype.NumIn()) 90 return nil 91 } 92 93 if stream { 94 // check stream type 95 streamType := reflect.TypeOf((*server.Stream)(nil)).Elem() 96 if !argType.Implements(streamType) { 97 log.Log(mname, "argument does not implement Streamer interface:", argType) 98 return nil 99 } 100 } else { 101 // if not stream check the replyType 102 103 // First arg need not be a pointer. 104 if !isExportedOrBuiltinType(argType) { 105 log.Log(mname, "argument type not exported:", argType) 106 return nil 107 } 108 109 if replyType.Kind() != reflect.Ptr { 110 log.Log("method", mname, "reply type not a pointer:", replyType) 111 return nil 112 } 113 114 // Reply type must be exported. 115 if !isExportedOrBuiltinType(replyType) { 116 log.Log("method", mname, "reply type not exported:", replyType) 117 return nil 118 } 119 } 120 121 // Endpoint() needs one out. 122 if mtype.NumOut() != 1 { 123 log.Log("method", mname, "has wrong number of outs:", mtype.NumOut()) 124 return nil 125 } 126 // The return type of the method must be error. 127 if returnType := mtype.Out(0); returnType != typeOfError { 128 log.Log("method", mname, "returns", returnType.String(), "not error") 129 return nil 130 } 131 return &methodType{method: method, ArgType: argType, ReplyType: replyType, ContextType: contextType, stream: stream} 132 } 133 134 func (server *rServer) register(rcvr interface{}) error { 135 server.mu.Lock() 136 defer server.mu.Unlock() 137 if server.serviceMap == nil { 138 server.serviceMap = make(map[string]*service) 139 } 140 s := new(service) 141 s.typ = reflect.TypeOf(rcvr) 142 s.rcvr = reflect.ValueOf(rcvr) 143 sname := reflect.Indirect(s.rcvr).Type().Name() 144 if sname == "" { 145 log.Fatal("rpc: no service name for type", s.typ.String()) 146 } 147 if !isExported(sname) { 148 s := "rpc Register: type " + sname + " is not exported" 149 log.Log(s) 150 return errors.New(s) 151 } 152 if _, present := server.serviceMap[sname]; present { 153 return errors.New("rpc: service already defined: " + sname) 154 } 155 s.name = sname 156 s.method = make(map[string]*methodType) 157 158 // Install the methods 159 for m := 0; m < s.typ.NumMethod(); m++ { 160 method := s.typ.Method(m) 161 if mt := prepareEndpoint(method); mt != nil { 162 s.method[method.Name] = mt 163 } 164 } 165 166 if len(s.method) == 0 { 167 s := "rpc Register: type " + sname + " has no exported methods of suitable type" 168 log.Log(s) 169 return errors.New(s) 170 } 171 server.serviceMap[s.name] = s 172 return nil 173 } 174 175 func (m *methodType) prepareContext(ctx context.Context) reflect.Value { 176 if contextv := reflect.ValueOf(ctx); contextv.IsValid() { 177 return contextv 178 } 179 return reflect.Zero(m.ContextType) 180 }