This commit is contained in:
crusader 2017-11-02 19:29:37 +09:00
parent 392dd3823b
commit bb77dd1b59
2 changed files with 72 additions and 46 deletions

View File

@ -77,19 +77,21 @@ func (rr *rpcRegistry) Invoke(codec protocol.RegistryCodec) (result interface{},
// Decode the args. // Decode the args.
var in []reflect.Value var in []reflect.Value
paramValues, paramInstances := methodSpec.getParams() paramValues := methodSpec.paramValues
if nil != paramValues { if nil != paramValues {
in = make([]reflect.Value, len(paramValues)+1) params := methodSpec.getInterfaces()
if errRead := codec.ReadParams(paramInstances); errRead != nil { if errRead := codec.ReadParams(params); errRead != nil {
return nil, errRead return nil, errRead
} }
in = make([]reflect.Value, len(paramValues)+1)
for indexI := 0; indexI < len(paramValues); indexI++ { for indexI := 0; indexI < len(paramValues); indexI++ {
in[indexI+1] = paramValues[indexI] in[indexI+1] = paramValues[indexI]
} }
} else { } else {
in = make([]reflect.Value, 1) in = make([]reflect.Value, 1)
} }
in[0] = serviceSpec.rcvr in[0] = serviceSpec.rcvrV
// Call the service method. // Call the service method.
returnValues := methodSpec.method.Func.Call(in) returnValues := methodSpec.method.Func.Call(in)

View File

@ -20,29 +20,29 @@ var (
type service struct { type service struct {
name string // name of service name string // name of service
rcvr reflect.Value // receiver of methods for the service rcvrV reflect.Value // receiver of methods for the service
rcvrType reflect.Type // type of the receiver rcvrT reflect.Type // type of the receiver
methods map[string]*serviceMethod // registered methods methods map[string]*serviceMethod // registered methods
} }
type serviceMethod struct { type serviceMethod struct {
method reflect.Method // receiver method method reflect.Method // receiver method
paramTypes []reflect.Type // type of the request argument paramTypes []reflect.Type // type of the request argument
paramValues []reflect.Value
returnType reflect.Type // type of the response argument returnType reflect.Type // type of the response argument
returnValue reflect.Value
} }
func (sm *serviceMethod) getParams() (values []reflect.Value, instances []interface{}) { func (sm *serviceMethod) getInterfaces() (instances []interface{}) {
if nil == sm.paramTypes || 0 == len(sm.paramTypes) { if nil == sm.paramValues || 0 == len(sm.paramValues) {
return nil, nil return nil
} }
pCount := len(sm.paramTypes) pCount := len(sm.paramValues)
values = make([]reflect.Value, pCount)
instances = make([]interface{}, pCount) instances = make([]interface{}, pCount)
for indexI := 0; indexI < pCount; indexI++ { for indexI := 0; indexI < pCount; indexI++ {
values[indexI] = reflect.New(sm.paramTypes[indexI]) instances[indexI] = sm.paramValues[indexI].Interface()
instances[indexI] = values[indexI].Interface()
} }
return return
@ -63,68 +63,76 @@ func (m *serviceMap) register(rcvr interface{}, name string) error {
// Setup service. // Setup service.
s := &service{ s := &service{
name: name, name: name,
rcvr: reflect.ValueOf(rcvr), rcvrV: reflect.ValueOf(rcvr),
rcvrType: reflect.TypeOf(rcvr), rcvrT: reflect.TypeOf(rcvr),
methods: make(map[string]*serviceMethod), methods: make(map[string]*serviceMethod),
} }
if name == "" { if name == "" {
s.name = reflect.Indirect(s.rcvr).Type().Name() s.name = reflect.Indirect(s.rcvrV).Type().Name()
if !isExported(s.name) { if !isExported(s.name) {
return fmt.Errorf("rpc: type %q is not exported", s.name) return fmt.Errorf("rpc: type %q is not exported", s.name)
} }
} }
if s.name == "" { if s.name == "" {
return fmt.Errorf("rpc: no service name for type %q", return fmt.Errorf("rpc: no service name for type %q",
s.rcvrType.String()) s.rcvrT.String())
} }
var err error
// Setup methods. // Setup methods.
Loop: Loop:
for i := 0; i < s.rcvrType.NumMethod(); i++ { for i := 0; i < s.rcvrT.NumMethod(); i++ {
method := s.rcvrType.Method(i) m := s.rcvrT.Method(i)
mtype := method.Type mt := m.Type
// Method must be exported. // Method must be exported.
if method.PkgPath != "" { if m.PkgPath != "" {
continue continue
} }
var paramTypes []reflect.Type var paramTypes []reflect.Type
var paramValues []reflect.Value
mCount := mtype.NumIn()
if 0 < mCount {
paramTypes = make([]reflect.Type, mCount)
for indexI := 1; indexI < mCount; indexI++ {
param := mtype.In(indexI)
if !isExportedOrBuiltin(param) {
continue Loop
}
paramTypes[indexI] = param.Elem()
}
}
var returnType reflect.Type var returnType reflect.Type
switch mtype.NumOut() { var returnValue reflect.Value
pCount := mt.NumIn() - 1
if 0 < pCount {
paramTypes = make([]reflect.Type, pCount)
paramValues = make([]reflect.Value, pCount)
for indexI := 0; indexI < pCount; indexI++ {
if paramTypes[indexI], paramValues[indexI], err = validateType(mt.In(indexI + 1)); nil != err {
return err
}
}
}
switch mt.NumOut() {
case 1: case 1:
if returnType := mtype.Out(0); returnType != typeOfError { if t := mt.Out(0); t != typeOfError {
continue Loop continue Loop
} }
case 2: case 2:
if returnType := mtype.Out(0); !isExportedOrBuiltin(returnType) { if t := mt.Out(0); !isExportedOrBuiltin(t) {
continue Loop continue Loop
} }
if returnType := mtype.Out(1); returnType != typeOfError { if t := mt.Out(1); t != typeOfError {
continue Loop continue Loop
} }
returnType = mtype.Out(0).Elem() if returnType, returnValue, err = validateType(mt.Out(0)); nil != err {
return err
}
default: default:
continue continue
} }
s.methods[method.Name] = &serviceMethod{ s.methods[m.Name] = &serviceMethod{
method: method, method: m,
paramTypes: paramTypes, paramTypes: paramTypes,
paramValues: paramValues,
returnType: returnType, returnType: returnType,
returnValue: returnValue,
} }
} }
if len(s.methods) == 0 { if len(s.methods) == 0 {
@ -142,6 +150,22 @@ Loop:
return nil return nil
} }
func validateType(t reflect.Type) (rt reflect.Type, rv reflect.Value, err error) {
if t.Kind() == reflect.Struct {
err = fmt.Errorf("Type is Struct. Pass by reference, i.e. %s", t)
return
}
if t.Kind() == reflect.Ptr {
rt = t.Elem()
}
rv = reflect.New(rt)
if rt.Kind() != reflect.Struct {
rv = reflect.Indirect(rv)
}
return
}
// get returns a registered service given a method name. // get returns a registered service given a method name.
// //
// The method name uses a dotted notation as in "Service.Method". // The method name uses a dotted notation as in "Service.Method".