rpc/registry.go

112 lines
2.8 KiB
Go
Raw Normal View History

2017-10-25 14:52:47 +00:00
package rpc
import (
"reflect"
2017-10-26 07:21:35 +00:00
"git.loafle.net/commons_go/rpc/protocol"
2017-10-25 14:52:47 +00:00
)
/**
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
2017-10-31 09:25:44 +00:00
Invoke(codec protocol.RegistryCodec) (result interface{}, err error)
2017-10-25 14:52:47 +00:00
}
// 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.
2017-10-27 04:00:30 +00:00
// - The method has two arguments: *args, *reply.
// - All two arguments are pointers.
// - The first and second arguments are exported or local.
2017-10-25 14:52:47 +00:00
// - The method has return type error.
//
// All other methods are ignored.
2017-10-26 07:21:35 +00:00
func (rr *rpcRegistry) RegisterService(receiver interface{}, name string) error {
return rr.services.register(receiver, name)
2017-10-25 14:52:47 +00:00
}
// HasMethod returns true if the given method is registered.
//
// The method uses a dotted notation as in "Service.Method".
2017-10-26 07:21:35 +00:00
func (rr *rpcRegistry) HasMethod(method string) bool {
if _, _, err := rr.services.get(method); err == nil {
2017-10-25 14:52:47 +00:00
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.
2017-10-31 09:25:44 +00:00
func (rr *rpcRegistry) Invoke(codec protocol.RegistryCodec) (result interface{}, err error) {
serviceSpec, methodSpec, errGet := rr.services.get(codec.Method())
2017-10-25 14:52:47 +00:00
if errGet != nil {
2017-10-31 09:25:44 +00:00
return nil, errGet
2017-10-25 14:52:47 +00:00
}
// Decode the args.
2017-11-02 06:39:30 +00:00
var in []reflect.Value
2017-11-03 06:33:50 +00:00
pValues, pInstances := methodSpec.getParamValues()
2017-11-02 10:29:37 +00:00
2017-11-03 06:33:50 +00:00
if nil != pInstances && 0 < len(pInstances) {
2017-11-03 06:35:43 +00:00
if errRead := codec.ReadParams(pInstances); errRead != nil {
2017-11-02 06:39:30 +00:00
return nil, errRead
}
2017-11-03 06:33:50 +00:00
pCount := len(pInstances)
2017-11-03 05:55:26 +00:00
in = make([]reflect.Value, pCount+1)
for indexI := 0; indexI < pCount; indexI++ {
2017-11-03 06:33:50 +00:00
in[indexI+1] = pValues[indexI]
2017-11-02 06:39:30 +00:00
}
} else {
in = make([]reflect.Value, 1)
2017-10-25 14:52:47 +00:00
}
2017-11-02 10:29:37 +00:00
in[0] = serviceSpec.rcvrV
2017-11-02 06:39:30 +00:00
2017-10-25 14:52:47 +00:00
// Call the service method.
2017-11-02 06:39:30 +00:00
returnValues := methodSpec.method.Func.Call(in)
2017-10-25 14:52:47 +00:00
2017-11-02 06:39:30 +00:00
if nil != methodSpec.returnType {
result = returnValues[0].Interface()
2017-11-02 11:06:19 +00:00
if nil != returnValues[1].Interface() {
err = returnValues[1].Interface().(error)
}
2017-11-02 06:39:30 +00:00
} else {
2017-11-02 11:06:19 +00:00
if nil != returnValues[0].Interface() {
err = returnValues[0].Interface().(error)
}
2017-10-25 14:52:47 +00:00
}
2017-11-02 06:39:30 +00:00
return
2017-10-25 14:52:47 +00:00
}