package kmsvc import ( "errors" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) // Sentinel errors callers can match with errors.Is, so they never need to // import google.golang.org/grpc/status themselves. var ( ErrQueueNotFound = errors.New("kmsvc: queue not found") ErrAlreadyExists = errors.New("kmsvc: already exists") ErrInvalidArgument = errors.New("kmsvc: invalid argument") ErrUnauthenticated = errors.New("kmsvc: unauthenticated") ErrMessageTooLarge = errors.New("kmsvc: message body too large") ) // mapError wraps a gRPC error with the matching sentinel above (when one // applies) so errors.Is works for callers, while preserving the original // error via %w for inspection/logging. func mapError(err error) error { if err == nil { return nil } st, ok := status.FromError(err) if !ok { return err } switch st.Code() { case codes.NotFound: return joinSentinel(ErrQueueNotFound, err) case codes.AlreadyExists: return joinSentinel(ErrAlreadyExists, err) case codes.InvalidArgument: return joinSentinel(ErrInvalidArgument, err) case codes.Unauthenticated: return joinSentinel(ErrUnauthenticated, err) case codes.ResourceExhausted: return joinSentinel(ErrMessageTooLarge, err) default: return err } } func joinSentinel(sentinel, original error) error { return &sentinelError{sentinel: sentinel, original: original} } type sentinelError struct { sentinel error original error } func (e *sentinelError) Error() string { return e.original.Error() } func (e *sentinelError) Unwrap() error { return e.original } func (e *sentinelError) Is(target error) bool { return target == e.sentinel }