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  }