From 46407e2033476b29ed9d5fa0464af3163a3b08e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Magiera?= Date: Fri, 28 Jun 2019 16:05:10 +0200 Subject: [PATCH] rpc: client errors License: MIT Signed-off-by: Jakub Sztandera --- rpclib/rpcClient.go | 44 +++++++++++++++++++++++++++++++++----------- rpclib/rpc_test.go | 19 +++++++++++++++++++ 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/rpclib/rpcClient.go b/rpclib/rpcClient.go index 46d61b496..9b416cfc7 100644 --- a/rpclib/rpcClient.go +++ b/rpclib/rpcClient.go @@ -4,11 +4,24 @@ import ( "bytes" "encoding/json" "errors" + "fmt" "net/http" "reflect" "sync/atomic" ) +type ErrClient struct { + err error +} + +func (e *ErrClient) Error() string { + return fmt.Sprintf("RPC client error: %s", e.err) +} + +func (e *ErrClient) Unwrap(err error) error { + return e.err +} + type result reflect.Value func (r *result) UnmarshalJSON(raw []byte) error { @@ -61,6 +74,20 @@ func NewClient(addr string, namespace string, handler interface{}) { return out } + processError := func(err error) []reflect.Value{ + out := make([]reflect.Value, nout) + + if valOut != -1 { + out[valOut] = reflect.New(ftyp.Out(valOut)).Elem() + } + if errOut != -1 { + out[errOut] = reflect.New(reflect.TypeOf(new(error)).Elem()).Elem() + out[errOut].Set(reflect.ValueOf(&ErrClient{err})) + } + + return out + } + fn := reflect.MakeFunc(ftyp, func(args []reflect.Value) (results []reflect.Value) { id := atomic.AddInt64(&idCtr, 1) params := make([]param, len(args)) @@ -79,21 +106,18 @@ func NewClient(addr string, namespace string, handler interface{}) { b, err := json.Marshal(&req) if err != nil { - // TODO: try returning an error if the method has one - panic(err) + return processError(err) } httpResp, err := http.Post(addr, "application/json", bytes.NewReader(b)) if err != nil { - // TODO: try returning an error if the method has one - panic(err) + return processError(err) } defer httpResp.Body.Close() + // TODO: check error codes in spec if httpResp.StatusCode != 200 { - // TODO: try returning an error if the method has one - // TODO: actually parse response, it haz right errors - panic("non 200 code") + return processError(errors.New("non 200 response code")) } var resp clientResponse @@ -102,13 +126,11 @@ func NewClient(addr string, namespace string, handler interface{}) { } if err := json.NewDecoder(httpResp.Body).Decode(&resp); err != nil { - // TODO: try returning an error if the method has one - panic(err) + return processError(err) } if resp.Id != *req.Id { - // TODO: try returning an error if the method has one - panic("request and response id didn't match") + return processError(errors.New("request and response id didn't match")) } return processResponse(resp) diff --git a/rpclib/rpc_test.go b/rpclib/rpc_test.go index fd387cf4a..6f8a9d143 100644 --- a/rpclib/rpc_test.go +++ b/rpclib/rpc_test.go @@ -142,4 +142,23 @@ func TestRPC(t *testing.T) { // shouldn't panic noparam.Add() + var erronly struct { + Add func() error + } + NewClient(testServ.URL, "SimpleServerHandler", &erronly) + + err = erronly.Add() + if err == nil || err.Error() != "RPC client error: non 200 response code" { + t.Error("wrong error") + } + + var wrongtype struct { + Add func(string) error + } + 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") + } }