-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
sado
committed
Oct 8, 2022
1 parent
d307ee3
commit aaaf771
Showing
22 changed files
with
1,652 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
package errors | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
|
||
"google.golang.org/genproto/googleapis/rpc/errdetails" | ||
"google.golang.org/grpc/status" | ||
) | ||
|
||
const ( | ||
// UnknownCode is unknown code for error info. | ||
UnknownCode = 500 | ||
// UnknownReason is unknown reason for error info. | ||
UnknownReason = "" | ||
// SupportPackageIsVersion1 this constant should not be referenced by any other code. | ||
SupportPackageIsVersion1 = true | ||
) | ||
|
||
// Error is a status error. | ||
type Error struct { | ||
Status | ||
cause error | ||
} | ||
|
||
func (e *Error) Error() string { | ||
return fmt.Sprintf("error: code = %d reason = %s message = %s metadata = %v cause = %v", e.Code, e.Reason, e.Message, e.Metadata, e.cause) | ||
} | ||
|
||
// Unwrap provides compatibility for Go 1.13 error chains. | ||
func (e *Error) Unwrap() error { return e.cause } | ||
|
||
// Is matches each error in the chain with the target value. | ||
func (e *Error) Is(err error) bool { | ||
if se := new(Error); errors.As(err, &se) { | ||
return se.Code == e.Code && se.Reason == e.Reason | ||
} | ||
return false | ||
} | ||
|
||
// WithCause with the underlying cause of the error. | ||
func (e *Error) WithCause(cause error) *Error { | ||
err := Clone(e) | ||
err.cause = cause | ||
return err | ||
} | ||
|
||
// WithMetadata with an MD formed by the mapping of key, value. | ||
func (e *Error) WithMetadata(md map[string]string) *Error { | ||
err := Clone(e) | ||
err.Metadata = md | ||
return err | ||
} | ||
|
||
// GRPCStatus returns the Status represented by se. | ||
func (e *Error) GRPCStatus() *status.Status { | ||
s, _ := status.New(ToGRPCCode(int(e.Code)), e.Message). | ||
WithDetails(&errdetails.ErrorInfo{ | ||
Reason: e.Reason, | ||
Metadata: e.Metadata, | ||
}) | ||
return s | ||
} | ||
|
||
// New returns an error object for the code, message. | ||
func New(code int, reason, message string) *Error { | ||
return &Error{ | ||
Status: Status{ | ||
Code: int32(code), | ||
Message: message, | ||
Reason: reason, | ||
}, | ||
} | ||
} | ||
|
||
// Newf New(code fmt.Sprintf(format, a...)) | ||
func Newf(code int, reason, format string, a ...interface{}) *Error { | ||
return New(code, reason, fmt.Sprintf(format, a...)) | ||
} | ||
|
||
// Errorf returns an error object for the code, message and error info. | ||
func Errorf(code int, reason, format string, a ...interface{}) error { | ||
return New(code, reason, fmt.Sprintf(format, a...)) | ||
} | ||
|
||
// Code returns the http code for an error. | ||
// It supports wrapped errors. | ||
func Code(err error) int { | ||
if err == nil { | ||
return 200 //nolint:gomnd | ||
} | ||
return int(FromError(err).Code) | ||
} | ||
|
||
// Reason returns the reason for a particular error. | ||
// It supports wrapped errors. | ||
func Reason(err error) string { | ||
if err == nil { | ||
return UnknownReason | ||
} | ||
return FromError(err).Reason | ||
} | ||
|
||
// Clone deep clone error to a new error. | ||
func Clone(err *Error) *Error { | ||
if err == nil { | ||
return nil | ||
} | ||
metadata := make(map[string]string, len(err.Metadata)) | ||
for k, v := range err.Metadata { | ||
metadata[k] = v | ||
} | ||
return &Error{ | ||
cause: err.cause, | ||
Status: Status{ | ||
Code: err.Code, | ||
Reason: err.Reason, | ||
Message: err.Message, | ||
Metadata: metadata, | ||
}, | ||
} | ||
} | ||
|
||
// FromError try to convert an error to *Error. | ||
// It supports wrapped errors. | ||
func FromError(err error) *Error { | ||
if err == nil { | ||
return nil | ||
} | ||
if se := new(Error); errors.As(err, &se) { | ||
return se | ||
} | ||
gs, ok := status.FromError(err) | ||
if !ok { | ||
return New(UnknownCode, UnknownReason, err.Error()) | ||
} | ||
ret := New( | ||
ToHTTPCode(gs.Code()), | ||
UnknownReason, | ||
gs.Message(), | ||
) | ||
for _, detail := range gs.Details() { | ||
switch d := detail.(type) { | ||
case *errdetails.ErrorInfo: | ||
ret.Reason = d.Reason | ||
return ret.WithMetadata(d.Metadata) | ||
} | ||
} | ||
return ret | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.