hyapp-server/pkg/xerr/errors.go

209 lines
9.1 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"
// RoomClosed 表示房间已被后台关闭,客户端不能再进入。
RoomClosed Code = "ROOM_CLOSED"
// 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"
// AuthLoginBlocked 表示登录入口命中地区、语言、时区或 IP 风控策略。
AuthLoginBlocked Code = "AUTH_LOGIN_BLOCKED"
// 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"
// RegionMismatch 表示当前动作要求双方同一区域,但用户、组织或上级身份的实时区域不一致。
RegionMismatch Code = "REGION_MISMATCH"
// InvalidInviteCode 表示邀请码不存在、停用、跨 App、邀请人不可用或用户尝试自邀。
InvalidInviteCode Code = "INVALID_INVITE_CODE"
// DeviceAlreadyRegistered 表示同一注册设备的账号数量已经达到注册上限,不能继续创建新账号。
DeviceAlreadyRegistered Code = "DEVICE_ALREADY_REGISTERED"
// InsufficientBalance 表示钱包余额不足。
InsufficientBalance Code = "INSUFFICIENT_BALANCE"
// DuplicateBillingCommand 表示账务幂等键命中已处理命令。
DuplicateBillingCommand Code = "DUPLICATE_BILLING_COMMAND"
// LedgerConflict 表示账本并发写入或余额版本冲突。
LedgerConflict Code = "LEDGER_CONFLICT"
// CoinSellerNotActive 表示目标用户不存在 active 币商身份。
CoinSellerNotActive Code = "COIN_SELLER_NOT_ACTIVE"
// CoinSellerStockTypeInvalid 表示币商库存入账类型不属于支持范围。
CoinSellerStockTypeInvalid Code = "COIN_SELLER_STOCK_TYPE_INVALID"
// CoinSellerStockAmountInvalid 表示币商库存金币数或线下付款金额不合法。
CoinSellerStockAmountInvalid Code = "COIN_SELLER_STOCK_AMOUNT_INVALID"
// CoinSellerPaymentRefDuplicated 表示同一 USDT 收款凭证已经入账。
CoinSellerPaymentRefDuplicated Code = "COIN_SELLER_PAYMENT_REF_DUPLICATED"
// IdempotencyConflict 表示 command_id 相同但业务 payload 不一致。
IdempotencyConflict Code = "IDEMPOTENCY_CONFLICT"
// VIPLevelNotFound 表示目标 VIP 等级不存在。
VIPLevelNotFound Code = "VIP_LEVEL_NOT_FOUND"
// VIPLevelDisabled 表示目标 VIP 等级当前不可购买。
VIPLevelDisabled Code = "VIP_LEVEL_DISABLED"
// VIPDowngradeNotAllowed 表示用户当前有效 VIP 等级高于本次购买目标等级。
VIPDowngradeNotAllowed Code = "VIP_DOWNGRADE_NOT_ALLOWED"
// VIPRechargeRequired 表示目标 VIP 等级需要用户先达到累计充值门槛。
VIPRechargeRequired Code = "VIP_RECHARGE_REQUIRED"
// RedPacketDisabled 表示红包功能未启用。
RedPacketDisabled Code = "RED_PACKET_DISABLED"
// RedPacketInvalidAmountTier 表示红包金额不在后台配置档位内。
RedPacketInvalidAmountTier Code = "INVALID_AMOUNT_TIER"
// RedPacketInvalidCountTier 表示红包数量不在后台配置档位内。
RedPacketInvalidCountTier Code = "INVALID_COUNT_TIER"
// RedPacketAmountTooSmall 表示红包总金额小于红包份数,无法保证每份至少 1 金币。
RedPacketAmountTooSmall Code = "RED_PACKET_AMOUNT_TOO_SMALL"
// RedPacketDailyLimitReached 表示用户达到 UTC 当日发送次数上限。
RedPacketDailyLimitReached Code = "DAILY_SEND_LIMIT_REACHED"
// RedPacketNotOpen 表示延迟红包尚未到打开时间。
RedPacketNotOpen Code = "RED_PACKET_NOT_OPEN"
// RedPacketExpired 表示红包已经过期。
RedPacketExpired Code = "RED_PACKET_EXPIRED"
// RedPacketAlreadyClaimed 表示当前用户已领取过该红包。
RedPacketAlreadyClaimed Code = "RED_PACKET_ALREADY_CLAIMED"
// RedPacketSoldOut 表示红包已经被抢完。
RedPacketSoldOut Code = "RED_PACKET_SOLD_OUT"
// RuleNotActive 表示活动规则当前不可用。
RuleNotActive Code = "RULE_NOT_ACTIVE"
// EventAlreadyConsumed 表示活动事件消费幂等命中。
EventAlreadyConsumed Code = "EVENT_ALREADY_CONSUMED"
// RewardPending 表示奖励仍在处理中,不能重复结算。
RewardPending Code = "REWARD_PENDING"
// InvalidSection 表示 App 消息分区不属于 system/activity。
InvalidSection Code = "INVALID_SECTION"
// MessageNotFound 表示消息不存在、已删除、已过期、已撤回或不属于当前用户。
MessageNotFound Code = "MESSAGE_NOT_FOUND"
// MessageRecalled 表示消息已撤回,不能继续展示或操作。
MessageRecalled Code = "MESSAGE_RECALLED"
// PageTokenInvalid 表示分页游标不能解析或不属于当前查询。
PageTokenInvalid Code = "PAGE_TOKEN_INVALID"
// RequestConflict 表示同 command_id 的 fanout 请求 payload 冲突。
RequestConflict Code = "REQUEST_CONFLICT"
// ProducerEventConflict 表示同 producer_event_id 的入箱请求 payload 冲突。
ProducerEventConflict Code = "PRODUCER_EVENT_CONFLICT"
)
// 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"
}