rpclib: improve errors
This commit is contained in:
parent
bed044b5a1
commit
573509b3e6
@ -64,7 +64,7 @@ func NewClient(addr string, namespace string, handler interface{}) {
|
||||
|
||||
valOut, errOut, nout := processFuncOut(ftyp)
|
||||
|
||||
processResponse := func(resp clientResponse) []reflect.Value {
|
||||
processResponse := func(resp clientResponse, code int) []reflect.Value {
|
||||
out := make([]reflect.Value, nout)
|
||||
|
||||
if valOut != -1 {
|
||||
@ -73,7 +73,7 @@ func NewClient(addr string, namespace string, handler interface{}) {
|
||||
if errOut != -1 {
|
||||
out[errOut] = reflect.New(errorType).Elem()
|
||||
if resp.Error != nil {
|
||||
out[errOut].Set(reflect.ValueOf(errors.New(resp.Error.Message)))
|
||||
out[errOut].Set(reflect.ValueOf(resp.Error))
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,11 +139,6 @@ func NewClient(addr string, namespace string, handler interface{}) {
|
||||
|
||||
// process response
|
||||
|
||||
// TODO: check error codes in spec
|
||||
if httpResp.StatusCode != 200 {
|
||||
return processError(errors.New("non 200 response code"))
|
||||
}
|
||||
|
||||
var resp clientResponse
|
||||
if valOut != -1 {
|
||||
resp.Result = result(reflect.New(ftyp.Out(valOut)))
|
||||
@ -157,7 +152,7 @@ func NewClient(addr string, namespace string, handler interface{}) {
|
||||
return processError(errors.New("request and response id didn't match"))
|
||||
}
|
||||
|
||||
return processResponse(resp)
|
||||
return processResponse(resp, httpResp.StatusCode)
|
||||
})
|
||||
|
||||
val.Elem().Field(i).Set(fn)
|
||||
|
@ -8,6 +8,14 @@ import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
const (
|
||||
rpcParseError = -32700
|
||||
rpcInvalidRequest = -32600
|
||||
rpcMethodNotFound = -32601
|
||||
rpcInvalidParams = -32602
|
||||
rpcInternalError = -32603
|
||||
)
|
||||
|
||||
type rpcHandler struct {
|
||||
paramReceivers []reflect.Type
|
||||
nParams int
|
||||
@ -59,6 +67,13 @@ type respError struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func (e *respError) Error() string {
|
||||
if e.Code >= -32768 && e.Code <= -32000 {
|
||||
return fmt.Sprintf("RPC error (%d): %s", e.Code, e.Message)
|
||||
}
|
||||
return e.Message
|
||||
}
|
||||
|
||||
type response struct {
|
||||
Jsonrpc string `json:"jsonrpc"`
|
||||
Result interface{} `json:"result,omitempty"`
|
||||
@ -70,21 +85,18 @@ type response struct {
|
||||
func (s *RPCServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
var req request
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
fmt.Println(err)
|
||||
w.WriteHeader(500)
|
||||
s.rpcError(w, &req, rpcParseError, err)
|
||||
return
|
||||
}
|
||||
|
||||
handler, ok := s.methods[req.Method]
|
||||
if !ok {
|
||||
fmt.Printf("rpcserver: unknown method %s\n", req.Method)
|
||||
w.WriteHeader(500)
|
||||
s.rpcError(w, &req, rpcMethodNotFound, fmt.Errorf("method '%s' not found", req.Method))
|
||||
return
|
||||
}
|
||||
|
||||
if len(req.Params) != handler.nParams {
|
||||
fmt.Println("rpcserver: wrong param count")
|
||||
w.WriteHeader(500)
|
||||
s.rpcError(w, &req, rpcInvalidParams, fmt.Errorf("wrong param count"))
|
||||
return
|
||||
}
|
||||
|
||||
@ -97,8 +109,7 @@ func (s *RPCServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
for i := 0; i < handler.nParams; i++ {
|
||||
rp := reflect.New(handler.paramReceivers[i])
|
||||
if err := json.NewDecoder(bytes.NewReader(req.Params[i].data)).Decode(rp.Interface()); err != nil {
|
||||
w.WriteHeader(500)
|
||||
fmt.Println(err)
|
||||
s.rpcError(w, &req, rpcParseError, err)
|
||||
return
|
||||
}
|
||||
|
||||
@ -130,11 +141,28 @@ func (s *RPCServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||
fmt.Println(err)
|
||||
w.WriteHeader(500)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (s *RPCServer) rpcError(w http.ResponseWriter, req *request, code int, err error) {
|
||||
w.WriteHeader(500)
|
||||
if req.Id == nil { // notification
|
||||
return
|
||||
}
|
||||
|
||||
resp := response{
|
||||
Jsonrpc: "2.0",
|
||||
Id: *req.Id,
|
||||
Error: &respError{
|
||||
Code: code,
|
||||
Message: err.(error).Error(),
|
||||
},
|
||||
}
|
||||
|
||||
_ = json.NewEncoder(w).Encode(resp)
|
||||
}
|
||||
|
||||
func (s *RPCServer) Register(namespace string, r interface{}) {
|
||||
val := reflect.ValueOf(r)
|
||||
//TODO: expect ptr
|
||||
@ -198,3 +226,5 @@ func processFuncOut(funcType reflect.Type) (valOut int, errOut int, n int) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
var _ error = &respError{}
|
||||
|
@ -87,7 +87,7 @@ func TestRPC(t *testing.T) {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
if err.Error() != "test" {
|
||||
t.Fatal("wrong error")
|
||||
t.Fatal("wrong error", err)
|
||||
}
|
||||
|
||||
// AddGet(int) int
|
||||
@ -151,8 +151,8 @@ func TestRPC(t *testing.T) {
|
||||
NewClient(testServ.URL, "SimpleServerHandler", &erronly)
|
||||
|
||||
_, err = erronly.AddGet()
|
||||
if err == nil || err.Error() != "RPC client error: non 200 response code" {
|
||||
t.Error("wrong error")
|
||||
if err == nil || err.Error() != "RPC error (-32602): wrong param count" {
|
||||
t.Error("wrong error:", err)
|
||||
}
|
||||
|
||||
var wrongtype struct {
|
||||
@ -161,8 +161,18 @@ func TestRPC(t *testing.T) {
|
||||
NewClient(testServ.URL, "SimpleServerHandler", &wrongtype)
|
||||
|
||||
err = wrongtype.Add("not an int")
|
||||
if err == nil || err.Error() != "RPC client error: non 200 response code" {
|
||||
t.Error("wrong error")
|
||||
if err == nil || err.Error() != "RPC error (-32700): json: cannot unmarshal string into Go value of type int" {
|
||||
t.Error("wrong error:", err)
|
||||
}
|
||||
|
||||
var notfound struct {
|
||||
NotThere func(string) error
|
||||
}
|
||||
NewClient(testServ.URL, "SimpleServerHandler", ¬found)
|
||||
|
||||
err = notfound.NotThere("hello?")
|
||||
if err == nil || err.Error() != "RPC error (-32601): method 'SimpleServerHandler.NotThere' not found" {
|
||||
t.Error("wrong error:", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user