hyapp-server/pkg/xerr/catalog.go

136 lines
8.9 KiB
Go
Raw Permalink 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 "google.golang.org/grpc/codes"
const (
httpStatusBadRequest = 400
httpStatusUnauthorized = 401
httpStatusForbidden = 403
httpStatusNotFound = 404
httpStatusConflict = 409
httpStatusInternalServerError = 500
httpStatusBadGateway = 502
)
// Spec 是错误码注册表中的一条稳定契约。
// GRPCCode 是服务间传输语义PublicCode/PublicMessage 是 gateway 对 App 暴露的 envelope。
type Spec struct {
GRPCCode codes.Code
HTTPStatus int
PublicCode string
PublicMessage string
Retryable bool
}
var catalog = map[Code]Spec{
InvalidArgument: spec(codes.InvalidArgument, httpStatusBadRequest, InvalidArgument, "invalid argument"),
NotFound: spec(codes.NotFound, httpStatusNotFound, NotFound, "not found"),
Conflict: spec(codes.FailedPrecondition, httpStatusConflict, Conflict, "request cannot be completed in current state"),
RoomClosed: spec(codes.FailedPrecondition, httpStatusConflict, RoomClosed, "room closed"),
Unauthorized: spec(codes.Unauthenticated, httpStatusUnauthorized, Unauthorized, "unauthorized"),
PermissionDenied: spec(codes.PermissionDenied, httpStatusForbidden, PermissionDenied, "permission denied"),
ProfileRequired: spec(codes.PermissionDenied, httpStatusForbidden, ProfileRequired, "profile required"),
Unavailable: {
GRPCCode: codes.Unavailable,
HTTPStatus: httpStatusBadGateway,
PublicCode: "UPSTREAM_ERROR",
PublicMessage: "upstream service error",
Retryable: true,
},
Internal: spec(codes.Internal, httpStatusInternalServerError, Internal, "internal error"),
AuthFailed: spec(codes.Unauthenticated, httpStatusUnauthorized, AuthFailed, "authentication failed"),
AuthLoginBlocked: spec(codes.PermissionDenied, httpStatusForbidden, AuthLoginBlocked, "login blocked"),
PasswordAlreadySet: spec(codes.AlreadyExists, httpStatusConflict, PasswordAlreadySet, "password already set"),
UserDisabled: spec(codes.PermissionDenied, httpStatusForbidden, UserDisabled, "permission denied"),
SessionExpired: spec(codes.Unauthenticated, httpStatusUnauthorized, SessionExpired, "unauthorized"),
SessionRevoked: spec(codes.Unauthenticated, httpStatusUnauthorized, SessionRevoked, "unauthorized"),
DisplayUserIDInvalid: spec(codes.InvalidArgument, httpStatusBadRequest, DisplayUserIDInvalid, "invalid argument"),
DisplayUserIDExists: spec(codes.AlreadyExists, httpStatusConflict, DisplayUserIDExists, "display user id already exists"),
DisplayUserIDCooldown: spec(codes.FailedPrecondition, httpStatusConflict, DisplayUserIDCooldown, "display user id change is cooling down"),
DisplayUserIDNotFound: spec(codes.NotFound, httpStatusNotFound, DisplayUserIDNotFound, "not found"),
DisplayUserIDAllocateFailed: spec(codes.Internal, httpStatusInternalServerError, Internal, "internal error"),
DisplayUserIDPrettyNotAvailable: spec(codes.FailedPrecondition, httpStatusConflict, DisplayUserIDPrettyNotAvailable, "pretty display user id is not available"),
DisplayUserIDPrettyActive: spec(codes.FailedPrecondition, httpStatusConflict, DisplayUserIDPrettyActive, "pretty display user id already active"),
DisplayUserIDLeaseExpired: spec(codes.FailedPrecondition, httpStatusConflict, DisplayUserIDLeaseExpired, "pretty display user id lease expired"),
DisplayUserIDPaymentRequired: spec(codes.FailedPrecondition, httpStatusConflict, DisplayUserIDPaymentRequired, "pretty display user id payment required"),
CountryChangeCooldown: spec(codes.FailedPrecondition, httpStatusConflict, CountryChangeCooldown, "country change is cooling down"),
CountryNotFound: spec(codes.NotFound, httpStatusNotFound, CountryNotFound, "not found"),
RegionNotFound: spec(codes.NotFound, httpStatusNotFound, RegionNotFound, "not found"),
RegionCountryConflict: spec(codes.FailedPrecondition, httpStatusConflict, RegionCountryConflict, "country already belongs to another region"),
RegionDisabled: spec(codes.FailedPrecondition, httpStatusConflict, RegionDisabled, "region is disabled"),
RegionMismatch: spec(codes.PermissionDenied, httpStatusForbidden, RegionMismatch, "不是同一个地区"),
InvalidInviteCode: spec(codes.InvalidArgument, httpStatusBadRequest, InvalidInviteCode, "invalid invite code"),
DeviceAlreadyRegistered: spec(
codes.FailedPrecondition,
httpStatusConflict,
DeviceAlreadyRegistered,
"device already registered",
),
InsufficientBalance: spec(codes.FailedPrecondition, httpStatusConflict, InsufficientBalance, "insufficient balance"),
DuplicateBillingCommand: spec(codes.AlreadyExists, httpStatusConflict, DuplicateBillingCommand, "billing command already processed"),
LedgerConflict: spec(codes.Aborted, httpStatusConflict, LedgerConflict, "wallet state changed, please retry"),
CoinSellerNotActive: spec(codes.FailedPrecondition, httpStatusConflict, CoinSellerNotActive, "coin seller is not active"),
CoinSellerStockTypeInvalid: spec(codes.InvalidArgument, httpStatusBadRequest, CoinSellerStockTypeInvalid, "invalid argument"),
CoinSellerStockAmountInvalid: spec(codes.InvalidArgument, httpStatusBadRequest, CoinSellerStockAmountInvalid, "invalid argument"),
CoinSellerPaymentRefDuplicated: spec(codes.AlreadyExists, httpStatusConflict, CoinSellerPaymentRefDuplicated, "payment reference already used"),
IdempotencyConflict: spec(codes.AlreadyExists, httpStatusConflict, IdempotencyConflict, "request payload does not match previous command"),
VIPLevelNotFound: spec(codes.NotFound, httpStatusNotFound, VIPLevelNotFound, "not found"),
VIPLevelDisabled: spec(codes.FailedPrecondition, httpStatusConflict, VIPLevelDisabled, "vip level is disabled"),
VIPDowngradeNotAllowed: spec(codes.FailedPrecondition, httpStatusConflict, VIPDowngradeNotAllowed, "vip downgrade is not allowed"),
VIPRechargeRequired: spec(codes.FailedPrecondition, httpStatusConflict, VIPRechargeRequired, "vip recharge is required"),
RedPacketDisabled: spec(codes.FailedPrecondition, httpStatusConflict, RedPacketDisabled, "red packet is disabled"),
RedPacketInvalidAmountTier: spec(codes.InvalidArgument, httpStatusBadRequest, RedPacketInvalidAmountTier, "invalid argument"),
RedPacketInvalidCountTier: spec(codes.InvalidArgument, httpStatusBadRequest, RedPacketInvalidCountTier, "invalid argument"),
RedPacketAmountTooSmall: spec(codes.InvalidArgument, httpStatusBadRequest, RedPacketAmountTooSmall, "invalid argument"),
RedPacketDailyLimitReached: spec(codes.ResourceExhausted, 429, RedPacketDailyLimitReached, "rate limited"),
RedPacketNotOpen: spec(codes.FailedPrecondition, httpStatusConflict, RedPacketNotOpen, "red packet is not open"),
RedPacketExpired: spec(codes.FailedPrecondition, httpStatusConflict, RedPacketExpired, "red packet expired"),
RedPacketAlreadyClaimed: spec(codes.AlreadyExists, httpStatusConflict, RedPacketAlreadyClaimed, "red packet already claimed"),
RedPacketSoldOut: spec(codes.FailedPrecondition, httpStatusConflict, RedPacketSoldOut, "red packet sold out"),
RuleNotActive: spec(codes.FailedPrecondition, httpStatusConflict, RuleNotActive, "reward rule is not active"),
EventAlreadyConsumed: spec(codes.AlreadyExists, httpStatusConflict, EventAlreadyConsumed, "event already consumed"),
RewardPending: spec(codes.FailedPrecondition, httpStatusConflict, RewardPending, "reward is pending"),
InvalidSection: spec(codes.InvalidArgument, httpStatusBadRequest, InvalidSection, "invalid argument"),
MessageNotFound: spec(codes.NotFound, httpStatusNotFound, MessageNotFound, "not found"),
MessageRecalled: spec(codes.NotFound, httpStatusNotFound, MessageRecalled, "not found"),
PageTokenInvalid: spec(codes.InvalidArgument, httpStatusBadRequest, PageTokenInvalid, "invalid argument"),
RequestConflict: spec(codes.FailedPrecondition, httpStatusConflict, RequestConflict, "request payload does not match existing record"),
ProducerEventConflict: spec(codes.FailedPrecondition, httpStatusConflict, ProducerEventConflict, "producer event payload does not match existing record"),
}
func spec(grpcCode codes.Code, httpStatus int, publicCode Code, publicMessage string) Spec {
return Spec{
GRPCCode: grpcCode,
HTTPStatus: httpStatus,
PublicCode: string(publicCode),
PublicMessage: publicMessage,
}
}
// SpecOf 返回业务码的注册表项。未知业务码降级为 INTERNAL_ERROR避免泄漏未登记 reason。
func SpecOf(code Code) Spec {
if registered, ok := catalog[code]; ok {
return registered
}
return catalog[Internal]
}
// RegisteredCodes 返回当前注册表中全部业务码,供测试和文档生成使用。
func RegisteredCodes() []Code {
registered := make([]Code, 0, len(catalog))
for code := range catalog {
registered = append(registered, code)
}
return registered
}