gopkg.in/hedzr/errors.v3@v3.3.1/coded.go (about) 1 package errors 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "strconv" 8 ) 9 10 // A Code is a signed 32-bit error code copied from gRPC spec 11 // but negatived. 12 // 13 // And more builtin error codes added since hedzr/errors.v3 (v3.1.6). 14 // 15 // You may register any application-level error codes by calling 16 // RegisterCode(codeInt, desc). 17 type Code int32 18 19 const ( 20 // OK is returned on success. [HTTP/non-HTTP] 21 OK Code = 0 22 23 // Canceled indicates the operation was canceled (typically by the caller). [HTTP/non-HTTP] 24 Canceled Code = -1 25 26 // Unknown error. [HTTP/non-HTTP] 27 // An example of where this error may be returned is 28 // if a Status value received from another address space belongs to 29 // an error-space that is not known in this address space. Also 30 // errors raised by APIs that do not return enough error information 31 // may be converted to this error. 32 Unknown Code = -2 33 34 // InvalidArgument indicates client specified an invalid argument. [HTTP] 35 // 36 // Note that this differs from FailedPrecondition. It indicates 37 // arguments that are problematic regardless of the state of the 38 // system (e.g., a malformed file name). 39 // 40 // And this also differs from IllegalArgument, who's applied and 41 // identify an application error or a general logical error. 42 InvalidArgument Code = -3 43 44 // DeadlineExceeded means operation expired before completion. [HTTP] 45 // For operations that change the state of the system, this error 46 // might be returned even if the operation has completed 47 // successfully. For example, a successful response from a server 48 // could have been delayed long enough for the deadline to expire. 49 // 50 // = HTTP 408 Timeout 51 DeadlineExceeded Code = -4 52 53 // NotFound means some requested entity (e.g., file or directory) 54 // wasn't found. [HTTP] 55 // 56 // = HTTP 404 57 NotFound Code = -5 58 59 // AlreadyExists means an attempt to create an entity failed 60 // because one already exists. [HTTP] 61 AlreadyExists Code = -6 62 63 // PermissionDenied indicates the caller does not have permission to 64 // execute the specified operation. [HTTP] 65 // 66 // It must not be used for rejections 67 // caused by exhausting some resource (use ResourceExhausted 68 // instead for those errors). It must not be 69 // used if the caller cannot be identified (use Unauthenticated 70 // instead for those errors). 71 PermissionDenied Code = -7 72 73 // ResourceExhausted indicates some resource has been exhausted, 74 // perhaps a per-user quota, or perhaps the entire file system 75 // is out of space. [HTTP] 76 ResourceExhausted Code = -8 77 78 // FailedPrecondition indicates operation was rejected because the 79 // system is not in a state required for the operation's execution. 80 // For example, directory to be deleted may be non-empty, a rmdir 81 // operation is applied to a non-directory, etc. [HTTP] 82 // 83 // A litmus test that may help a service implementor in deciding 84 // between FailedPrecondition, Aborted, and Unavailable: 85 // (a) Use Unavailable if the client can retry just the failing call. 86 // (b) Use Aborted if the client should retry at a higher-level 87 // (e.g., restarting a read-modify-write sequence). 88 // (c) Use FailedPrecondition if the client should not retry until 89 // the system state has been explicitly fixed. E.g., if a "rmdir" 90 // fails because the directory is non-empty, FailedPrecondition 91 // should be returned since the client should not retry unless 92 // they have first fixed up the directory by deleting files from it. 93 // (d) Use FailedPrecondition if the client performs conditional 94 // REST Get/Update/Delete on a resource and the resource on the 95 // server does not match the condition. E.g., conflicting 96 // read-modify-write on the same resource. 97 FailedPrecondition Code = -9 98 99 // Aborted indicates the operation was aborted, typically due to a 100 // concurrency issue like sequencer check failures, transaction aborts, 101 // etc. [HTTP] 102 // 103 // See litmus test above for deciding between FailedPrecondition, 104 // Aborted, and Unavailable. 105 Aborted Code = -10 106 107 // OutOfRange means operation was attempted past the valid range. [HTTP] 108 // 109 // E.g., seeking or reading past end of file. 110 // 111 // Unlike InvalidArgument, this error indicates a problem that may 112 // be fixed if the system state changes. For example, a 32-bit file 113 // system will generate InvalidArgument if asked to read at an 114 // offset that is not in the range [0,2^32-1], but it will generate 115 // OutOfRange if asked to read from an offset past the current 116 // file size. 117 // 118 // There is a fair bit of overlap between FailedPrecondition and 119 // OutOfRange. We recommend using OutOfRange (the more specific 120 // error) when it applies so that callers who are iterating through 121 // a space can easily look for an OutOfRange error to detect when 122 // they are done. 123 OutOfRange Code = -11 124 125 // Unimplemented indicates operation is not implemented or not 126 // supported/enabled in this service. [HTTP] 127 Unimplemented Code = -12 128 129 // Internal errors [HTTP]. 130 // 131 // Means some invariants expected by underlying 132 // system has been broken. If you see one of these errors, 133 // something is very broken. 134 Internal Code = -13 135 136 // Unavailable indicates the service is currently unavailable. [HTTP] 137 // This is a most likely a transient condition and may be corrected 138 // by retrying with a backoff. Note that it is not always safe to 139 // retry non-idempotent operations. 140 // 141 // See litmus test above for deciding between FailedPrecondition, 142 // Aborted, and Unavailable. 143 Unavailable Code = -14 144 145 // DataLoss indicates unrecoverable data loss or corruption. [HTTP] 146 DataLoss Code = -15 147 148 // Unauthenticated indicates the request does not have valid 149 // authentication credentials for the operation. [HTTP] 150 // 151 // = HTTP 401 Unauthorized 152 Unauthenticated Code = -16 153 154 // RateLimited indicates some flow control algorithm is running. [HTTP] 155 // and applied. 156 // 157 // = HTTP Code 429 158 RateLimited Code = -17 159 160 // BadRequest generates a 400 error. [HTTP] 161 // 162 // = HTTP 400 163 BadRequest Code = -18 164 165 // Conflict generates a 409 error. [HTTP] 166 // 167 // = hTTP 409 168 Conflict Code = -19 169 170 // Forbidden generates a 403 error. [HTTP] 171 Forbidden Code = -20 172 173 // InternalServerError generates a 500 error. [HTTP] 174 InternalServerError Code = -21 175 176 // MethodNotAllowed generates a 405 error. [HTTP] 177 MethodNotAllowed Code = -22 178 179 // Timeout generates a Timeout error. 180 Timeout Code = -23 181 182 // IllegalState is used for the application is entering a 183 // bad state. 184 IllegalState Code = -24 185 186 // IllegalFormat can be used for Format failed, user input parsing 187 // or analysis failed, etc. 188 IllegalFormat Code = -25 189 190 // IllegalArgument is like InvalidArgument but applied on application. 191 IllegalArgument Code = -26 192 193 // InitializationFailed is used for application start up unsuccessfully. 194 InitializationFailed Code = -27 195 196 // DataUnavailable is used for the data fetching failed. 197 DataUnavailable Code = -28 198 199 // UnsupportedOperation is like MethodNotAllowed but applied on application. 200 UnsupportedOperation Code = -29 201 202 // UnsupportedVersion can be used for production continuously iteration. 203 UnsupportedVersion Code = -30 204 205 // MinErrorCode is the lower bound for user-defined Code. 206 MinErrorCode Code = -1000 207 ) 208 209 var strToCode = map[string]Code{ 210 `OK`: OK, 211 `CANCELLED`: Canceled, 212 `UNKNOWN`: Unknown, 213 `INVALID_ARGUMENT`: InvalidArgument, 214 `DEADLINE_EXCEEDED`: DeadlineExceeded, 215 `NOT_FOUND`: NotFound, 216 `ALREADY_EXISTS`: AlreadyExists, 217 `PERMISSION_DENIED`: PermissionDenied, 218 `RESOURCE_EXHAUSTED`: ResourceExhausted, 219 `FAILED_PRECONDITION`: FailedPrecondition, 220 `ABORTED`: Aborted, 221 `OUT_OF_RANGE`: OutOfRange, 222 `UNIMPLEMENTED`: Unimplemented, 223 `INTERNAL`: Internal, 224 `UNAVAILABLE`: Unavailable, 225 `DATA_LOSS`: DataLoss, 226 `UNAUTHENTICATED`: Unauthenticated, 227 `RATE_LIMITED`: RateLimited, 228 `BAD_REQUEST`: BadRequest, 229 `CONFLICT`: Conflict, 230 `FORBIDDEN`: Forbidden, 231 `INTERNAL_SERVER_ERROR`: InternalServerError, 232 `METHOD_NOT_ALLOWED`: MethodNotAllowed, 233 `TIMEOUT`: Timeout, 234 "Illegal Format": IllegalFormat, 235 "Illegal State": IllegalState, 236 "Illegal Argument": IllegalArgument, 237 "Initialization Failed": InitializationFailed, 238 "Data Unavailable": DataUnavailable, 239 "Unsupported Operation": UnsupportedOperation, 240 "Unsupported Version": UnsupportedVersion, 241 } 242 243 var codeToStr = map[Code]string{ 244 OK: `OK`, 245 Canceled: `CANCELLED`, 246 Unknown: `UNKNOWN`, 247 InvalidArgument: `INVALID_ARGUMENT`, 248 DeadlineExceeded: `DEADLINE_EXCEEDED`, 249 NotFound: `NOT_FOUND`, 250 AlreadyExists: `ALREADY_EXISTS`, 251 PermissionDenied: `PERMISSION_DENIED`, 252 ResourceExhausted: `RESOURCE_EXHAUSTED`, 253 FailedPrecondition: `FAILED_PRECONDITION`, 254 Aborted: `ABORTED`, 255 OutOfRange: `OUT_OF_RANGE`, 256 Unimplemented: `UNIMPLEMENTED`, 257 Internal: `INTERNAL`, 258 Unavailable: `UNAVAILABLE`, 259 DataLoss: `DATA_LOSS`, 260 Unauthenticated: `UNAUTHENTICATED`, 261 RateLimited: `RATE_LIMITED`, 262 BadRequest: `BAD_REQUEST`, 263 Conflict: `CONFLICT`, 264 Forbidden: `FORBIDDEN`, 265 InternalServerError: `INTERNAL_SERVER_ERROR`, 266 MethodNotAllowed: `METHOD_NOT_ALLOWED`, 267 Timeout: `TIMEOUT`, 268 IllegalState: "Illegal State", 269 IllegalFormat: "Illegal Format", 270 IllegalArgument: "Illegal Argument", 271 InitializationFailed: "Initialization Failed", 272 DataUnavailable: "Data Unavailable", 273 UnsupportedOperation: "Unsupported Operation", 274 UnsupportedVersion: "Unsupported Version", 275 } 276 277 // 278 // ---------------------------- 279 // 280 281 // New create a new *CodedErr object based an error code 282 func (c Code) New(msg string, args ...interface{}) Buildable { //nolint:revive 283 return Message(msg, args...).WithCode(c).Build() 284 } 285 286 // WithCode for error interface 287 func (c *Code) WithCode(code Code) *Code { 288 *c = code 289 return c 290 } 291 292 // Error for error interface 293 func (c Code) Error() string { return c.String() } 294 295 // String for stringer interface 296 func (c Code) String() string { 297 if x, ok := codeToStr[c]; ok { 298 return x 299 } 300 return codeToStr[Unknown] 301 } 302 303 func (c Code) makeErrorString(line bool) string { //nolint:revive,unparam 304 var buf bytes.Buffer 305 _, _ = buf.WriteString(c.Error()) 306 _, _ = buf.WriteRune(' ') 307 _, _ = buf.WriteRune('(') 308 _, _ = buf.WriteString(strconv.Itoa(int(c))) 309 _, _ = buf.WriteRune(')') 310 return buf.String() 311 } 312 313 func (c Code) Is(other error) bool { 314 if o, ok := other.(Code); ok && o == c { 315 return true 316 } 317 return false 318 } 319 320 // Format formats the stack of Frames according to the fmt.Formatter interface. 321 // 322 // %s lists source files for each Frame in the stack 323 // %v lists the source file and line number for each Frame in the stack 324 // 325 // Format accepts flags that alter the printing of some verbs, as follows: 326 // 327 // %+v Prints filename, function, and line number for each Frame in the stack. 328 func (c Code) Format(s fmt.State, verb rune) { 329 switch verb { 330 case 'v': 331 if s.Flag('+') { 332 _, _ = fmt.Fprintf(s, "%+v", c.makeErrorString(true)) 333 // c.Stack.Format(s, verb) 334 return 335 } 336 fallthrough 337 case 's': 338 _, _ = io.WriteString(s, c.makeErrorString(false)) 339 case 'q': 340 _, _ = fmt.Fprintf(s, "%q", c.makeErrorString(false)) 341 } 342 } 343 344 // Register registers a code and its token string for using later 345 func (c Code) Register(codeName string) (errno Code) { 346 errno = AlreadyExists 347 if c <= MinErrorCode || c > 0 { 348 if _, ok := strToCode[codeName]; !ok { 349 if _, ok = codeToStr[c]; !ok { 350 strToCode[codeName] = c 351 codeToStr[c] = codeName 352 errno = OK 353 } 354 } 355 } 356 return 357 } 358 359 // RegisterCode makes a code integer associated with a name, and 360 // returns the available Code number. 361 // 362 // When a positive integer given as codePositive (such as 3), 363 // it'll be negatived and added errors.MinErrorCode (-1000) so 364 // the final Code number will be -1003. 365 // 366 // When a negative integer given, and it's less than 367 // errors.MinErrorCode, it'll be used as it. 368 // Or an errors.AlreadyExists returned. 369 // 370 // An existing code will be returned directly. 371 // 372 // RegisterCode provides a shortcut to declare a number as Code 373 // as your need. 374 // 375 // The best way is: 376 // 377 // var ErrAck = errors.RegisterCode(3, "cannot ack") // ErrAck will be -1003 378 // var ErrAck = errors.RegisterCode(-1003, "cannot ack) // equivalent with last line 379 func RegisterCode(codePositive int, codeName string) (errno Code) { 380 errno = AlreadyExists 381 applier := func(c Code) { 382 if v, ok := strToCode[codeName]; !ok { 383 if _, ok = codeToStr[c]; !ok { 384 strToCode[codeName] = c 385 codeToStr[c] = codeName 386 errno = c 387 } 388 } else { 389 errno = v 390 } 391 } 392 if codePositive > 0 { 393 c := MinErrorCode - Code(codePositive) 394 applier(c) 395 } else if c := Code(codePositive); c < MinErrorCode { 396 applier(c) 397 } 398 return 399 }