198 lines
4.1 KiB
Go
198 lines
4.1 KiB
Go
package error
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"member/internal/lib/error/code"
|
|
"net/http"
|
|
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
)
|
|
|
|
// TODO Error要移到common 包
|
|
|
|
// Scope global variable should be set by service or module
|
|
var Scope = code.Unset
|
|
|
|
type Err struct {
|
|
category uint32
|
|
code uint32
|
|
scope uint32
|
|
msg string
|
|
internalErr error
|
|
}
|
|
|
|
// Error is the interface of error
|
|
// Getter function of private property "msg"
|
|
func (e *Err) Error() string {
|
|
if e == nil {
|
|
return ""
|
|
}
|
|
|
|
// chain the error string if the internal err exists
|
|
var internalErrStr string
|
|
if e.internalErr != nil {
|
|
internalErrStr = e.internalErr.Error()
|
|
}
|
|
|
|
if e.msg != "" {
|
|
if internalErrStr != "" {
|
|
return fmt.Sprintf("%s: %s", e.msg, internalErrStr)
|
|
}
|
|
return e.msg
|
|
}
|
|
|
|
generalErrStr := e.GeneralError()
|
|
if internalErrStr != "" {
|
|
return fmt.Sprintf("%s: %s", generalErrStr, internalErrStr)
|
|
}
|
|
return generalErrStr
|
|
}
|
|
|
|
// Category getter function of private property "category"
|
|
func (e *Err) Category() uint32 {
|
|
if e == nil {
|
|
return 0
|
|
}
|
|
return e.category
|
|
}
|
|
|
|
// Scope getter function of private property "scope"
|
|
func (e *Err) Scope() uint32 {
|
|
if e == nil {
|
|
return code.Unset
|
|
}
|
|
|
|
return e.scope
|
|
}
|
|
|
|
// CodeStr returns the string of error code with zero padding
|
|
func (e *Err) CodeStr() string {
|
|
if e == nil {
|
|
return "00000"
|
|
}
|
|
|
|
if e.Category() == code.CatGRPC {
|
|
return fmt.Sprintf("%d%04d", e.Scope(), e.Category()+e.Code())
|
|
}
|
|
|
|
return fmt.Sprintf("%d%04d", e.Scope(), e.Code())
|
|
}
|
|
|
|
// Code getter function of private property "code"
|
|
func (e *Err) Code() uint32 {
|
|
if e == nil {
|
|
return code.OK
|
|
}
|
|
|
|
return e.code
|
|
}
|
|
|
|
func (e *Err) FullCode() uint32 {
|
|
if e == nil {
|
|
return 0
|
|
}
|
|
|
|
if e.Category() == code.CatGRPC {
|
|
return e.Scope()*10000 + e.Category() + e.Code()
|
|
}
|
|
|
|
return e.Scope()*10000 + e.Code()
|
|
}
|
|
|
|
// HTTPStatus returns corresponding HTTP status code
|
|
func (e *Err) HTTPStatus() int {
|
|
if e == nil || e.Code() == code.OK {
|
|
return http.StatusOK
|
|
}
|
|
// determine status code by code
|
|
switch e.Code() {
|
|
case code.ResourceInsufficient:
|
|
// 400
|
|
return http.StatusBadRequest
|
|
case code.Unauthorized, code.InsufficientPermission:
|
|
// 401
|
|
return http.StatusUnauthorized
|
|
case code.InsufficientQuota:
|
|
// 402
|
|
return http.StatusPaymentRequired
|
|
case code.InvalidPosixTime, code.Forbidden:
|
|
// 403
|
|
return http.StatusForbidden
|
|
case code.ResourceNotFound:
|
|
// 404
|
|
return http.StatusNotFound
|
|
case code.ResourceAlreadyExist, code.InvalidResourceState:
|
|
// 409
|
|
return http.StatusConflict
|
|
case code.NotValidImplementation:
|
|
// 501
|
|
return http.StatusNotImplemented
|
|
default:
|
|
}
|
|
|
|
// determine status code by category
|
|
switch e.Category() {
|
|
case code.CatInput:
|
|
return http.StatusBadRequest
|
|
default:
|
|
// return status code 500 if none of the condition is met
|
|
return http.StatusInternalServerError
|
|
}
|
|
}
|
|
|
|
// GeneralError transform category level error message
|
|
// It's the general error message for customer/API caller
|
|
func (e *Err) GeneralError() string {
|
|
if e == nil {
|
|
return ""
|
|
}
|
|
|
|
errStr, ok := code.CatToStr[e.Category()]
|
|
if !ok {
|
|
return ""
|
|
}
|
|
|
|
return errStr
|
|
}
|
|
|
|
// Is called when performing errors.Is().
|
|
// DO NOT USE THIS FUNCTION DIRECTLY unless you are very certain about what you're doing.
|
|
// Use errors.Is instead.
|
|
// This function compares if two error variables are both *Err, and have the same code (without checking the wrapped internal error)
|
|
func (e *Err) Is(f error) bool {
|
|
var err *Err
|
|
ok := errors.As(f, &err)
|
|
if !ok {
|
|
return false
|
|
}
|
|
return e.Code() == err.Code()
|
|
}
|
|
|
|
// Unwrap returns the underlying error
|
|
// The result of unwrapping an error may itself have an Unwrap method;
|
|
// we call the sequence of errors produced by repeated unwrapping the error chain.
|
|
func (e *Err) Unwrap() error {
|
|
if e == nil {
|
|
return nil
|
|
}
|
|
return e.internalErr
|
|
}
|
|
|
|
// Wrap sets the internal error to Err struct
|
|
func (e *Err) Wrap(internalErr error) *Err {
|
|
if e != nil {
|
|
e.internalErr = internalErr
|
|
}
|
|
return e
|
|
}
|
|
|
|
func (e *Err) GRPCStatus() *status.Status {
|
|
if e == nil {
|
|
return status.New(codes.OK, "")
|
|
}
|
|
|
|
return status.New(codes.Code(e.FullCode()), e.Error())
|
|
}
|