mirror of
https://github.com/foomo/gotsrpc.git
synced 2025-10-16 12:35:35 +00:00
135 lines
2.5 KiB
Go
135 lines
2.5 KiB
Go
package gotsrpc
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"reflect"
|
|
"strings"
|
|
|
|
"github.com/mitchellh/mapstructure"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
type Error struct {
|
|
Msg string `json:"m"`
|
|
Pkg string `json:"p"`
|
|
Type string `json:"t"`
|
|
Data interface{} `json:"d,omitempty"`
|
|
ErrCause *Error `json:"c,omitempty"`
|
|
}
|
|
|
|
// NewError returns a new instance
|
|
func NewError(err error) *Error {
|
|
// check if already transformed
|
|
if v, ok := err.(*Error); ok { //nolint:errorlint
|
|
return v
|
|
}
|
|
|
|
// skip *withStack error type
|
|
if _, ok := err.(interface {
|
|
StackTrace() errors.StackTrace
|
|
}); ok && errors.Unwrap(err) != nil {
|
|
err = errors.Unwrap(err)
|
|
}
|
|
|
|
// retrieve error details
|
|
errType := reflect.TypeOf(err)
|
|
errElem := errType
|
|
if errType.Kind() == reflect.Ptr {
|
|
errElem = errType.Elem()
|
|
}
|
|
|
|
inst := &Error{
|
|
Msg: err.Error(),
|
|
Type: errType.String(),
|
|
Pkg: errElem.PkgPath(),
|
|
Data: err,
|
|
}
|
|
|
|
// unwrap error
|
|
if unwrappedErr := errors.Unwrap(err); unwrappedErr != nil {
|
|
inst.ErrCause = NewError(unwrappedErr)
|
|
inst.Msg = strings.TrimSuffix(inst.Msg, ": "+unwrappedErr.Error())
|
|
}
|
|
|
|
return inst
|
|
}
|
|
|
|
// As interface
|
|
func (e *Error) As(err interface{}) bool {
|
|
if e == nil || err == nil {
|
|
return false
|
|
}
|
|
if reflect.TypeOf(err).Elem().String() == e.Type {
|
|
if decodeErr := mapstructure.Decode(e.Data, &err); decodeErr != nil {
|
|
fmt.Printf("ERROR: failed to decode error data\n%+v", decodeErr)
|
|
return false
|
|
} else {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Cause interface
|
|
func (e *Error) Cause() error {
|
|
if e.ErrCause != nil {
|
|
return e.ErrCause
|
|
}
|
|
return e
|
|
}
|
|
|
|
// Format interface
|
|
func (e *Error) Format(s fmt.State, verb rune) {
|
|
switch verb {
|
|
case 'v':
|
|
if s.Flag('+') {
|
|
_, _ = fmt.Fprintf(s, "%s.(%s)\n", e.Pkg, e.Type)
|
|
if e.Data != nil {
|
|
_, _ = fmt.Fprintf(s, "Data: %v\n", e.Data)
|
|
}
|
|
}
|
|
fallthrough
|
|
case 's', 'q':
|
|
_, _ = io.WriteString(s, e.Error())
|
|
}
|
|
}
|
|
|
|
// Unwrap interface
|
|
func (e *Error) Unwrap() error {
|
|
if e != nil && e.ErrCause != nil {
|
|
return e.ErrCause
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Is interface
|
|
func (e *Error) Is(err error) bool {
|
|
if e == nil || err == nil {
|
|
return false
|
|
}
|
|
|
|
errType := reflect.TypeOf(err)
|
|
errElem := errType
|
|
if errType.Kind() == reflect.Ptr {
|
|
errElem = errType.Elem()
|
|
}
|
|
|
|
if e.Msg == err.Error() &&
|
|
errType.String() == e.Type &&
|
|
errElem.PkgPath() == e.Pkg {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// Error interface
|
|
func (e *Error) Error() string {
|
|
msg := e.Msg
|
|
if e.ErrCause != nil {
|
|
msg += ": " + e.ErrCause.Error()
|
|
}
|
|
return msg
|
|
}
|