package registry import ( "reflect" "git.loafle.net/commons/rpc-go/protocol" cus "git.loafle.net/commons/util-go/service" ) // NewRPCRegistry returns a new RPC registry. func NewRPCRegistry() RPCRegistry { return &rpcRegistry{ serviceRegistry: new(cus.ServiceRegistry), } } type RPCRegistry interface { RPCInvoker GetService(name string) interface{} RegisterService(receiver interface{}, name string) error RegisterServices(receivers ...interface{}) error RegisterServiceMap(keysAndValues map[string]interface{}) error } // RPCRegistry serves registered RPC services using registered codecs. type rpcRegistry struct { serviceRegistry *cus.ServiceRegistry } // 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.serviceRegistry.Register(receiver, name) } func (rr *rpcRegistry) RegisterServices(receivers ...interface{}) error { if nil == receivers || 0 == len(receivers) { return nil } for _, receiver := range receivers { if err := rr.serviceRegistry.Register(receiver, ""); nil != err { return err } } return nil } func (rr *rpcRegistry) RegisterServiceMap(keysAndValues map[string]interface{}) error { if nil == keysAndValues || 0 == len(keysAndValues) { return nil } for name, receiver := range keysAndValues { if err := rr.serviceRegistry.Register(receiver, name); nil != err { return err } } return nil } func (rr *rpcRegistry) GetService(name string) interface{} { return rr.serviceRegistry.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.serviceRegistry.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, leadingParams ...interface{}) (result interface{}, err error) { serviceSpec, methodSpec, errGet := rr.serviceRegistry.Get(codec.Method()) if nil != errGet { return nil, errGet } // Decode the args. var in []reflect.Value pValues, pInstances := methodSpec.ParamValues() var lParamLen int if nil != leadingParams { lParamLen = len(leadingParams) } if nil != pInstances && 0 < len(pInstances) { if errRead := codec.ReadParams(pInstances[lParamLen:]); errRead != nil { return nil, errRead } for indexI := 0; indexI < lParamLen; indexI++ { i := pInstances[indexI] rv := reflect.ValueOf(i) iv := reflect.ValueOf(leadingParams[indexI]) switch reflect.TypeOf(i).Elem().Kind() { case reflect.Struct: rv.Elem().Set(iv.Elem()) default: rv.Elem().Set(iv) } } 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.ReceiverValue() // Call the service method. returnValues := methodSpec.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()), // } // } // }