package registry import ( "reflect" "git.loafle.net/commons_go/rpc/protocol" ) // NewRPCRegistry returns a new RPC registry. func NewRPCRegistry() RPCRegistry { return &rpcRegistry{ services: new(serviceMap), } } type RPCRegistry interface { RPCInvoker GetService(name string) interface{} RegisterService(receiver interface{}, name string) error } // RPCRegistry serves registered RPC services using registered codecs. type rpcRegistry struct { services *serviceMap } // RegisterService adds a new service to the server. // // The name parameter is optional: if empty it will be inferred from // the receiver type name. // // Methods from the receiver will be extracted if these rules are satisfied: // // - The receiver is exported (begins with an upper case letter) or local // (defined in the package registering the service). // - The method name is exported. // - The method has two arguments: *args, *reply. // - All two arguments are pointers. // - The first and second arguments are exported or local. // - The method has return type error. // // All other methods are ignored. func (rr *rpcRegistry) RegisterService(receiver interface{}, name string) error { return rr.services.register(receiver, name) } func (rr *rpcRegistry) GetService(name string) interface{} { return rr.services.getService(name) } // HasMethod returns true if the given method is registered. // // The method uses a dotted notation as in "Service.Method". func (rr *rpcRegistry) HasMethod(method string) bool { if _, _, err := rr.services.get(method); err == nil { return true } return false } // Invoke execute a method. // // Codecs are defined to process a given serialization scheme, e.g., JSON or // XML. A codec is chosen based on the "Content-Type" header from the request, // excluding the charset definition. func (rr *rpcRegistry) Invoke(codec protocol.RegistryCodec) (result interface{}, err error) { serviceSpec, methodSpec, errGet := rr.services.get(codec.Method()) if errGet != nil { return nil, errGet } // Decode the args. var in []reflect.Value pValues, pInstances := methodSpec.getParamValues() if nil != pInstances && 0 < len(pInstances) { if errRead := codec.ReadParams(pInstances); errRead != nil { return nil, errRead } pCount := len(pInstances) in = make([]reflect.Value, pCount+1) for indexI := 0; indexI < pCount; indexI++ { if pValues[indexI].Type().Kind() == reflect.Ptr && pValues[indexI].Type().Elem().Kind() != reflect.Struct { in[indexI+1] = reflect.Indirect(pValues[indexI]) } else { in[indexI+1] = pValues[indexI] } } } else { in = make([]reflect.Value, 1) } in[0] = serviceSpec.rcvrV // Call the service method. returnValues := methodSpec.method.Func.Call(in) if nil != methodSpec.returnType { result = returnValues[0].Interface() if nil != returnValues[1].Interface() { err = returnValues[1].Interface().(error) } } else { if nil != returnValues[0].Interface() { err = returnValues[0].Interface().(error) } } return } // func convertValues(values []interface{}, types []reflect.Type) []reflect.Value { // c := len(values) // vs := make([]reflect.Value, c) // for indexI := 0; indexI < c; indexI++ { // vs[indexI] = convertValue(&values[indexI], types[indexI]) // } // return vs // } // func convertValue(v *interface{}, t reflect.Type) reflect.Value { // switch t.Kind() { // case reflect.Bool: // return reflect.ValueOf(*v).Convert(t) // case reflect.Float32, reflect.Float64: // return reflect.ValueOf(*v).Convert(t) // case reflect.Int, reflect.Int32, reflect.Int64: // return reflect.ValueOf(*v).Convert(t) // case reflect.Interface: // // When we see an interface, we make our own thing // return reflect.ValueOf(*v).Convert(t) // case reflect.Map: // return reflect.ValueOf(*v).M // return d.decodeMap(name, node, result) // case reflect.Ptr: // return d.decodePtr(name, node, result) // case reflect.Slice: // return d.decodeSlice(name, node, result) // case reflect.String: // return d.decodeString(name, node, result) // case reflect.Struct: // return d.decodeStruct(name, node, result) // default: // return &parser.PosError{ // Pos: node.Pos(), // Err: fmt.Errorf("%s: unknown kind to decode into: %s", name, k.Kind()), // } // } // }