diff --git a/protocol/json/client_notification.go b/protocol/json/client_notification.go index f2684bf..51a8e7a 100644 --- a/protocol/json/client_notification.go +++ b/protocol/json/client_notification.go @@ -31,7 +31,7 @@ func (cnc *ClientNotificationCodec) ReadParams(args []interface{}) error { if nil != cnc.noti.Params { // 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. - if err := cuej.SetValueWithJSONStringArray(*cnc.noti.Params, args); nil != err { + if err := cuej.SetValueWithJSONStringArrayBytes(*cnc.noti.Params, args); nil != err { return err } return nil diff --git a/protocol/json/server_request.go b/protocol/json/server_request.go index 06a5442..3a72f53 100644 --- a/protocol/json/server_request.go +++ b/protocol/json/server_request.go @@ -92,7 +92,7 @@ func (src *ServerRequestCodec) ReadParams(args []interface{}) error { 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. // 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{ Code: protocol.E_BAD_PARAMS, Message: err.Error(), diff --git a/registry/rpc_registry.go b/registry/rpc-registry.go similarity index 88% rename from registry/rpc_registry.go rename to registry/rpc-registry.go index 91386f0..91c7bdc 100644 --- a/registry/rpc_registry.go +++ b/registry/rpc-registry.go @@ -4,12 +4,13 @@ import ( "reflect" "git.loafle.net/commons/rpc-go/protocol" + cus "git.loafle.net/commons/util-go/service" ) // NewRPCRegistry returns a new RPC registry. func NewRPCRegistry() 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. type rpcRegistry struct { - services *serviceMap + serviceRegistry *cus.ServiceRegistry } // RegisterService adds a new service to the server. @@ -43,7 +44,7 @@ type rpcRegistry struct { // // All other methods are ignored. 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 { @@ -52,7 +53,7 @@ func (rr *rpcRegistry) RegisterServices(receivers ...interface{}) error { } for _, receiver := range receivers { - if err := rr.services.register(receiver, ""); nil != err { + if err := rr.serviceRegistry.Register(receiver, ""); nil != err { return err } } @@ -65,7 +66,7 @@ func (rr *rpcRegistry) RegisterServiceMap(keysAndValues map[string]interface{}) } 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 } } @@ -73,14 +74,14 @@ func (rr *rpcRegistry) RegisterServiceMap(keysAndValues map[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. // // 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 { + if _, _, err := rr.serviceRegistry.Get(method); err == nil { return true } 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, // excluding the charset definition. 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 { return nil, errGet } // Decode the args. var in []reflect.Value - pValues, pInstances := methodSpec.getParamValues() + pValues, pInstances := methodSpec.ParamValues() var lParamLen int if nil != leadingParams { lParamLen = len(leadingParams) @@ -135,12 +136,12 @@ func (rr *rpcRegistry) Invoke(codec protocol.RegistryCodec, leadingParams ...int } else { in = make([]reflect.Value, 1) } - in[0] = serviceSpec.rcvrV + in[0] = serviceSpec.ReceiverValue() // 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() if nil != returnValues[1].Interface() { err = returnValues[1].Interface().(error) diff --git a/registry/service_map.go b/registry/service_map.go deleted file mode 100644 index 10635d1..0000000 --- a/registry/service_map.go +++ /dev/null @@ -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() == "" -}