storj/pkg/rpc/rpcstatus/status_grpc.go
Egon Elbre f929310add pkg/rpc/rpcstatus: fix drpc grpc compatibilty (#3306)
When code is compiled without -tags=drpc the statuses for drpc server
weren't handled, which meant an uplink using -tags=drpc didn't get the
correct status code.
2019-10-17 15:21:20 -04:00

177 lines
3.8 KiB
Go

// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
// +build !drpc
package rpcstatus
import (
"context"
"errors"
"fmt"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"storj.io/drpc/drpcerr"
)
// StatusCode is the type of status codes for drpc.
type StatusCode uint64
// These constants are all the rpc error codes.
const (
Unknown StatusCode = iota
OK
Canceled
InvalidArgument
DeadlineExceeded
NotFound
AlreadyExists
PermissionDenied
ResourceExhausted
FailedPrecondition
Aborted
OutOfRange
Unimplemented
Internal
Unavailable
DataLoss
Unauthenticated
)
// Code returns the status code associated with the error.
func Code(err error) StatusCode {
// special case: if the error is context canceled or deadline exceeded, the code
// must be those.
switch err {
case context.Canceled:
return Canceled
case context.DeadlineExceeded:
return DeadlineExceeded
default:
code := StatusCode(drpcerr.Code(err))
if code == Unknown {
// it's unknown, but it might be a known grpc error
grpccode := status.Code(err)
if grpccode != codes.Unknown {
return codeGRPCToDRPC(grpccode)
}
}
return code
}
}
// Error wraps the message with a status code into an error.
func Error(code StatusCode, msg string) error {
return &codeErr{
err: errors.New(msg),
code: uint64(code),
grpc: status.New(codeDRPCToGRPC(code), msg),
}
}
// Errorf : Error :: fmt.Sprintf : fmt.Sprint
func Errorf(code StatusCode, format string, a ...interface{}) error {
return &codeErr{
err: fmt.Errorf(format, a...),
code: uint64(code),
grpc: status.Newf(codeDRPCToGRPC(code), format, a...),
}
}
// codeErr implements error that can work both in grpc and drpc.
type codeErr struct {
err error
code uint64
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 }
func (c *codeErr) Code() uint64 { return c.code }
func (c *codeErr) GRPCStatus() *status.Status { return c.grpc }
func codeDRPCToGRPC(code StatusCode) codes.Code {
switch code {
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
}
}
func codeGRPCToDRPC(code codes.Code) StatusCode {
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
}
}