...
1 package errcode
2
3 import (
4 "fmt"
5 "net/http"
6 "sort"
7 "sync"
8 )
9
10 var (
11 errorCodeToDescriptors = map[ErrorCode]ErrorDescriptor{}
12 idToDescriptors = map[string]ErrorDescriptor{}
13 groupToDescriptors = map[string][]ErrorDescriptor{}
14 )
15
16 var (
17
18
19 ErrorCodeUnknown = Register("errcode", ErrorDescriptor{
20 Value: "UNKNOWN",
21 Message: "unknown error",
22 Description: `Generic error returned when the error does not have an
23 API classification.`,
24 HTTPStatusCode: http.StatusInternalServerError,
25 })
26
27
28 ErrorCodeUnsupported = Register("errcode", ErrorDescriptor{
29 Value: "UNSUPPORTED",
30 Message: "The operation is unsupported.",
31 Description: `The operation was unsupported due to a missing
32 implementation or invalid set of parameters.`,
33 HTTPStatusCode: http.StatusMethodNotAllowed,
34 })
35
36
37
38 ErrorCodeUnauthorized = Register("errcode", ErrorDescriptor{
39 Value: "UNAUTHORIZED",
40 Message: "authentication required",
41 Description: `The access controller was unable to authenticate
42 the client. Often this will be accompanied by a
43 Www-Authenticate HTTP response header indicating how to
44 authenticate.`,
45 HTTPStatusCode: http.StatusUnauthorized,
46 })
47
48
49
50 ErrorCodeDenied = Register("errcode", ErrorDescriptor{
51 Value: "DENIED",
52 Message: "requested access to the resource is denied",
53 Description: `The access controller denied access for the
54 operation on a resource.`,
55 HTTPStatusCode: http.StatusForbidden,
56 })
57
58
59
60 ErrorCodeUnavailable = Register("errcode", ErrorDescriptor{
61 Value: "UNAVAILABLE",
62 Message: "service unavailable",
63 Description: "Returned when a service is not available",
64 HTTPStatusCode: http.StatusServiceUnavailable,
65 })
66
67
68
69 ErrorCodeTooManyRequests = Register("errcode", ErrorDescriptor{
70 Value: "TOOMANYREQUESTS",
71 Message: "too many requests",
72 Description: `Returned when a client attempts to contact a
73 service too many times`,
74 HTTPStatusCode: http.StatusTooManyRequests,
75 })
76 )
77
78 var nextCode = 1000
79 var registerLock sync.Mutex
80
81
82
83 func Register(group string, descriptor ErrorDescriptor) ErrorCode {
84 registerLock.Lock()
85 defer registerLock.Unlock()
86
87 descriptor.Code = ErrorCode(nextCode)
88
89 if _, ok := idToDescriptors[descriptor.Value]; ok {
90 panic(fmt.Sprintf("ErrorValue %q is already registered", descriptor.Value))
91 }
92 if _, ok := errorCodeToDescriptors[descriptor.Code]; ok {
93 panic(fmt.Sprintf("ErrorCode %v is already registered", descriptor.Code))
94 }
95
96 groupToDescriptors[group] = append(groupToDescriptors[group], descriptor)
97 errorCodeToDescriptors[descriptor.Code] = descriptor
98 idToDescriptors[descriptor.Value] = descriptor
99
100 nextCode++
101 return descriptor.Code
102 }
103
104 type byValue []ErrorDescriptor
105
106 func (a byValue) Len() int { return len(a) }
107 func (a byValue) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
108 func (a byValue) Less(i, j int) bool { return a[i].Value < a[j].Value }
109
110
111 func GetGroupNames() []string {
112 keys := []string{}
113
114 for k := range groupToDescriptors {
115 keys = append(keys, k)
116 }
117 sort.Strings(keys)
118 return keys
119 }
120
121
122 func GetErrorCodeGroup(name string) []ErrorDescriptor {
123 desc := groupToDescriptors[name]
124 sort.Sort(byValue(desc))
125 return desc
126 }
127
128
129
130 func GetErrorAllDescriptors() []ErrorDescriptor {
131 result := []ErrorDescriptor{}
132
133 for _, group := range GetGroupNames() {
134 result = append(result, GetErrorCodeGroup(group)...)
135 }
136 sort.Sort(byValue(result))
137 return result
138 }
139
View as plain text