Andrey Meshkov f1791135af Sync v2.11.0
2024-12-05 14:19:25 +03:00

70 lines
1.7 KiB
Go

package backendpb
import (
"context"
"fmt"
"github.com/AdguardTeam/AdGuardDNS/internal/profiledb"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// fixGRPCError converts a gRPC error into an application error, if necessary.
// That includes gRPC deadlines, which do not match [context.DeadlineExceeded]
// correctly.
//
// It also updates the backend gRPC metrics depending on the type, see
// [GRPCMetrics.IncrementErrorCount].
func fixGRPCError(ctx context.Context, mtrc GRPCMetrics, err error) (res error) {
metricsType := GRPCErrOther
defer func() { mtrc.IncrementErrorCount(ctx, metricsType) }()
s, ok := status.FromError(err)
if !ok {
// Return the error as-is.
return err
}
// See https://github.com/grpc/grpc-go/issues/4822.
//
// TODO(d.kolyshev): Remove after the grpc-go issue is fixed.
if s.Code() == codes.DeadlineExceeded {
metricsType = GRPCErrTimeout
return fmt.Errorf("grpc: %w; original message: %s", context.DeadlineExceeded, err)
}
for _, d := range s.Details() {
switch structErr := d.(type) {
case *AuthenticationFailedError:
metricsType = GRPCErrAuthentication
return &profiledb.AuthenticationFailedError{
Message: structErr.Message,
}
case *BadRequestError:
metricsType = GRPCErrBadRequest
return &profiledb.BadRequestError{
Message: structErr.Message,
}
case *DeviceQuotaExceededError:
metricsType = GRPCErrDeviceQuota
return &profiledb.DeviceQuotaExceededError{
Message: structErr.Message,
}
case *RateLimitedError:
metricsType = GRPCErrRateLimit
return &profiledb.RateLimitedError{
Message: structErr.Message,
RetryDelay: structErr.RetryDelay.AsDuration(),
}
}
}
// Return the error as-is.
return err
}