github.com/swiftstack/ProxyFS@v0.0.0-20210203235616-4017c267d62f/retryrpc/svrmap.go (about) 1 // Copyright (c) 2015-2021, NVIDIA CORPORATION. 2 // SPDX-License-Identifier: Apache-2.0 3 4 package retryrpc 5 6 import ( 7 "errors" 8 "reflect" 9 "unicode" 10 "unicode/utf8" 11 ) 12 13 var typeOfError = reflect.TypeOf((*error)(nil)).Elem() 14 15 // Find all methods for the type which can be exported. 16 // Build svrMap listing methods available as well as their 17 // request and reply types. 18 func (server *Server) buildSvrMap(typ reflect.Type) { 19 for m := 0; m < typ.NumMethod(); m++ { 20 method := typ.Method(m) 21 mtype := method.Type 22 mname := method.Name 23 24 // Just like net/rpc, we have these requirements on methods: 25 // - must be exported 26 // - needs three ins: receiver, *args, *reply 27 // - reply has to be a pointer and must be exported 28 // - method can only return one value of type error 29 if method.PkgPath != "" { 30 continue 31 } 32 33 if mtype.NumIn() != 3 { 34 continue 35 } 36 argType := mtype.In(1) 37 if !isExportedOrBuiltinType(argType) { 38 continue 39 } 40 41 replyType := mtype.In(2) 42 if replyType.Kind() != reflect.Ptr { 43 continue 44 } 45 46 if !isExportedOrBuiltinType(replyType) { 47 continue 48 } 49 50 if mtype.NumOut() != 1 { 51 continue 52 } 53 54 returnType := mtype.Out(0) 55 if returnType != typeOfError { 56 continue 57 } 58 59 // We save off the request type so we know how to unmarshal the request. 60 // We use the reply type to allocate the reply struct and marshal the response. 61 ma := methodArgs{methodPtr: &method, request: argType, reply: replyType} 62 server.svrMap[mname] = &ma 63 } 64 } 65 66 func isExportedOrBuiltinType(t reflect.Type) bool { 67 for t.Kind() == reflect.Ptr { 68 t = t.Elem() 69 } 70 return isMethodExported(t.Name()) || t.PkgPath() == "" 71 } 72 73 func isMethodExported(name string) bool { 74 ch, _ := utf8.DecodeRuneInString(name) 75 return unicode.IsUpper(ch) 76 } 77 78 // Figure out what methods we can have as RPCs and build the 79 // service map 80 func (server *Server) register(retrySvr interface{}) (err error) { 81 82 // Find all the methods associated with retrySvr and put into serviceMap 83 typ := reflect.TypeOf(retrySvr) 84 rcvr := reflect.ValueOf(retrySvr) 85 sname := reflect.Indirect(rcvr).Type().Name() 86 87 if !isMethodExported(sname) { 88 s := "retryrpc.Register: type " + sname + " is not exported" 89 return errors.New(s) 90 } 91 92 server.buildSvrMap(typ) 93 return 94 }