dubbo.apache.org/dubbo-go/v3@v3.1.1/common/rpc_service.go (about) 1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package common 19 20 import ( 21 "context" 22 "reflect" 23 "strings" 24 "sync" 25 "unicode" 26 "unicode/utf8" 27 ) 28 29 import ( 30 "github.com/dubbogo/gost/log/logger" 31 32 perrors "github.com/pkg/errors" 33 ) 34 35 // RPCService the type alias of interface{} 36 type RPCService = interface{} 37 38 // ReferencedRPCService is the rpc service interface which wraps base Reference method. 39 // 40 // Reference method refers rpc service id or reference id. 41 type ReferencedRPCService interface { 42 Reference() string 43 } 44 45 // TriplePBService is the type alias of interface{} 46 type TriplePBService interface { 47 XXX_InterfaceName() string 48 } 49 50 // GetReference return the reference id of the service. 51 // If the service implemented the ReferencedRPCService interface, 52 // it will call the Reference method. If not, it will 53 // return the struct name as the reference id. 54 func GetReference(service RPCService) string { 55 if s, ok := service.(ReferencedRPCService); ok { 56 return s.Reference() 57 } 58 59 ref := "" 60 sType := reflect.TypeOf(service) 61 kind := sType.Kind() 62 switch kind { 63 case reflect.Struct: 64 ref = sType.Name() 65 case reflect.Ptr: 66 sName := sType.Elem().Name() 67 if sName != "" { 68 ref = sName 69 } else { 70 ref = sType.Elem().Field(0).Name 71 } 72 } 73 return ref 74 } 75 76 // AsyncCallbackService callback interface for async 77 type AsyncCallbackService interface { 78 CallBack(response CallbackResponse) 79 } 80 81 // CallbackResponse for different protocol 82 type CallbackResponse interface{} 83 84 // AsyncCallback async callback method 85 type AsyncCallback func(response CallbackResponse) 86 87 const ( 88 METHOD_MAPPER = "MethodMapper" 89 ) 90 91 var ( 92 // Precompute the reflect type for error. Can't use error directly 93 // because Typeof takes an empty interface value. This is annoying. 94 typeOfError = reflect.TypeOf((*error)(nil)).Elem() 95 96 // ServiceMap store description of service. 97 ServiceMap = &serviceMap{ 98 serviceMap: make(map[string]map[string]*Service), 99 interfaceMap: make(map[string][]*Service), 100 } 101 ) 102 103 // MethodType is description of service method. 104 type MethodType struct { 105 method reflect.Method 106 ctxType reflect.Type // request context 107 argsType []reflect.Type // args except ctx, include replyType if existing 108 replyType reflect.Type // return value, otherwise it is nil 109 } 110 111 // Method gets @m.method. 112 func (m *MethodType) Method() reflect.Method { 113 return m.method 114 } 115 116 // CtxType gets @m.ctxType. 117 func (m *MethodType) CtxType() reflect.Type { 118 return m.ctxType 119 } 120 121 // ArgsType gets @m.argsType. 122 func (m *MethodType) ArgsType() []reflect.Type { 123 return m.argsType 124 } 125 126 // ReplyType gets @m.replyType. 127 func (m *MethodType) ReplyType() reflect.Type { 128 return m.replyType 129 } 130 131 // SuiteContext transfers @ctx to reflect.Value type or get it from @m.ctxType. 132 func (m *MethodType) SuiteContext(ctx context.Context) reflect.Value { 133 if ctxV := reflect.ValueOf(ctx); ctxV.IsValid() { 134 return ctxV 135 } 136 return reflect.Zero(m.ctxType) 137 } 138 139 // Service is description of service 140 type Service struct { 141 name string 142 rcvr reflect.Value 143 rcvrType reflect.Type 144 methods map[string]*MethodType 145 } 146 147 // Method gets @s.methods. 148 func (s *Service) Method() map[string]*MethodType { 149 return s.methods 150 } 151 152 // Name will return service name 153 func (s *Service) Name() string { 154 return s.name 155 } 156 157 // RcvrType gets @s.rcvrType. 158 func (s *Service) RcvrType() reflect.Type { 159 return s.rcvrType 160 } 161 162 // Rcvr gets @s.rcvr. 163 func (s *Service) Rcvr() reflect.Value { 164 return s.rcvr 165 } 166 167 type serviceMap struct { 168 mutex sync.RWMutex // protects the serviceMap 169 serviceMap map[string]map[string]*Service // protocol -> service name -> service 170 interfaceMap map[string][]*Service // interface -> service 171 } 172 173 // GetService gets a service definition by protocol and name 174 func (sm *serviceMap) GetService(protocol, interfaceName, group, version string) *Service { 175 serviceKey := ServiceKey(interfaceName, group, version) 176 return sm.GetServiceByServiceKey(protocol, serviceKey) 177 } 178 179 // GetServiceByServiceKey gets a service definition by protocol and service key 180 func (sm *serviceMap) GetServiceByServiceKey(protocol, serviceKey string) *Service { 181 sm.mutex.RLock() 182 defer sm.mutex.RUnlock() 183 if s, ok := sm.serviceMap[protocol]; ok { 184 if srv, ok := s[serviceKey]; ok { 185 return srv 186 } 187 return nil 188 } 189 return nil 190 } 191 192 // GetInterface gets an interface definition by interface name 193 func (sm *serviceMap) GetInterface(interfaceName string) []*Service { 194 sm.mutex.RLock() 195 defer sm.mutex.RUnlock() 196 if s, ok := sm.interfaceMap[interfaceName]; ok { 197 return s 198 } 199 return nil 200 } 201 202 // Register registers a service by @interfaceName and @protocol 203 func (sm *serviceMap) Register(interfaceName, protocol, group, version string, rcvr RPCService) (string, error) { 204 if sm.serviceMap[protocol] == nil { 205 sm.serviceMap[protocol] = make(map[string]*Service) 206 } 207 if sm.interfaceMap[interfaceName] == nil { 208 sm.interfaceMap[interfaceName] = make([]*Service, 0, 16) 209 } 210 211 s := new(Service) 212 s.rcvrType = reflect.TypeOf(rcvr) 213 s.rcvr = reflect.ValueOf(rcvr) 214 sname := reflect.Indirect(s.rcvr).Type().Name() 215 if sname == "" { 216 s := "no service name for type " + s.rcvrType.String() 217 logger.Errorf(s) 218 return "", perrors.New(s) 219 } 220 if !isExported(sname) { 221 s := "type " + sname + " is not exported" 222 logger.Errorf(s) 223 return "", perrors.New(s) 224 } 225 226 sname = ServiceKey(interfaceName, group, version) 227 if server := sm.GetService(protocol, interfaceName, group, version); server != nil { 228 return "", perrors.New("service already defined: " + sname) 229 } 230 s.name = sname 231 s.methods = make(map[string]*MethodType) 232 233 // Install the methods 234 methods := "" 235 methods, s.methods = suitableMethods(s.rcvrType) 236 237 if len(s.methods) == 0 { 238 s := "type " + sname + " has no exported methods of suitable type" 239 logger.Errorf(s) 240 return "", perrors.New(s) 241 } 242 sm.mutex.Lock() 243 sm.serviceMap[protocol][s.name] = s 244 sm.interfaceMap[interfaceName] = append(sm.interfaceMap[interfaceName], s) 245 sm.mutex.Unlock() 246 247 return strings.TrimSuffix(methods, ","), nil 248 } 249 250 // UnRegister cancels a service by @interfaceName, @protocol and @serviceId 251 func (sm *serviceMap) UnRegister(interfaceName, protocol, serviceKey string) error { 252 if protocol == "" || serviceKey == "" { 253 return perrors.New("protocol or ServiceKey is nil") 254 } 255 256 var ( 257 err error 258 index = -1 259 svcs map[string]*Service 260 svrs []*Service 261 ok bool 262 ) 263 264 f := func() error { 265 sm.mutex.RLock() 266 defer sm.mutex.RUnlock() 267 svcs, ok = sm.serviceMap[protocol] 268 if !ok { 269 return perrors.New("no services for " + protocol) 270 } 271 s, ok := svcs[serviceKey] 272 if !ok { 273 return perrors.New("no service for " + serviceKey) 274 } 275 svrs, ok = sm.interfaceMap[interfaceName] 276 if !ok { 277 return perrors.New("no service for " + interfaceName) 278 } 279 for i, svr := range svrs { 280 if svr == s { 281 index = i 282 } 283 } 284 return nil 285 } 286 287 if err = f(); err != nil { 288 return err 289 } 290 291 sm.mutex.Lock() 292 defer sm.mutex.Unlock() 293 sm.interfaceMap[interfaceName] = make([]*Service, 0, len(svrs)) 294 for i := range svrs { 295 if i != index { 296 sm.interfaceMap[interfaceName] = append(sm.interfaceMap[interfaceName], svrs[i]) 297 } 298 } 299 delete(svcs, serviceKey) 300 if len(sm.serviceMap[protocol]) == 0 { 301 delete(sm.serviceMap, protocol) 302 } 303 304 return nil 305 } 306 307 // Is this an exported - upper case - name 308 func isExported(name string) bool { 309 s, _ := utf8.DecodeRuneInString(name) 310 return unicode.IsUpper(s) 311 } 312 313 // Is this type exported or a builtin? 314 func isExportedOrBuiltinType(t reflect.Type) bool { 315 for t.Kind() == reflect.Ptr { 316 t = t.Elem() 317 } 318 // PkgPath will be non-empty even for an exported type, 319 // so we need to check the type name as well. 320 return isExported(t.Name()) || t.PkgPath() == "" 321 } 322 323 // suitableMethods returns suitable Rpc methods of typ 324 func suitableMethods(typ reflect.Type) (string, map[string]*MethodType) { 325 methods := make(map[string]*MethodType) 326 var mts []string 327 logger.Debugf("[%s] NumMethod is %d", typ.String(), typ.NumMethod()) 328 method, ok := typ.MethodByName(METHOD_MAPPER) 329 var methodMapper map[string]string 330 if ok && method.Type.NumIn() == 1 && method.Type.NumOut() == 1 && method.Type.Out(0).String() == "map[string]string" { 331 methodMapper = method.Func.Call([]reflect.Value{reflect.New(typ.Elem())})[0].Interface().(map[string]string) 332 } 333 334 for m := 0; m < typ.NumMethod(); m++ { 335 method = typ.Method(m) 336 if mt := suiteMethod(method); mt != nil { 337 methodName, ok := methodMapper[method.Name] 338 if !ok { 339 methodName = method.Name 340 } 341 methods[methodName] = mt 342 mts = append(mts, methodName) 343 } 344 } 345 return strings.Join(mts, ","), methods 346 } 347 348 // suiteMethod returns a suitable Rpc methodType 349 func suiteMethod(method reflect.Method) *MethodType { 350 mtype := method.Type 351 mname := method.Name 352 inNum := mtype.NumIn() 353 outNum := mtype.NumOut() 354 355 // Method must be exported. 356 if method.PkgPath != "" { 357 return nil 358 } 359 360 var ( 361 replyType, ctxType reflect.Type 362 argsType []reflect.Type 363 ) 364 365 // Reference is used to define service reference, and method with prefix 'XXX' is generated by triple pb tool. 366 // SetGRPCServer is used for pb reflection. 367 // They should not to be checked. 368 if mname == "Reference" || mname == "SetGRPCServer" || strings.HasPrefix(mname, "XXX") { 369 return nil 370 } 371 372 if outNum != 1 && outNum != 2 { 373 logger.Warnf("method %s of mtype %v has wrong number of in out parameters %d; needs exactly 1/2", 374 mname, mtype.String(), outNum) 375 return nil 376 } 377 378 // The latest return type of the method must be error. 379 if returnType := mtype.Out(outNum - 1); returnType != typeOfError { 380 logger.Debugf(`"%s" method will not be exported because its last return type %v doesn't have error`, mname, returnType) 381 return nil 382 } 383 384 // replyType 385 if outNum == 2 { 386 replyType = mtype.Out(0) 387 if !isExportedOrBuiltinType(replyType) { 388 logger.Errorf("reply type of method %s not exported{%v}", mname, replyType) 389 return nil 390 } 391 } 392 393 index := 1 394 395 // ctxType 396 if inNum > 1 && mtype.In(1).String() == "context.Context" { 397 ctxType = mtype.In(1) 398 index = 2 399 } 400 401 for ; index < inNum; index++ { 402 argsType = append(argsType, mtype.In(index)) 403 // need not be a pointer. 404 if !isExportedOrBuiltinType(mtype.In(index)) { 405 logger.Errorf("argument type of method %q is not exported %v", mname, mtype.In(index)) 406 return nil 407 } 408 } 409 410 return &MethodType{method: method, argsType: argsType, replyType: replyType, ctxType: ctxType} 411 }