ing
This commit is contained in:
parent
280cda6238
commit
9b0d093216
|
@ -31,7 +31,7 @@ func (cnc *ClientNotificationCodec) ReadParams(args []interface{}) error {
|
||||||
if nil != cnc.noti.Params {
|
if nil != cnc.noti.Params {
|
||||||
// Note: if scr.request.Params is nil it's not an error, it's an optional member.
|
// Note: if scr.request.Params is nil it's not an error, it's an optional member.
|
||||||
// JSON params structured object. Unmarshal to the args object.
|
// JSON params structured object. Unmarshal to the args object.
|
||||||
if err := cuej.SetValueWithJSONStringArray(*cnc.noti.Params, args); nil != err {
|
if err := cuej.SetValueWithJSONStringArrayBytes(*cnc.noti.Params, args); nil != err {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -92,7 +92,7 @@ func (src *ServerRequestCodec) ReadParams(args []interface{}) error {
|
||||||
if src.err == nil && src.req.Params != nil {
|
if src.err == nil && src.req.Params != nil {
|
||||||
// Note: if scr.request.Params is nil it's not an error, it's an optional member.
|
// Note: if scr.request.Params is nil it's not an error, it's an optional member.
|
||||||
// JSON params structured object. Unmarshal to the args object.
|
// JSON params structured object. Unmarshal to the args object.
|
||||||
if err := cuej.SetValueWithJSONStringArray(*src.req.Params, args); nil != err {
|
if err := cuej.SetValueWithJSONStringArrayBytes(*src.req.Params, args); nil != err {
|
||||||
src.err = &protocol.Error{
|
src.err = &protocol.Error{
|
||||||
Code: protocol.E_BAD_PARAMS,
|
Code: protocol.E_BAD_PARAMS,
|
||||||
Message: err.Error(),
|
Message: err.Error(),
|
||||||
|
|
|
@ -4,12 +4,13 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"git.loafle.net/commons/rpc-go/protocol"
|
"git.loafle.net/commons/rpc-go/protocol"
|
||||||
|
cus "git.loafle.net/commons/util-go/service"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewRPCRegistry returns a new RPC registry.
|
// NewRPCRegistry returns a new RPC registry.
|
||||||
func NewRPCRegistry() RPCRegistry {
|
func NewRPCRegistry() RPCRegistry {
|
||||||
return &rpcRegistry{
|
return &rpcRegistry{
|
||||||
services: new(serviceMap),
|
serviceRegistry: new(cus.ServiceRegistry),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +24,7 @@ type RPCRegistry interface {
|
||||||
|
|
||||||
// RPCRegistry serves registered RPC services using registered codecs.
|
// RPCRegistry serves registered RPC services using registered codecs.
|
||||||
type rpcRegistry struct {
|
type rpcRegistry struct {
|
||||||
services *serviceMap
|
serviceRegistry *cus.ServiceRegistry
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterService adds a new service to the server.
|
// RegisterService adds a new service to the server.
|
||||||
|
@ -43,7 +44,7 @@ type rpcRegistry struct {
|
||||||
//
|
//
|
||||||
// All other methods are ignored.
|
// All other methods are ignored.
|
||||||
func (rr *rpcRegistry) RegisterService(receiver interface{}, name string) error {
|
func (rr *rpcRegistry) RegisterService(receiver interface{}, name string) error {
|
||||||
return rr.services.register(receiver, name)
|
return rr.serviceRegistry.Register(receiver, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *rpcRegistry) RegisterServices(receivers ...interface{}) error {
|
func (rr *rpcRegistry) RegisterServices(receivers ...interface{}) error {
|
||||||
|
@ -52,7 +53,7 @@ func (rr *rpcRegistry) RegisterServices(receivers ...interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, receiver := range receivers {
|
for _, receiver := range receivers {
|
||||||
if err := rr.services.register(receiver, ""); nil != err {
|
if err := rr.serviceRegistry.Register(receiver, ""); nil != err {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,7 +66,7 @@ func (rr *rpcRegistry) RegisterServiceMap(keysAndValues map[string]interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, receiver := range keysAndValues {
|
for name, receiver := range keysAndValues {
|
||||||
if err := rr.services.register(receiver, name); nil != err {
|
if err := rr.serviceRegistry.Register(receiver, name); nil != err {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,14 +74,14 @@ func (rr *rpcRegistry) RegisterServiceMap(keysAndValues map[string]interface{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *rpcRegistry) GetService(name string) interface{} {
|
func (rr *rpcRegistry) GetService(name string) interface{} {
|
||||||
return rr.services.getService(name)
|
return rr.serviceRegistry.GetService(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasMethod returns true if the given method is registered.
|
// HasMethod returns true if the given method is registered.
|
||||||
//
|
//
|
||||||
// The method uses a dotted notation as in "Service.Method".
|
// The method uses a dotted notation as in "Service.Method".
|
||||||
func (rr *rpcRegistry) HasMethod(method string) bool {
|
func (rr *rpcRegistry) HasMethod(method string) bool {
|
||||||
if _, _, err := rr.services.get(method); err == nil {
|
if _, _, err := rr.serviceRegistry.Get(method); err == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -92,14 +93,14 @@ func (rr *rpcRegistry) HasMethod(method string) bool {
|
||||||
// XML. A codec is chosen based on the "Content-Type" header from the request,
|
// XML. A codec is chosen based on the "Content-Type" header from the request,
|
||||||
// excluding the charset definition.
|
// excluding the charset definition.
|
||||||
func (rr *rpcRegistry) Invoke(codec protocol.RegistryCodec, leadingParams ...interface{}) (result interface{}, err error) {
|
func (rr *rpcRegistry) Invoke(codec protocol.RegistryCodec, leadingParams ...interface{}) (result interface{}, err error) {
|
||||||
serviceSpec, methodSpec, errGet := rr.services.get(codec.Method())
|
serviceSpec, methodSpec, errGet := rr.serviceRegistry.Get(codec.Method())
|
||||||
if nil != errGet {
|
if nil != errGet {
|
||||||
return nil, errGet
|
return nil, errGet
|
||||||
}
|
}
|
||||||
// Decode the args.
|
// Decode the args.
|
||||||
|
|
||||||
var in []reflect.Value
|
var in []reflect.Value
|
||||||
pValues, pInstances := methodSpec.getParamValues()
|
pValues, pInstances := methodSpec.ParamValues()
|
||||||
var lParamLen int
|
var lParamLen int
|
||||||
if nil != leadingParams {
|
if nil != leadingParams {
|
||||||
lParamLen = len(leadingParams)
|
lParamLen = len(leadingParams)
|
||||||
|
@ -135,12 +136,12 @@ func (rr *rpcRegistry) Invoke(codec protocol.RegistryCodec, leadingParams ...int
|
||||||
} else {
|
} else {
|
||||||
in = make([]reflect.Value, 1)
|
in = make([]reflect.Value, 1)
|
||||||
}
|
}
|
||||||
in[0] = serviceSpec.rcvrV
|
in[0] = serviceSpec.ReceiverValue()
|
||||||
|
|
||||||
// Call the service method.
|
// Call the service method.
|
||||||
returnValues := methodSpec.method.Func.Call(in)
|
returnValues := methodSpec.Call(in)
|
||||||
|
|
||||||
if nil != methodSpec.returnType {
|
if nil != methodSpec.ReturnType() {
|
||||||
result = returnValues[0].Interface()
|
result = returnValues[0].Interface()
|
||||||
if nil != returnValues[1].Interface() {
|
if nil != returnValues[1].Interface() {
|
||||||
err = returnValues[1].Interface().(error)
|
err = returnValues[1].Interface().(error)
|
|
@ -1,229 +0,0 @@
|
||||||
package registry
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"unicode"
|
|
||||||
"unicode/utf8"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// Precompute the reflect.Type of error and http.Request
|
|
||||||
typeOfError = reflect.TypeOf((*error)(nil)).Elem()
|
|
||||||
)
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// service
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
type service struct {
|
|
||||||
name string // name of service
|
|
||||||
rcvrV reflect.Value // receiver of methods for the service
|
|
||||||
rcvrT reflect.Type // type of the receiver
|
|
||||||
methods map[string]*serviceMethod // registered methods
|
|
||||||
}
|
|
||||||
|
|
||||||
type serviceMethod struct {
|
|
||||||
method reflect.Method // receiver method
|
|
||||||
paramTypes []reflect.Type // type of the request argument
|
|
||||||
returnType reflect.Type // type of the response argument
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *serviceMethod) getParamValues() (values []reflect.Value, instances []interface{}) {
|
|
||||||
if nil == sm.paramTypes || 0 == len(sm.paramTypes) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
pCount := len(sm.paramTypes)
|
|
||||||
values = make([]reflect.Value, pCount)
|
|
||||||
instances = make([]interface{}, pCount)
|
|
||||||
|
|
||||||
for indexI := 0; indexI < pCount; indexI++ {
|
|
||||||
values[indexI] = getValue(sm.paramTypes[indexI])
|
|
||||||
instances[indexI] = values[indexI].Interface()
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func getValue(t reflect.Type) reflect.Value {
|
|
||||||
rt := t
|
|
||||||
if rt.Kind() == reflect.Ptr {
|
|
||||||
rt = rt.Elem()
|
|
||||||
}
|
|
||||||
|
|
||||||
// rv := reflect.New(rt)
|
|
||||||
// if rt.Kind() != reflect.Struct {
|
|
||||||
// rv = reflect.Indirect(rv)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// var rv reflect.Value
|
|
||||||
|
|
||||||
// switch rt.Kind() {
|
|
||||||
// case reflect.Slice:
|
|
||||||
// rv = reflect.New(reflect.SliceOf(rt.Elem()))
|
|
||||||
// default:
|
|
||||||
// rv = reflect.New(rt)
|
|
||||||
// }
|
|
||||||
|
|
||||||
return reflect.New(rt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// serviceMap
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// serviceMap is a registry for services.
|
|
||||||
type serviceMap struct {
|
|
||||||
mutex sync.RWMutex
|
|
||||||
services map[string]*service
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sm *serviceMap) getService(name string) interface{} {
|
|
||||||
sm.mutex.RLock()
|
|
||||||
defer sm.mutex.RUnlock()
|
|
||||||
if sm.services == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return sm.services[name]
|
|
||||||
}
|
|
||||||
|
|
||||||
// register adds a new service using reflection to extract its methods.
|
|
||||||
func (sm *serviceMap) register(rcvr interface{}, name string) error {
|
|
||||||
// Setup service.
|
|
||||||
s := &service{
|
|
||||||
name: name,
|
|
||||||
rcvrV: reflect.ValueOf(rcvr),
|
|
||||||
rcvrT: reflect.TypeOf(rcvr),
|
|
||||||
methods: make(map[string]*serviceMethod),
|
|
||||||
}
|
|
||||||
if name == "" {
|
|
||||||
s.name = reflect.Indirect(s.rcvrV).Type().Name()
|
|
||||||
if !isExported(s.name) {
|
|
||||||
return fmt.Errorf("rpc: type %q is not exported", s.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if s.name == "" {
|
|
||||||
return fmt.Errorf("rpc: no service name for type %q",
|
|
||||||
s.rcvrT.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
// Setup methods.
|
|
||||||
Loop:
|
|
||||||
for i := 0; i < s.rcvrT.NumMethod(); i++ {
|
|
||||||
m := s.rcvrT.Method(i)
|
|
||||||
mt := m.Type
|
|
||||||
// Method must be exported.
|
|
||||||
if m.PkgPath != "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var paramTypes []reflect.Type
|
|
||||||
var returnType reflect.Type
|
|
||||||
|
|
||||||
pCount := mt.NumIn() - 1
|
|
||||||
|
|
||||||
if 0 < pCount {
|
|
||||||
paramTypes = make([]reflect.Type, pCount)
|
|
||||||
|
|
||||||
for indexI := 0; indexI < pCount; indexI++ {
|
|
||||||
pt := mt.In(indexI + 1)
|
|
||||||
if err = validateType(mt.In(indexI + 1)); nil != err {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
paramTypes[indexI] = pt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch mt.NumOut() {
|
|
||||||
case 1:
|
|
||||||
if t := mt.Out(0); t != typeOfError {
|
|
||||||
continue Loop
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
if t := mt.Out(0); !isExportedOrBuiltin(t) {
|
|
||||||
continue Loop
|
|
||||||
}
|
|
||||||
|
|
||||||
if t := mt.Out(1); t != typeOfError {
|
|
||||||
continue Loop
|
|
||||||
}
|
|
||||||
rt := mt.Out(0)
|
|
||||||
if err = validateType(rt); nil != err {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
returnType = rt
|
|
||||||
default:
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
s.methods[m.Name] = &serviceMethod{
|
|
||||||
method: m,
|
|
||||||
paramTypes: paramTypes,
|
|
||||||
returnType: returnType,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(s.methods) == 0 {
|
|
||||||
return fmt.Errorf("rpc: %q has no exported methods of suitable type", s.name)
|
|
||||||
}
|
|
||||||
// Add to the map.
|
|
||||||
sm.mutex.Lock()
|
|
||||||
defer sm.mutex.Unlock()
|
|
||||||
if sm.services == nil {
|
|
||||||
sm.services = make(map[string]*service)
|
|
||||||
} else if _, ok := sm.services[s.name]; ok {
|
|
||||||
return fmt.Errorf("rpc: service already defined: %q", s.name)
|
|
||||||
}
|
|
||||||
sm.services[s.name] = s
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateType(t reflect.Type) error {
|
|
||||||
if t.Kind() == reflect.Struct {
|
|
||||||
return fmt.Errorf("Type is Struct. Pass by reference, i.e. *%s", t)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// get returns a registered service given a method name.
|
|
||||||
//
|
|
||||||
// The method name uses a dotted notation as in "Service.Method".
|
|
||||||
func (sm *serviceMap) get(method string) (*service, *serviceMethod, error) {
|
|
||||||
parts := strings.Split(method, ".")
|
|
||||||
if len(parts) != 2 {
|
|
||||||
err := fmt.Errorf("rpc: service/method request ill-formed: %q", method)
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
sm.mutex.Lock()
|
|
||||||
service := sm.services[parts[0]]
|
|
||||||
sm.mutex.Unlock()
|
|
||||||
if service == nil {
|
|
||||||
err := fmt.Errorf("rpc: can't find service %q", method)
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
serviceMethod := service.methods[parts[1]]
|
|
||||||
if serviceMethod == nil {
|
|
||||||
err := fmt.Errorf("rpc: can't find method %q", method)
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
return service, serviceMethod, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// isExported returns true of a string is an exported (upper case) name.
|
|
||||||
func isExported(name string) bool {
|
|
||||||
rune, _ := utf8.DecodeRuneInString(name)
|
|
||||||
return unicode.IsUpper(rune)
|
|
||||||
}
|
|
||||||
|
|
||||||
// isExportedOrBuiltin returns true if a type is exported or a builtin.
|
|
||||||
func isExportedOrBuiltin(t reflect.Type) bool {
|
|
||||||
for t.Kind() == reflect.Ptr {
|
|
||||||
t = t.Elem()
|
|
||||||
}
|
|
||||||
// PkgPath will be non-empty even for an exported type,
|
|
||||||
// so we need to check the type name as well.
|
|
||||||
return isExported(t.Name()) || t.PkgPath() == ""
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user