hyapp-server/pkg/xerr/errors.go
2026-04-30 02:30:32 +08:00

149 lines
5.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package xerr
import (
"errors"
"fmt"
)
// Code 是服务内部稳定错误原因。
// 它对应 google.rpc.ErrorInfo.reason而不是 HTTP code 或 gRPC code。
type Code string
const (
// InvalidArgument 表示请求字段、格式或领域约束不合法。
InvalidArgument Code = "INVALID_ARGUMENT"
// NotFound 表示目标实体不存在。
NotFound Code = "NOT_FOUND"
// Conflict 表示唯一键、版本、幂等或状态冲突。
Conflict Code = "CONFLICT"
// Unauthorized 表示身份不存在或认证失败。
Unauthorized Code = "UNAUTHORIZED"
// PermissionDenied 表示已认证但没有执行权限。
PermissionDenied Code = "PERMISSION_DENIED"
// ProfileRequired 表示已登录用户尚未完成 App 最小注册资料,不能进入门禁保护业务。
ProfileRequired Code = "PROFILE_REQUIRED"
// Unavailable 表示依赖或当前服务临时不可用。
Unavailable Code = "UNAVAILABLE"
// Internal 表示不能安全暴露更细原因的内部失败。
Internal Code = "INTERNAL_ERROR"
// AuthFailed 统一短号不存在、未设置密码、密码错误和三方凭证拒绝,避免身份枚举。
AuthFailed Code = "AUTH_FAILED"
// PasswordAlreadySet 表示用户已经设置过密码,不能重复初始化密码身份。
PasswordAlreadySet Code = "PASSWORD_ALREADY_SET"
// UserDisabled 表示用户被禁用或封禁。
UserDisabled Code = "USER_DISABLED"
// SessionExpired 表示 refresh token 或会话已过期。
SessionExpired Code = "SESSION_EXPIRED"
// SessionRevoked 表示 refresh token 或会话已被主动失效。
SessionRevoked Code = "SESSION_REVOKED"
// DisplayUserIDInvalid 表示短号格式不符合 user-service 规则。
DisplayUserIDInvalid Code = "DISPLAY_USER_ID_INVALID"
// DisplayUserIDExists 表示短号已被 active 用户占用。
DisplayUserIDExists Code = "DISPLAY_USER_ID_EXISTS"
// DisplayUserIDCooldown 表示用户仍处在短号修改冷却期。
DisplayUserIDCooldown Code = "DISPLAY_USER_ID_COOLDOWN"
// DisplayUserIDNotFound 表示 active 短号不存在。
DisplayUserIDNotFound Code = "DISPLAY_USER_ID_NOT_FOUND"
// DisplayUserIDAllocateFailed 表示默认短号分配重试耗尽。
DisplayUserIDAllocateFailed Code = "DISPLAY_USER_ID_ALLOCATE_FAILED"
// DisplayUserIDPrettyNotAvailable 表示靓号不可申请、已被租用或被预留。
DisplayUserIDPrettyNotAvailable Code = "DISPLAY_USER_ID_PRETTY_NOT_AVAILABLE"
// DisplayUserIDPrettyActive 表示用户已有 active 靓号租约。
DisplayUserIDPrettyActive Code = "DISPLAY_USER_ID_PRETTY_ACTIVE"
// DisplayUserIDLeaseExpired 表示靓号租约已经过期或不能再被当前操作使用。
DisplayUserIDLeaseExpired Code = "DISPLAY_USER_ID_LEASE_EXPIRED"
// DisplayUserIDPaymentRequired 表示申请靓号缺少有效支付凭证。
DisplayUserIDPaymentRequired Code = "DISPLAY_USER_ID_PAYMENT_REQUIRED"
// CountryChangeCooldown 表示用户仍处在国家修改冷却期。
CountryChangeCooldown Code = "COUNTRY_CHANGE_COOLDOWN"
// CountryNotFound 表示国家主数据不存在或已经停用。
CountryNotFound Code = "COUNTRY_NOT_FOUND"
// RegionNotFound 表示区域主数据不存在。
RegionNotFound Code = "REGION_NOT_FOUND"
// RegionCountryConflict 表示国家已经归属其他 active 区域。
RegionCountryConflict Code = "REGION_COUNTRY_CONFLICT"
// RegionDisabled 表示区域已经停用,不能继续配置国家。
RegionDisabled Code = "REGION_DISABLED"
// InsufficientBalance 表示钱包余额不足。
InsufficientBalance Code = "INSUFFICIENT_BALANCE"
// DuplicateBillingCommand 表示账务幂等键命中已处理命令。
DuplicateBillingCommand Code = "DUPLICATE_BILLING_COMMAND"
// LedgerConflict 表示账本并发写入或余额版本冲突。
LedgerConflict Code = "LEDGER_CONFLICT"
// RuleNotActive 表示活动规则当前不可用。
RuleNotActive Code = "RULE_NOT_ACTIVE"
// EventAlreadyConsumed 表示活动事件消费幂等命中。
EventAlreadyConsumed Code = "EVENT_ALREADY_CONSUMED"
// RewardPending 表示奖励仍在处理中,不能重复结算。
RewardPending Code = "REWARD_PENDING"
)
// Error 是 domain/service 层统一返回的业务错误。
// 该类型不依赖任何传输层包,避免业务代码直接绑定 gRPC status。
type Error struct {
Code Code
Message string
}
// Error 实现标准 error 接口。
func (e *Error) Error() string {
return fmt.Sprintf("%s: %s", e.Code, e.Message)
}
// Is 让 errors.Is 可以按稳定 reason 判断业务错误。
func (e *Error) Is(target error) bool {
typed, ok := target.(*Error)
return ok && e.Code == typed.Code
}
// New 构造带稳定 reason 的业务错误。
func New(code Code, message string) error {
return &Error{
Code: code,
Message: message,
}
}
// As 提取当前仓库约定的业务错误。
func As(err error) (*Error, bool) {
if err == nil {
return nil, false
}
var typed *Error
if errors.As(err, &typed) {
return typed, true
}
return nil, false
}
// CodeOf 安全提取错误 reason。
func CodeOf(err error) Code {
if typed, ok := As(err); ok {
return typed.Code
}
if err == nil {
return ""
}
return Internal
}
// MessageOf 安全提取可返回给内部调用方的短错误描述。
func MessageOf(err error) string {
if typed, ok := As(err); ok {
return typed.Message
}
if err == nil {
return ""
}
return "internal error"
}