func (*reflectSuite) TestValueOf(c *gc.C) { v := rpcreflect.ValueOf(reflect.ValueOf(nil)) c.Check(v.IsValid(), jc.IsFalse) c.Check(func() { v.FindMethod("foo", 0, "bar") }, gc.PanicMatches, "FindMethod called on invalid Value") root := &Root{} v = rpcreflect.ValueOf(reflect.ValueOf(root)) c.Check(v.IsValid(), jc.IsTrue) c.Check(v.GoValue().Interface(), gc.Equals, root) }
func (*reflectSuite) TestFindMethod(c *gc.C) { // FindMethod is actually extensively tested because it's // used in the implementation of the rpc server, // so just a simple sanity check test here. root := &Root{ simple: make(map[string]*SimpleMethods), } root.simple["a99"] = &SimpleMethods{root: root, id: "a99"} v := rpcreflect.ValueOf(reflect.ValueOf(root)) m, err := v.FindMethod("foo", 0, "bar") c.Assert(err, gc.ErrorMatches, `unknown object type "foo"`) c.Assert(err, gc.FitsTypeOf, (*rpcreflect.CallNotImplementedError)(nil)) c.Assert(m, gc.IsNil) m, err = v.FindMethod("SimpleMethods", 0, "bar") c.Assert(err, gc.ErrorMatches, "no such request - method SimpleMethods.bar is not implemented") c.Assert(err, gc.FitsTypeOf, (*rpcreflect.CallNotImplementedError)(nil)) c.Assert(m, gc.IsNil) m, err = v.FindMethod("SimpleMethods", 0, "Call1r1e") c.Assert(err, jc.ErrorIsNil) c.Assert(m.ParamsType(), gc.Equals, reflect.TypeOf(stringVal{})) c.Assert(m.ResultType(), gc.Equals, reflect.TypeOf(stringVal{})) ret, err := m.Call("a99", reflect.ValueOf(stringVal{"foo"})) c.Assert(err, jc.ErrorIsNil) c.Assert(ret.Interface(), gc.Equals, stringVal{"Call1r1e ret"}) }
// Serve serves RPC requests on the connection by invoking methods on // root. Note that it does not start the connection running, // though it may be called once the connection is already started. // // The server executes each client request by calling a method on root // to obtain an object to act on; then it invokes an method on that // object with the request parameters, possibly returning some result. // // Methods on the root value are of the form: // // M(id string) (O, error) // // where M is an exported name, conventionally naming the object type, // id is some identifier for the object and O is the type of the // returned object. // // Methods defined on O may defined in one of the following forms, where // T and R must be struct types. // // Method() // Method() R // Method() (R, error) // Method() error // Method(T) // Method(T) R // Method(T) (R, error) // Method(T) error // // If transformErrors is non-nil, it will be called on all returned // non-nil errors, for example to transform the errors into ServerErrors // with specified codes. There will be a panic if transformErrors // returns nil. // // Serve may be called at any time on a connection to change the // set of methods being served by the connection. This will have // no effect on calls that are currently being services. // If root is nil, the connection will serve no methods. func (conn *Conn) Serve(root interface{}, transformErrors func(error) error) { rootValue := rpcreflect.ValueOf(reflect.ValueOf(root)) if rootValue.IsValid() { conn.serve(rootValue, transformErrors) } else { conn.serve(nil, transformErrors) } }
func (s *errRootSuite) TestErrorRootViaRPC(c *gc.C) { origErr := fmt.Errorf("my custom error") errRoot := apiserver.NewErrRoot(origErr) val := rpcreflect.ValueOf(reflect.ValueOf(errRoot)) caller, err := val.FindMethod("Admin", 0, "Login") c.Assert(err, jc.ErrorIsNil) resp, err := caller.Call("", reflect.Value{}) c.Check(err, gc.Equals, origErr) c.Check(resp.IsValid(), jc.IsFalse) }
// Serve serves RPC requests on the connection by invoking methods on // root. Note that it does not start the connection running, // though it may be called once the connection is already started. // // The server executes each client request by calling a method on root // to obtain an object to act on; then it invokes an method on that // object with the request parameters, possibly returning some result. // // Methods on the root value are of the form: // // M(id string) (O, error) // // where M is an exported name, conventionally naming the object type, // id is some identifier for the object and O is the type of the // returned object. // // Methods defined on O may defined in one of the following forms, where // T and R must be struct types. // // Method() // Method() R // Method() (R, error) // Method() error // Method(T) // Method(T) R // Method(T) (R, error) // Method(T) error // // If transformErrors is non-nil, it will be called on all returned // non-nil errors, for example to transform the errors into ServerErrors // with specified codes. There will be a panic if transformErrors // returns nil. // // Serve may be called at any time on a connection to change the // set of methods being served by the connection. This will have // no effect on calls that are currently being services. // If root is nil, the connection will serve no methods. func (conn *Conn) Serve(root interface{}, transformErrors func(error) error) { rootValue := rpcreflect.ValueOf(reflect.ValueOf(root)) if rootValue.IsValid() && transformErrors == nil { transformErrors = func(err error) error { return err } } conn.mutex.Lock() defer conn.mutex.Unlock() conn.rootValue = rootValue conn.transformErrors = transformErrors }
func (srv *Server) serveConn(wsConn *websocket.Conn, modelUUID string) { codec := jsoncodec.NewWebsocket(wsConn) conn := rpc.NewConn(codec, &fakeobserver.Instance{}) root := allVersions{ rpcreflect.ValueOf(reflect.ValueOf(srv.newRoot(modelUUID))), } conn.ServeRoot(root, nil) conn.Start() <-conn.Dead() conn.Close() }
func (r *anonRoot) FindMethod(rootName string, version int, methodName string) (rpcreflect.MethodCaller, error) { if rootName != "Admin" { return nil, &rpcreflect.CallNotImplementedError{ RootMethod: rootName, Version: version, } } if api, ok := r.adminAPIs[version]; ok { return rpcreflect.ValueOf(reflect.ValueOf(api)).FindMethod(rootName, 0, methodName) } return nil, &rpc.RequestError{ Code: params.CodeNotSupported, Message: "this version of Juju does not support login from old clients", } }
func (*reflectSuite) TestFindMethodRefusesVersionsNot0(c *gc.C) { root := &Root{ simple: make(map[string]*SimpleMethods), } root.simple["a99"] = &SimpleMethods{root: root, id: "a99"} v := rpcreflect.ValueOf(reflect.ValueOf(root)) m, err := v.FindMethod("SimpleMethods", 0, "Call1r1e") c.Assert(err, jc.ErrorIsNil) c.Assert(m.ParamsType(), gc.Equals, reflect.TypeOf(stringVal{})) c.Assert(m.ResultType(), gc.Equals, reflect.TypeOf(stringVal{})) m, err = v.FindMethod("SimpleMethods", 1, "Call1r1e") c.Assert(err, gc.FitsTypeOf, (*rpcreflect.CallNotImplementedError)(nil)) c.Assert(err, gc.ErrorMatches, `unknown version \(1\) of interface "SimpleMethods"`) }
func (r *anonRoot) FindMethod(rootName string, version int, methodName string) (rpcreflect.MethodCaller, error) { if rootName != "Admin" { return nil, &rpcreflect.CallNotImplementedError{ RootMethod: rootName, Version: version, } } if api, ok := r.adminApis[version]; ok { return rpcreflect.ValueOf(reflect.ValueOf(api)).FindMethod(rootName, 0, methodName) } return nil, &rpcreflect.CallNotImplementedError{ RootMethod: rootName, Method: methodName, Version: version, } }