-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patherror.go
More file actions
137 lines (113 loc) · 2.92 KB
/
error.go
File metadata and controls
137 lines (113 loc) · 2.92 KB
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package speedrail
import (
"encoding/json"
"errors"
"fmt"
"runtime"
"strings"
)
// Error is a speedrail error interface that can be used to wrap any error
type Error interface {
error
json.Marshaler
Trail() Trail
Merge(Error) Error
StatusCode() int
}
// defaultError is the default error struct for speedrail.
type defaultError struct {
trail Trail
outgoingMessage string
statusCode int
}
// Type check that default error implements Error interface
var _ Error = defaultError{}
func (e defaultError) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]string{"error": e.Error()})
}
type ErrorWithTrail struct {
StrategyName string
Error error
}
// Trail is a map of errors, with a custom marshaler.
type Trail []ErrorWithTrail
func (t Trail) MarshalJSON() ([]byte, error) {
result := map[string]string{}
for index, err := range t {
if strings.Contains(err.StrategyName, "/") && strings.LastIndex(err.StrategyName, "/") < len(err.StrategyName) {
result[fmt.Sprintf("[%d]%s", index+1, err.StrategyName[strings.LastIndex(err.StrategyName, "/")+1:])] = err.Error.Error()
continue
}
result[fmt.Sprintf("[%d]%s", index+1, err.StrategyName)] = err.Error.Error()
}
return json.Marshal(result)
}
// Trail returns the error trail
func (e defaultError) Trail() Trail {
return e.trail
}
// Merge will merge two errors together.
func (e defaultError) Merge(err Error) Error {
e.trail = append(e.trail, err.Trail()...)
if e.StatusCode() < err.StatusCode() {
e.statusCode = err.StatusCode()
}
e.outgoingMessage = strings.Join([]string{e.outgoingMessage, err.Error()}, "; ")
return e
}
// StatusCode returns the status code of the error.
func (e defaultError) StatusCode() int {
return e.statusCode
}
// Error returns the error message.
func (e defaultError) Error() string {
return e.outgoingMessage
}
// Unwrap will return the underlying error.
func (e defaultError) Unwrap() error {
for _, err := range e.trail {
return err.Error
}
return nil
}
// Is checks if the error is of the given type.
func (e defaultError) Is(target error) bool {
for _, err := range e.trail {
if errors.Is(err.Error, target) {
return true
}
}
return false
}
// As checks if the error can be cast as this type.
func (e defaultError) As(target any) bool {
for _, err := range e.trail {
if errors.As(err.Error, target) {
return true
}
}
return false
}
// NewError will return a default error struct.
func NewError(err error, statusCode int, outgoingMessage string) Error {
// Create err if it is nil.
if err == nil {
err = errors.New(outgoingMessage)
}
strategyName := "unknown"
pc, _, _, ok := runtime.Caller(1)
details := runtime.FuncForPC(pc)
if ok && details != nil {
strategyName = details.Name()
}
return defaultError{
trail: []ErrorWithTrail{
{
StrategyName: strategyName,
Error: err,
},
},
statusCode: statusCode,
outgoingMessage: outgoingMessage,
}
}