rpclib: improve errors

This commit is contained in:
Łukasz Magiera 2019-07-02 15:49:10 +02:00
parent bed044b5a1
commit 573509b3e6
3 changed files with 57 additions and 22 deletions

View File

@ -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)

View File

@ -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{}

View File

@ -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", &notfound)
err = notfound.NotThere("hello?")
if err == nil || err.Error() != "RPC error (-32601): method 'SimpleServerHandler.NotThere' not found" {
t.Error("wrong error:", err)
}
}