library-go/errors/errors.go

226 lines
4.5 KiB
Go
Raw Normal View History

2024-08-20 15:32:06 +00:00
package errors
import (
"errors"
"fmt"
"net/http"
2024-08-20 15:32:06 +00:00
code2 "code.30cm.net/digimon/library-go/errors/code"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// Scope 全域變數應由服務或模組設置
var Scope = code2.Unset
2024-08-20 15:32:06 +00:00
// LibError 6 碼,服務 2, 大類 2, 詳細錯誤 2
type LibError struct {
category uint32
code uint32
scope uint32
msg string
internalErr error
}
// Error 是錯誤的介面
// 私有屬性 "msg" 的 getter 函數
2024-08-20 15:32:06 +00:00
func (e *LibError) Error() string {
if e == nil {
return ""
}
// 如果 internal err 存在,連接錯誤字串
var internalErrStr string
if e.internalErr != nil {
internalErrStr = e.internalErr.Error()
}
if e.msg != "" {
if internalErrStr != "" {
return fmt.Sprintf("%s: %s", e.msg, internalErrStr)
}
2024-08-20 15:32:06 +00:00
return e.msg
}
generalErrStr := e.GeneralError()
if internalErrStr != "" {
return fmt.Sprintf("%s: %s", generalErrStr, internalErrStr)
}
2024-08-20 15:32:06 +00:00
return generalErrStr
}
// Category 私有屬性 "category" 的 getter 函數
2024-08-20 15:32:06 +00:00
func (e *LibError) Category() uint32 {
if e == nil {
return 0
}
2024-08-20 15:32:06 +00:00
return e.category
}
// Scope 私有屬性 "scope" 的 getter 函數
2024-08-20 15:32:06 +00:00
func (e *LibError) Scope() uint32 {
if e == nil {
return code2.Unset
}
return e.scope
}
// CodeStr 返回帶有零填充的錯誤代碼字串
2024-08-20 15:32:06 +00:00
func (e *LibError) CodeStr() string {
if e == nil {
return "00000"
}
if e.Category() == code2.CatGRPC {
2024-08-27 13:53:58 +00:00
return fmt.Sprintf("%02d%04d", e.Scope(), e.Category()+e.Code())
}
2024-08-27 13:53:58 +00:00
return fmt.Sprintf("%02d%04d", e.Scope(), e.Code())
}
// Code 私有屬性 "code" 的 getter 函數
2024-08-20 15:32:06 +00:00
func (e *LibError) Code() uint32 {
if e == nil {
return code2.OK
}
return e.code
}
2024-08-20 15:32:06 +00:00
func (e *LibError) FullCode() uint32 {
if e == nil {
return 0
}
if e.Category() == code2.CatGRPC {
return e.Scope()*10000 + e.Category() + e.Code()
}
return e.Scope()*10000 + e.Code()
}
// HTTPStatus 返回對應的 HTTP 狀態碼
2024-08-20 15:32:06 +00:00
func (e *LibError) HTTPStatus() int {
if e == nil || e.Code() == code2.OK {
return http.StatusOK
}
// 根據 code 判斷狀態碼
switch e.Code() {
case code2.ResourceInsufficient:
// 400
return http.StatusBadRequest
case code2.Unauthorized, code2.InsufficientPermission:
// 401
return http.StatusUnauthorized
case code2.InsufficientQuota:
// 402
return http.StatusPaymentRequired
case code2.InvalidPosixTime, code2.Forbidden:
// 403
return http.StatusForbidden
case code2.ResourceNotFound:
// 404
return http.StatusNotFound
case code2.ResourceAlreadyExist, code2.InvalidResourceState:
// 409
return http.StatusConflict
case code2.NotValidImplementation:
// 501
return http.StatusNotImplemented
default:
}
// 根據 category 判斷狀態碼
switch e.Category() {
case code2.CatInput:
return http.StatusBadRequest
default:
// 如果沒有符合的條件,返回狀態碼 500
return http.StatusInternalServerError
}
}
// GeneralError 轉換 category 級別錯誤訊息
// 這是給客戶或 API 調用者的一般錯誤訊息
2024-08-20 15:32:06 +00:00
func (e *LibError) GeneralError() string {
if e == nil {
return ""
}
errStr, ok := code2.CatToStr[e.Category()]
if !ok {
return ""
}
return errStr
}
// Is 在執行 errors.Is() 時調用。
// 除非你非常確定你在做什麼,否則不要直接使用這個函數。
// 請使用 errors.Is 代替。
// 此函數比較兩個錯誤變量是否都是 *Err並且具有相同的 code不檢查包裹的內部錯誤
2024-08-20 15:32:06 +00:00
func (e *LibError) Is(f error) bool {
var err *LibError
ok := errors.As(f, &err)
if !ok {
return false
}
2024-08-20 15:32:06 +00:00
return e.Code() == err.Code()
}
// Unwrap 返回底層錯誤
// 解除包裹錯誤的結果本身可能具有 Unwrap 方法;
// 我們稱通過反覆解除包裹產生的錯誤序列為錯誤鏈。
2024-08-20 15:32:06 +00:00
func (e *LibError) Unwrap() error {
if e == nil {
return nil
}
2024-08-20 15:32:06 +00:00
return e.internalErr
}
// Wrap 將內部錯誤設置到 Err 結構
2024-08-20 15:32:06 +00:00
func (e *LibError) Wrap(internalErr error) *LibError {
if e != nil {
e.internalErr = internalErr
}
2024-08-20 15:32:06 +00:00
return e
}
2024-08-20 15:32:06 +00:00
func (e *LibError) GRPCStatus() *status.Status {
if e == nil {
return status.New(codes.OK, "")
}
return status.New(codes.Code(e.FullCode()), e.Error())
}
// 工廠函數
// NewErr 創建新的 Err
2024-08-20 15:32:06 +00:00
func NewErr(scope, category, detail uint32, msg string) *LibError {
return &LibError{
category: category,
code: detail,
scope: scope,
msg: msg,
}
}
// NewGRPCErr 創建新的 gRPC Err
2024-08-20 15:32:06 +00:00
func NewGRPCErr(scope, detail uint32, msg string) *LibError {
return &LibError{
category: code2.CatGRPC,
code: detail,
scope: scope,
msg: msg,
}
}