package rpc import ( "reflect" "git.loafle.net/commons_go/rpc/protocol" ) /** Network connection Handshake(1..n) Send request HTTP */ // NewRPCRegistry returns a new RPC registry. func NewRegistry() Registry { return &rpcRegistry{ services: new(serviceMap), } } type Registry interface { RegisterService(receiver interface{}, name string) error HasMethod(method string) bool Invoke(codec protocol.RegistryCodec) (result interface{}, err 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) } // 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 paramValues, paramInstances := methodSpec.getParams() if nil != paramValues { in = make([]reflect.Value, len(paramValues)+1) if errRead := codec.ReadParams(paramInstances); errRead != nil { return nil, errRead } for indexI := 0; indexI < len(paramValues); indexI++ { in[indexI+1] = paramValues[indexI] } } else { in = make([]reflect.Value, 1) } in[0] = serviceSpec.rcvr // Call the service method. returnValues := methodSpec.method.Func.Call(in) if nil != methodSpec.returnType { result = returnValues[0].Interface() err = returnValues[1].Interface().(error) } else { err = returnValues[0].Interface().(error) } return }