2019-09-19 05:46:39 +01:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package rpcstatus
|
|
|
|
|
|
|
|
import (
|
2019-10-17 20:21:20 +01:00
|
|
|
"context"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
|
2019-09-19 05:46:39 +01:00
|
|
|
"google.golang.org/grpc/codes"
|
|
|
|
"google.golang.org/grpc/status"
|
2019-10-17 20:21:20 +01:00
|
|
|
|
|
|
|
"storj.io/drpc/drpcerr"
|
2019-09-19 05:46:39 +01:00
|
|
|
)
|
|
|
|
|
2019-11-18 22:44:11 +00:00
|
|
|
// StatusCode is an enumeration of rpc status codes.
|
2019-10-17 20:21:20 +01:00
|
|
|
type StatusCode uint64
|
2019-09-19 05:46:39 +01:00
|
|
|
|
2019-11-18 22:44:11 +00:00
|
|
|
// These constants are all the rpc error codes. It is important that
|
|
|
|
// their numerical values do not change.
|
2019-09-19 05:46:39 +01:00
|
|
|
const (
|
2019-10-17 20:21:20 +01:00
|
|
|
Unknown StatusCode = iota
|
|
|
|
OK
|
|
|
|
Canceled
|
|
|
|
InvalidArgument
|
|
|
|
DeadlineExceeded
|
|
|
|
NotFound
|
|
|
|
AlreadyExists
|
|
|
|
PermissionDenied
|
|
|
|
ResourceExhausted
|
|
|
|
FailedPrecondition
|
|
|
|
Aborted
|
|
|
|
OutOfRange
|
|
|
|
Unimplemented
|
|
|
|
Internal
|
|
|
|
Unavailable
|
|
|
|
DataLoss
|
|
|
|
Unauthenticated
|
2019-09-19 05:46:39 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
// Code returns the status code associated with the error.
|
|
|
|
func Code(err error) StatusCode {
|
2019-10-17 20:21:20 +01:00
|
|
|
// special case: if the error is context canceled or deadline exceeded, the code
|
2019-11-18 22:44:11 +00:00
|
|
|
// must be those. additionally, grpc returns OK for a nil error, so we will, too.
|
2019-10-17 20:21:20 +01:00
|
|
|
switch err {
|
2019-11-18 22:44:11 +00:00
|
|
|
case nil:
|
|
|
|
return OK
|
2019-10-17 20:21:20 +01:00
|
|
|
case context.Canceled:
|
|
|
|
return Canceled
|
|
|
|
case context.DeadlineExceeded:
|
|
|
|
return DeadlineExceeded
|
|
|
|
default:
|
2019-11-18 22:44:11 +00:00
|
|
|
if code := StatusCode(drpcerr.Code(err)); code != Unknown {
|
|
|
|
return code
|
|
|
|
}
|
|
|
|
if grpccode := status.Code(err); grpccode != codes.Unknown {
|
|
|
|
return statusCodeFromGRPC(grpccode)
|
2019-10-17 20:21:20 +01:00
|
|
|
}
|
2019-11-18 22:44:11 +00:00
|
|
|
return Unknown
|
2019-10-17 20:21:20 +01:00
|
|
|
}
|
2019-09-19 05:46:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Error wraps the message with a status code into an error.
|
|
|
|
func Error(code StatusCode, msg string) error {
|
2019-10-17 20:21:20 +01:00
|
|
|
return &codeErr{
|
|
|
|
err: errors.New(msg),
|
2019-11-18 22:44:11 +00:00
|
|
|
code: code,
|
|
|
|
grpc: status.New(code.toGRPC(), msg),
|
2019-10-17 20:21:20 +01:00
|
|
|
}
|
2019-09-19 05:46:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Errorf : Error :: fmt.Sprintf : fmt.Sprint
|
|
|
|
func Errorf(code StatusCode, format string, a ...interface{}) error {
|
2019-10-17 20:21:20 +01:00
|
|
|
return &codeErr{
|
|
|
|
err: fmt.Errorf(format, a...),
|
2019-11-18 22:44:11 +00:00
|
|
|
code: code,
|
|
|
|
grpc: status.Newf(code.toGRPC(), format, a...),
|
2019-10-17 20:21:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// codeErr implements error that can work both in grpc and drpc.
|
|
|
|
type codeErr struct {
|
|
|
|
err error
|
2019-11-18 22:44:11 +00:00
|
|
|
code StatusCode
|
2019-10-17 20:21:20 +01:00
|
|
|
grpc *status.Status
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *codeErr) Error() string { return c.err.Error() }
|
|
|
|
func (c *codeErr) Unwrap() error { return c.err }
|
|
|
|
func (c *codeErr) Cause() error { return c.err }
|
2019-11-18 22:44:11 +00:00
|
|
|
func (c *codeErr) Code() uint64 { return uint64(c.code) }
|
2019-10-17 20:21:20 +01:00
|
|
|
func (c *codeErr) GRPCStatus() *status.Status { return c.grpc }
|
|
|
|
|
2019-11-18 22:44:11 +00:00
|
|
|
// toGRPC returns the grpc version of the status code.
|
|
|
|
func (s StatusCode) toGRPC() codes.Code {
|
|
|
|
switch s {
|
2019-10-17 20:21:20 +01:00
|
|
|
case Unknown:
|
|
|
|
return codes.Unknown
|
|
|
|
case OK:
|
|
|
|
return codes.OK
|
|
|
|
case Canceled:
|
|
|
|
return codes.Canceled
|
|
|
|
case InvalidArgument:
|
|
|
|
return codes.InvalidArgument
|
|
|
|
case DeadlineExceeded:
|
|
|
|
return codes.DeadlineExceeded
|
|
|
|
case NotFound:
|
|
|
|
return codes.NotFound
|
|
|
|
case AlreadyExists:
|
|
|
|
return codes.AlreadyExists
|
|
|
|
case PermissionDenied:
|
|
|
|
return codes.PermissionDenied
|
|
|
|
case ResourceExhausted:
|
|
|
|
return codes.ResourceExhausted
|
|
|
|
case FailedPrecondition:
|
|
|
|
return codes.FailedPrecondition
|
|
|
|
case Aborted:
|
|
|
|
return codes.Aborted
|
|
|
|
case OutOfRange:
|
|
|
|
return codes.OutOfRange
|
|
|
|
case Unimplemented:
|
|
|
|
return codes.Unimplemented
|
|
|
|
case Internal:
|
|
|
|
return codes.Internal
|
|
|
|
case Unavailable:
|
|
|
|
return codes.Unavailable
|
|
|
|
case DataLoss:
|
|
|
|
return codes.DataLoss
|
|
|
|
case Unauthenticated:
|
|
|
|
return codes.Unauthenticated
|
|
|
|
default:
|
|
|
|
return codes.Unknown
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-18 22:44:11 +00:00
|
|
|
// statusCodeFromGRPC turns the grpc status code into a StatusCode.
|
|
|
|
func statusCodeFromGRPC(code codes.Code) StatusCode {
|
2019-10-17 20:21:20 +01:00
|
|
|
switch code {
|
|
|
|
case codes.Unknown:
|
|
|
|
return Unknown
|
|
|
|
case codes.OK:
|
|
|
|
return OK
|
|
|
|
case codes.Canceled:
|
|
|
|
return Canceled
|
|
|
|
case codes.InvalidArgument:
|
|
|
|
return InvalidArgument
|
|
|
|
case codes.DeadlineExceeded:
|
|
|
|
return DeadlineExceeded
|
|
|
|
case codes.NotFound:
|
|
|
|
return NotFound
|
|
|
|
case codes.AlreadyExists:
|
|
|
|
return AlreadyExists
|
|
|
|
case codes.PermissionDenied:
|
|
|
|
return PermissionDenied
|
|
|
|
case codes.ResourceExhausted:
|
|
|
|
return ResourceExhausted
|
|
|
|
case codes.FailedPrecondition:
|
|
|
|
return FailedPrecondition
|
|
|
|
case codes.Aborted:
|
|
|
|
return Aborted
|
|
|
|
case codes.OutOfRange:
|
|
|
|
return OutOfRange
|
|
|
|
case codes.Unimplemented:
|
|
|
|
return Unimplemented
|
|
|
|
case codes.Internal:
|
|
|
|
return Internal
|
|
|
|
case codes.Unavailable:
|
|
|
|
return Unavailable
|
|
|
|
case codes.DataLoss:
|
|
|
|
return DataLoss
|
|
|
|
case codes.Unauthenticated:
|
|
|
|
return Unauthenticated
|
|
|
|
default:
|
|
|
|
return Unknown
|
|
|
|
}
|
2019-09-19 05:46:39 +01:00
|
|
|
}
|