145 lines
4.2 KiB
Go
145 lines
4.2 KiB
Go
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 {
|
|
Invoke(codec protocol.RegistryCodec) (result interface{}, err error)
|
|
RegisterService(receiver interface{}, name string) error
|
|
HasMethod(method string) bool
|
|
}
|
|
|
|
// 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
|
|
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()),
|
|
// }
|
|
// }
|
|
// }
|