From 4a282ffe96735645173adf860880f3b048bb9750 Mon Sep 17 00:00:00 2001 From: Felipe Martinez Date: Thu, 21 Jan 2021 14:12:35 +0100 Subject: [PATCH] Add errors package and handling --- client/client.go | 4 ++++ errors/error.go | 51 ++++++++++++++++++++++++++++++++++++++++++++ errors/errors.go | 21 ++++++++++++++++++ transport/message.go | 35 +++++++++++++++++++++++++++++- 4 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 errors/error.go create mode 100644 errors/errors.go diff --git a/client/client.go b/client/client.go index e3c52fe..0543f2c 100644 --- a/client/client.go +++ b/client/client.go @@ -104,6 +104,10 @@ func (c *client) Call(service string, path string, reqval interface{}, respval i return fmt.Errorf("decode response: %w", err) } + if err, ok := respmsg.GetError(); ok { + return err + } + return nil } diff --git a/errors/error.go b/errors/error.go new file mode 100644 index 0000000..9fad7c5 --- /dev/null +++ b/errors/error.go @@ -0,0 +1,51 @@ +package errors + +import ( + "bytes" + "encoding/base64" + "encoding/gob" + "fmt" + "net/http" + "strings" +) + +type Error struct { + StatusCode int16 + Detail string +} + +func NewError(code int16, format string, a ...interface{}) error { + return &Error{ + StatusCode: code, + Detail: fmt.Sprintf(format, a...), + } +} + +// Encode transforms the error instance into a base64-encoded blob +func (e *Error) Encode() (string, error) { + var b bytes.Buffer + enc := gob.NewEncoder(&b) + + if err := enc.Encode(e); err != nil { + return "", err + } + + return base64.StdEncoding.EncodeToString(b.Bytes()), nil +} + +// Decode tries to decode en error from a base64-encoded string +func Decode(str string) (*Error, error) { + b := strings.NewReader(str) + dec := gob.NewDecoder(b) + + var merr Error + if err := dec.Decode(&merr); err != nil { + return nil, err + } + + return &merr, nil +} + +func (e *Error) Error() string { + return fmt.Sprintf("%s: %s", http.StatusText(int(e.StatusCode)), e.Detail) +} diff --git a/errors/errors.go b/errors/errors.go new file mode 100644 index 0000000..e90a654 --- /dev/null +++ b/errors/errors.go @@ -0,0 +1,21 @@ +package errors + +func BadRequest(format string, a ...string) error { + return NewError(400, format, a) +} + +func Unauthorized(format string, a ...string) error { + return NewError(401, format, a) +} + +func Forbidden(format string, a ...string) error { + return NewError(403, format, a) +} + +func NotFound(format string, a ...string) error { + return NewError(404, format, a) +} + +func InternalServerError(format string, a ...string) error { + return NewError(404, format, a) +} diff --git a/transport/message.go b/transport/message.go index 8aa1760..96c2b44 100644 --- a/transport/message.go +++ b/transport/message.go @@ -1,5 +1,11 @@ package transport +import ( + goerrors "errors" + + "github.com/MouseHatGames/mice/errors" +) + type Message struct { Headers map[string]string Data []byte @@ -12,5 +18,32 @@ func NewMessage() *Message { } func (m *Message) SetError(err error) { - m.Headers[HeaderError] = err.Error() + var value string + + if merr, ok := err.(*errors.Error); ok { + enc, err := merr.Encode() + + if err != nil { + value = err.Error() + } else { + value = enc + } + } else { + value = err.Error() + } + + m.Headers[HeaderError] = value +} + +func (m *Message) GetError() (err error, hasError bool) { + value, ok := m.Headers[HeaderError] + if !ok { + return nil, false + } + + if merr, err := errors.Decode(value); err != nil { + return merr, true + } + + return goerrors.New(value), true }