2026-05-19 11:00:28 +00:00
|
|
|
package errs
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
|
|
"gateway/internal/library/errors/code"
|
2026-05-19 13:15:18 +00:00
|
|
|
|
2026-05-19 11:00:28 +00:00
|
|
|
"google.golang.org/grpc/codes"
|
|
|
|
|
"google.golang.org/grpc/status"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// GRPCCode maps the business category to a standard gRPC status code.
|
|
|
|
|
func (e *Error) GRPCCode() codes.Code {
|
|
|
|
|
if e == nil || e.SubCode() == code.OK {
|
|
|
|
|
return codes.OK
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return grpcCodeForCategory(e.Category())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GRPCStatus converts the error to a gRPC status.
|
|
|
|
|
// The business code is embedded in the message as [SSCCCDDD].
|
|
|
|
|
func (e *Error) GRPCStatus() *status.Status {
|
|
|
|
|
if e == nil {
|
|
|
|
|
return status.New(codes.OK, "")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
msg := fmt.Sprintf("[%s] %s", e.DisplayCode(), e.Error())
|
|
|
|
|
if cause := e.Unwrap(); cause != nil {
|
|
|
|
|
msg = fmt.Sprintf("%s: %v", msg, cause)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return status.New(e.GRPCCode(), msg)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func grpcCodeForCategory(cat code.Category) codes.Code {
|
|
|
|
|
switch cat {
|
|
|
|
|
case code.InputInvalidFormat, code.InputNotValidImplementation, code.InputInvalidRange,
|
|
|
|
|
code.InputMissingRequired, code.InputUnsupportedMedia,
|
|
|
|
|
code.ResInsufficient, code.ResInvalidMeasureID, code.ResInvalidFormat,
|
|
|
|
|
code.DBDataConvert, code.SvcHTTP400:
|
|
|
|
|
return codes.InvalidArgument
|
|
|
|
|
|
|
|
|
|
case code.InputPayloadTooLarge, code.PSuTooLarge:
|
|
|
|
|
return codes.InvalidArgument
|
|
|
|
|
|
|
|
|
|
case code.ResNotFound:
|
|
|
|
|
return codes.NotFound
|
|
|
|
|
|
|
|
|
|
case code.DBDuplicate, code.ResAlreadyExist, code.ResInvalidState, code.ResMultiOwner:
|
|
|
|
|
return codes.AlreadyExists
|
|
|
|
|
|
|
|
|
|
case code.ResPreconditionFailed, code.ResLocked:
|
|
|
|
|
return codes.FailedPrecondition
|
|
|
|
|
|
|
|
|
|
case code.AuthUnauthorized, code.AuthExpired, code.AuthInvalidPosixTime, code.AuthSigPayloadMismatch:
|
|
|
|
|
return codes.Unauthenticated
|
|
|
|
|
|
|
|
|
|
case code.AuthForbidden, code.ResInsufficientPerm:
|
|
|
|
|
return codes.PermissionDenied
|
|
|
|
|
|
|
|
|
|
case code.ResExpired, code.ResMigrated:
|
|
|
|
|
return codes.FailedPrecondition
|
|
|
|
|
|
|
|
|
|
case code.SysTooManyRequest, code.ResInsufficientQuota, code.SvcRateLimited:
|
|
|
|
|
return codes.ResourceExhausted
|
|
|
|
|
|
|
|
|
|
case code.SysTimeout:
|
|
|
|
|
return codes.DeadlineExceeded
|
|
|
|
|
|
|
|
|
|
case code.SysClientTimeout:
|
|
|
|
|
return codes.Canceled
|
|
|
|
|
|
|
|
|
|
case code.SysMaintain, code.SvcMaintenance, code.DBUnavailable:
|
|
|
|
|
return codes.Unavailable
|
|
|
|
|
|
|
|
|
|
case code.SvcThirdParty, code.PSuPublish, code.PSuConsume:
|
|
|
|
|
return codes.Unavailable
|
|
|
|
|
|
|
|
|
|
case code.SysNotImplemented, code.AuthMethodNotAllowed:
|
|
|
|
|
return codes.Unimplemented
|
|
|
|
|
|
|
|
|
|
case code.DBError, code.SysInternal, code.SvcInternal:
|
|
|
|
|
return codes.Internal
|
|
|
|
|
|
|
|
|
|
case code.CatGRPC:
|
|
|
|
|
return codes.Unknown
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
return codes.Unknown
|
|
|
|
|
}
|
|
|
|
|
}
|