package errors import ( "errors" "fmt" "net/http" "haixun-backend/internal/library/errors/code" ) type Error struct { scope code.Scope category code.Category detail code.Detail message string cause error } func New(scope code.Scope, category code.Category, detail code.Detail, message string) *Error { return &Error{scope: scope, category: category, detail: detail, message: message} } func FromError(err error) *Error { var e *Error if errors.As(err, &e) { return e } return nil } func (e *Error) Error() string { if e == nil { return "" } return e.message } func (e *Error) Unwrap() error { if e == nil { return nil } return e.cause } func (e *Error) WithCause(cause error) *Error { if e == nil { return nil } cp := *e cp.cause = cause return &cp } func (e *Error) Scope() code.Scope { if e == nil { return code.Unset } return e.scope } func (e *Error) Category() code.Category { if e == nil { return code.SysInternal } return e.category } func (e *Error) Detail() code.Detail { if e == nil { return code.DefaultDetail } return e.detail } func (e *Error) Code() uint32 { if e == nil { return 0 } return uint32(e.scope)*code.ScopeMultiplier + uint32(e.category)*code.CategoryMultiplier + uint32(e.detail) } func (e *Error) DisplayCode() string { if e == nil { return "00000000" } return fmt.Sprintf("%08d", e.Code()) } func (e *Error) HTTPStatus() int { if e == nil { return http.StatusInternalServerError } switch e.category { case code.InputInvalidFormat, code.InputMissingRequired: return http.StatusBadRequest case code.DBUnavailable: return http.StatusServiceUnavailable case code.ResNotFound: return http.StatusNotFound case code.ResConflict: return http.StatusConflict case code.ResInvalidState: return http.StatusConflict case code.AuthUnauthorized: return http.StatusUnauthorized case code.AuthForbidden: return http.StatusForbidden case code.SvcThirdParty: return http.StatusBadGateway default: return http.StatusInternalServerError } } type Builder struct { scope code.Scope } func For(scope code.Scope) Builder { return Builder{scope: scope} } func (b Builder) InputInvalidFormat(message string) *Error { return New(b.scope, code.InputInvalidFormat, 0, message) } func (b Builder) InputMissingRequired(message string) *Error { return New(b.scope, code.InputMissingRequired, 0, message) } func (b Builder) DBError(message string) *Error { return New(b.scope, code.DBError, 0, message) } func (b Builder) DBUnavailable(message string) *Error { return New(b.scope, code.DBUnavailable, 0, message) } func (b Builder) ResNotFound(message string) *Error { return New(b.scope, code.ResNotFound, 0, message) } func (b Builder) ResConflict(message string) *Error { return New(b.scope, code.ResConflict, 0, message) } func (b Builder) ResInvalidState(message string) *Error { return New(b.scope, code.ResInvalidState, 0, message) } func (b Builder) AuthUnauthorized(message string) *Error { return New(b.scope, code.AuthUnauthorized, 0, message) } func (b Builder) AuthForbidden(message string) *Error { return New(b.scope, code.AuthForbidden, 0, message) } func (b Builder) SysInternal(message string) *Error { return New(b.scope, code.SysInternal, 0, message) } func (b Builder) SysNotImplemented(message string) *Error { return New(b.scope, code.SysNotImplemented, 0, message) } func (b Builder) SvcThirdParty(message string) *Error { return New(b.scope, code.SvcThirdParty, 0, message) }