-
Notifications
You must be signed in to change notification settings - Fork 0
/
standard.go
executable file
·219 lines (173 loc) · 4.71 KB
/
standard.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
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
package goerrors
import (
"bytes"
"fmt"
)
// IStandardError Interface for a standard error which decorate another basic go error (`error` go interface)
// with an error code, message and other additionnal informations
type IStandardError interface {
// Base interface
IError
// Add more informations on that error
AddInfo(info string, args ...interface{}) IStandardError
// Get error code
GetCode() int64
}
// Internal structure type for the standard error
type tStandardError struct {
GoError
code int64 // Error code
infos bytes.Buffer // Additionnal informations
}
// GetName gets standard error name
func (se *tStandardError) GetName() string {
return "StandardError"
}
// AddInfo adds informations in standard error
func (se *tStandardError) AddInfo(info string, args ...interface{}) IStandardError {
// Just prints into internal buffer the informations passed as parameters
_, _ = fmt.Fprintln(&se.infos, fmt.Sprintf(info, args...))
return se
}
// GetCode gets error code
func (se *tStandardError) GetCode() int64 {
return se.code
}
// DecorateError «decorates» the error passed as "err" parameter.
// The error returned will be an standard error with additionnal informations and stack trace.
func DecorateError(err error) IStandardError {
if err == nil {
return nil
}
ierr, ok := err.(IStandardError)
if !ok {
res := new(tStandardError)
_ = res.Init(res, "", nil, err, 1)
ierr = res
}
return ierr
}
// DecorateErrorWithDatas is like `DecorateError` with error code and custom data
func DecorateErrorWithDatas(err error, code int64, data interface{}, msg string, args ...interface{}) IStandardError {
if err == nil {
return nil
}
ierr, ok := err.(IStandardError)
if ok {
_ = ierr.AddInfo("Recorate for code=%d and message=%s", code, fmt.Sprintf(msg, args...))
} else {
res := &tStandardError{code: code}
_ = res.Init(res, fmt.Sprintf(msg, args...), data, err, 1)
ierr = res
}
return ierr
}
// MakeError makes an standard error from a message passed as "message" parameter
func MakeError(message string, args ...interface{}) IStandardError {
res := new(tStandardError)
_ = res.Init(res, fmt.Sprintf(message, args...), nil, nil, 1)
return res
}
// MakeErrorWithDatas is like `MakeError` with error code and custom data
func MakeErrorWithDatas(code int64, data interface{}, message string, args ...interface{}) IStandardError {
res := &tStandardError{code: code}
_ = res.Init(res, fmt.Sprintf(message, args...), data, nil, 1)
return res
}
// AddInfo is the global function to add information in an error whatever.
// This function just call the "AddInfo" method of an standard error.
func AddInfo(err error, info string, args ...interface{}) IStandardError {
// Check if "err" is already an standard error
goErr, ok := err.(IStandardError)
if !ok {
// Otherwise decorate that unknown error
goErr = DecorateError(err)
}
// Delegate call to "AddInfo" method
return goErr.AddInfo(info, args...)
}
// Catch is the global function to catch an error
func Catch(err *error, catch, finally ErrorHandler) {
var resErr error
defer func() {
if finally != nil {
ierr, _ := resErr.(IError)
resErr = finally(ierr)
}
if err != nil {
*err = resErr
}
}()
recovered := recover()
if recovered == nil {
return
}
var ok bool
resErr, ok = recovered.(error)
if !ok {
panic(recovered)
}
if catch == nil {
return
}
ierr, ok := resErr.(IError)
if !ok {
ierr = DecorateError(resErr)
}
cerr := catch(ierr)
if cerr != nil {
resErr = cerr
}
}
// Try is the global function to call a try block
func Try(try, catch, finally ErrorHandler) (err error) {
defer func() {
if finally == nil {
return
}
ierr, _ := err.(IError)
ferr := finally(ierr)
if ferr != nil {
err = ferr
}
}()
defer func() {
recovered := recover()
if ((recovered == nil) || (catch == nil)) && (err == nil) {
return
}
if err == nil {
recoveredError, ok := recovered.(error)
if ok {
err = recoveredError
} else {
err = fmt.Errorf("error: %s", recovered)
}
}
ierr, ok := err.(IError)
if !ok {
ierr = DecorateError(err)
}
cerr := catch(ierr)
if cerr != nil {
err = cerr
}
}()
return try(nil)
}
// Raise is the global function to raise an anonymous error
func Raise(message string, args ...interface{}) {
MakeError(message, args...).raise(1)
}
// RaiseWithInfos is like Raise with error code and custom data
func RaiseWithInfos(errorCode int64, data interface{}, message string, args ...interface{}) {
MakeErrorWithDatas(errorCode, data, message, args...).raise(1)
}
// RaiseError is the global function to raise the error passed in argument
func RaiseError(err error) {
gerr, ok := err.(IError)
if !ok {
gerr = DecorateError(err)
}
gerr.raise(1)
}