From fc0bd12101f8e4ed34191229667c90d701cdf385 Mon Sep 17 00:00:00 2001 From: Evgenii Baidakov Date: Tue, 16 May 2023 12:21:59 +0400 Subject: [PATCH] client: Add separate error for each apistatus Signed-off-by: Evgenii Baidakov --- client/status/common.go | 60 +++++++++++++++++++++++++++++++++++ client/status/object.go | 52 ++++++++++++++++++++++++++++++ client/status/unrecognized.go | 22 +++++++++++-- client/status/v2.go | 2 +- 4 files changed, 132 insertions(+), 4 deletions(-) diff --git a/client/status/common.go b/client/status/common.go index a17c7322..ef33f080 100644 --- a/client/status/common.go +++ b/client/status/common.go @@ -2,10 +2,30 @@ package apistatus import ( "encoding/binary" + "errors" "github.com/nspcc-dev/neofs-api-go/v2/status" ) +// Error describes common error which is a grouping type for any [apistatus] errors. Any [apistatus] error may be checked +// explicitly via it's type of just check the group via errors.Is(err, [apistatus.Error]). +var Error = errors.New("api error") + +var ( + // ErrServerInternal is an instance of ServerInternal error status. It's expected to be used for [errors.Is] + // and MUST NOT be changed. + ErrServerInternal ServerInternal + // ErrWrongMagicNumber is an instance of WrongMagicNumber error status. It's expected to be used for [errors.Is] + // and MUST NOT be changed. + ErrWrongMagicNumber WrongMagicNumber + // ErrSignatureVerification is an instance of SignatureVerification error status. It's expected to be used for [errors.Is] + // and MUST NOT be changed. + ErrSignatureVerification SignatureVerification + // ErrNodeUnderMaintenance is an instance of NodeUnderMaintenance error status. It's expected to be used for [errors.Is] + // and MUST NOT be changed. + ErrNodeUnderMaintenance NodeUnderMaintenance +) + // ServerInternal describes failure statuses related to internal server errors. // Instances provide [Status], [StatusV2] and error interfaces. // @@ -21,6 +41,16 @@ func (x ServerInternal) Error() string { ) } +// Is implements interface for correct checking current error type with [errors.Is]. +func (x ServerInternal) Is(target error) bool { + switch target.(type) { + default: + return false + case ServerInternal, *ServerInternal: + return true + } +} + // implements local interface defined in FromStatusV2 func. func (x *ServerInternal) fromStatusV2(st *status.Status) { x.v2 = *st @@ -69,6 +99,16 @@ func (x WrongMagicNumber) Error() string { ) } +// Is implements interface for correct checking current error type with [errors.Is]. +func (x WrongMagicNumber) Is(target error) bool { + switch target.(type) { + default: + return false + case WrongMagicNumber, *WrongMagicNumber: + return true + } +} + // implements local interface defined in FromStatusV2 func. func (x *WrongMagicNumber) fromStatusV2(st *status.Status) { x.v2 = *st @@ -144,6 +184,16 @@ func (x SignatureVerification) Error() string { ) } +// Is implements interface for correct checking current error type with [errors.Is]. +func (x SignatureVerification) Is(target error) bool { + switch target.(type) { + default: + return false + case SignatureVerification, *SignatureVerification: + return true + } +} + // implements local interface defined in FromStatusV2 func. func (x *SignatureVerification) fromStatusV2(st *status.Status) { x.v2 = *st @@ -203,6 +253,16 @@ func (x NodeUnderMaintenance) Error() string { ) } +// Is implements interface for correct checking current error type with [errors.Is]. +func (x NodeUnderMaintenance) Is(target error) bool { + switch target.(type) { + default: + return false + case NodeUnderMaintenance, *NodeUnderMaintenance: + return true + } +} + func (x *NodeUnderMaintenance) fromStatusV2(st *status.Status) { x.v2 = *st } diff --git a/client/status/object.go b/client/status/object.go index d52c7548..1fbebb68 100644 --- a/client/status/object.go +++ b/client/status/object.go @@ -6,12 +6,24 @@ import ( ) var ( + // ErrObjectLocked is an instance of ObjectLocked error status. It's expected to be used for [errors.Is] + // and MUST NOT be changed. + ErrObjectLocked ObjectLocked // ErrObjectAlreadyRemoved is an instance of ObjectAlreadyRemoved error status. It's expected to be used for [errors.Is] // and MUST NOT be changed. ErrObjectAlreadyRemoved ObjectAlreadyRemoved + // ErrLockNonRegularObject is an instance of LockNonRegularObject error status. It's expected to be used for [errors.Is] + // and MUST NOT be changed. + ErrLockNonRegularObject LockNonRegularObject + // ErrObjectAccessDenied is an instance of ObjectAccessDenied error status. It's expected to be used for [errors.Is] + // and MUST NOT be changed. + ErrObjectAccessDenied ObjectAccessDenied // ErrObjectNotFound is an instance of ObjectNotFound error status. It's expected to be used for [errors.Is] // and MUST NOT be changed. ErrObjectNotFound ObjectNotFound + // ErrObjectOutOfRange is an instance of ObjectOutOfRange error status. It's expected to be used for [errors.Is] + // and MUST NOT be changed. + ErrObjectOutOfRange ObjectOutOfRange ) // ObjectLocked describes status of the failure because of the locked object. @@ -34,6 +46,16 @@ func (x ObjectLocked) Error() string { ) } +// Is implements interface for correct checking current error type with [errors.Is]. +func (x ObjectLocked) Is(target error) bool { + switch target.(type) { + default: + return false + case ObjectLocked, *ObjectLocked: + return true + } +} + // implements local interface defined in FromStatusV2 func. func (x *ObjectLocked) fromStatusV2(st *status.Status) { x.v2 = *st @@ -71,6 +93,16 @@ func (x LockNonRegularObject) Error() string { ) } +// Is implements interface for correct checking current error type with [errors.Is]. +func (x LockNonRegularObject) Is(target error) bool { + switch target.(type) { + default: + return false + case LockNonRegularObject, *LockNonRegularObject: + return true + } +} + // implements local interface defined in FromStatusV2 func. func (x *LockNonRegularObject) fromStatusV2(st *status.Status) { x.v2 = *st @@ -108,6 +140,16 @@ func (x ObjectAccessDenied) Error() string { ) } +// Is implements interface for correct checking current error type with [errors.Is]. +func (x ObjectAccessDenied) Is(target error) bool { + switch target.(type) { + default: + return false + case ObjectAccessDenied, *ObjectAccessDenied: + return true + } +} + // implements local interface defined in FromStatusV2 func. func (x *ObjectAccessDenied) fromStatusV2(st *status.Status) { x.v2 = *st @@ -251,6 +293,16 @@ func (x ObjectOutOfRange) Error() string { ) } +// Is implements interface for correct checking current error type with [errors.Is]. +func (x ObjectOutOfRange) Is(target error) bool { + switch target.(type) { + default: + return false + case ObjectOutOfRange, *ObjectOutOfRange: + return true + } +} + // implements local interface defined in FromStatusV2 func. func (x *ObjectOutOfRange) fromStatusV2(st *status.Status) { x.v2 = *st diff --git a/client/status/unrecognized.go b/client/status/unrecognized.go index 2d6c8e67..a48ee443 100644 --- a/client/status/unrecognized.go +++ b/client/status/unrecognized.go @@ -4,15 +4,31 @@ import ( "github.com/nspcc-dev/neofs-api-go/v2/status" ) -type unrecognizedStatusV2 struct { +// ErrUnrecognizedStatusV2 is an instance of UnrecognizedStatusV2 error status. It's expected to be used for [errors.Is] +// and MUST NOT be changed. +var ErrUnrecognizedStatusV2 UnrecognizedStatusV2 + +// UnrecognizedStatusV2 describes status of the uncertain failure. +// Instances provide [Status], [StatusV2] and error interfaces. +type UnrecognizedStatusV2 struct { v2 status.Status } -func (x unrecognizedStatusV2) Error() string { +func (x UnrecognizedStatusV2) Error() string { return errMessageStatusV2("unrecognized", x.v2.Message()) } +// Is implements interface for correct checking current error type with [errors.Is]. +func (x UnrecognizedStatusV2) Is(target error) bool { + switch target.(type) { + default: + return false + case UnrecognizedStatusV2, *UnrecognizedStatusV2: + return true + } +} + // implements local interface defined in FromStatusV2 func. -func (x *unrecognizedStatusV2) fromStatusV2(st *status.Status) { +func (x *UnrecognizedStatusV2) fromStatusV2(st *status.Status) { x.v2 = *st } diff --git a/client/status/v2.go b/client/status/v2.go index 4216e9dd..c1f406b8 100644 --- a/client/status/v2.go +++ b/client/status/v2.go @@ -95,7 +95,7 @@ func FromStatusV2(st *status.Status) Status { } if decoder == nil { - decoder = new(unrecognizedStatusV2) + decoder = new(UnrecognizedStatusV2) } decoder.fromStatusV2(st)