-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patherrors.go
More file actions
109 lines (102 loc) · 3.43 KB
/
errors.go
File metadata and controls
109 lines (102 loc) · 3.43 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
package reghelp
import (
"errors"
"fmt"
)
// Error is the base error type returned by the SDK.
//
// Status is the HTTP status code (or 0 for transport errors).
// Code mirrors the `id` field from the REGHelp error envelope when present
// (RATE_LIMIT, SERVICE_DISABLED, MAINTENANCE_MODE, TASK_NOT_FOUND,
// INVALID_PARAM, EXTERNAL_ERROR …).
// Raw holds the decoded error envelope for callers that need the original
// fields (e.g. balance on push.setStatus error).
type Error struct {
Status int
Code string
Message string
Raw map[string]any
// Unwrapped underlying error, if any (e.g. network/timeout).
Cause error
}
func (e *Error) Error() string {
if e.Status != 0 {
return fmt.Sprintf("[%d %s] %s", e.Status, e.Code, e.Message)
}
if e.Code != "" {
return fmt.Sprintf("[%s] %s", e.Code, e.Message)
}
return e.Message
}
func (e *Error) Unwrap() error { return e.Cause }
// Sentinel error codes. Compare with errors.Is(err, reghelp.ErrUnauthorized).
var (
ErrUnauthorized = errors.New("reghelp: invalid api key")
ErrRateLimit = errors.New("reghelp: rate limit exceeded")
ErrServiceDisabled = errors.New("reghelp: service temporarily disabled")
ErrMaintenance = errors.New("reghelp: api in maintenance mode")
ErrTaskNotFound = errors.New("reghelp: task not found")
ErrInvalidParameter = errors.New("reghelp: invalid parameter")
ErrExternalService = errors.New("reghelp: external service error")
ErrUnknown = errors.New("reghelp: unknown error")
ErrNetwork = errors.New("reghelp: network error")
ErrTimeout = errors.New("reghelp: timeout waiting for task result")
ErrInvalidJSONResult = errors.New("reghelp: invalid JSON in response")
)
// Is reports whether err equals one of the sentinel errors above.
// Implements errors.Is for chained Error values.
func (e *Error) Is(target error) bool {
switch target {
case ErrUnauthorized:
return e.Status == 401 || e.Code == "UNAUTHORIZED"
case ErrRateLimit:
return e.Status == 429 || e.Code == "RATE_LIMIT"
case ErrServiceDisabled:
return e.Code == "SERVICE_DISABLED"
case ErrMaintenance:
return e.Code == "MAINTENANCE_MODE"
case ErrTaskNotFound:
return e.Status == 404 || e.Code == "TASK_NOT_FOUND"
case ErrInvalidParameter:
return e.Status == 400 || e.Code == "INVALID_PARAM"
case ErrExternalService:
return e.Status == 502 || e.Code == "EXTERNAL_ERROR"
}
return false
}
// mapErrorCode converts the server `id`/HTTP-status pair to a typed Error.
// task is included in the message when relevant (TASK_NOT_FOUND).
func mapErrorCode(status int, code, message, task string, raw map[string]any) *Error {
e := &Error{Status: status, Code: code, Message: message, Raw: raw}
if e.Message == "" {
switch code {
case "RATE_LIMIT":
e.Message = "rate limit exceeded"
case "SERVICE_DISABLED":
e.Message = "service temporarily disabled"
case "MAINTENANCE_MODE":
e.Message = "api in maintenance mode"
case "TASK_NOT_FOUND":
if task != "" {
e.Message = "task " + task + " not found"
} else {
e.Message = "task not found"
}
case "INVALID_PARAM":
e.Message = "invalid parameter"
case "EXTERNAL_ERROR":
e.Message = "external service error"
case "UNAUTHORIZED":
e.Message = "invalid api key"
default:
if code != "" {
e.Message = "unknown error: " + code
} else if status != 0 {
e.Message = fmt.Sprintf("http %d", status)
} else {
e.Message = "unknown error"
}
}
}
return e
}