forked from Marquis42/ari-proxy
/
errors.go
82 lines (66 loc) · 1.62 KB
/
errors.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package client
import "errors"
type wrappedError struct {
Message string
Err error
}
func (err *wrappedError) Cause() error {
return err.Err
}
func (err *wrappedError) Error() string {
return err.Message + ": " + err.Err.Error()
}
// remote error, used wrap the error response before sending
type codedError struct {
err error
code int
}
func (err *codedError) Error() string {
return err.err.Error()
}
func (err *codedError) Code() int {
return err.code
}
type causer interface {
Cause() error
}
type coded interface {
Code() int
}
// ErrorToMap converts an error type to a key-value map
func ErrorToMap(err error, parent string) map[string]interface{} {
data := make(map[string]interface{})
if parent == err.Error() {
// NOTE: this is done because of how errors.Wrap works, internally,
// to build a stacktrace. We end up with duplicate
// entries in the tree of errors.
if c, ok := err.(causer); ok {
return ErrorToMap(c.Cause(), parent)
}
}
data["message"] = err.Error()
if c, ok := err.(coded); ok {
data["code"] = c.Code()
}
if c, ok := err.(causer); ok {
data["cause"] = ErrorToMap(c.Cause(), data["message"].(string))
}
return data
}
// MapToError converts a JSON parsed map to an error type
func MapToError(i map[string]interface{}) error {
msg, _ := i["message"].(string)
code, codeOK := i["code"].(int)
cause, causeOK := i["cause"].(map[string]interface{})
err := errors.New(msg)
if codeOK {
err = &codedError{err, code}
}
if causeOK {
causeError := MapToError(cause)
l := len(msg) - len(causeError.Error())
msg = msg[:l-2]
err = &wrappedError{msg, causeError}
}
return err
}