From 5e759bf089a0bde636a9324114f769e7520a37f7 Mon Sep 17 00:00:00 2001 From: Anton Nikiforov Date: Mon, 27 Feb 2023 10:53:27 +0300 Subject: [PATCH] [#2] Remove panic from RPCs Signed-off-by: Anton Nikiforov --- client/accounting.go | 6 +++--- client/client.go | 8 ++++---- client/common.go | 21 ++++++++++++++++----- client/container.go | 42 ++++++++++++++++++++--------------------- client/netmap.go | 11 ++++++----- client/netmap_test.go | 7 +++---- client/object_delete.go | 8 ++++---- client/object_get.go | 26 ++++++++++++------------- client/object_hash.go | 10 +++++----- client/object_put.go | 3 ++- client/object_search.go | 6 +++--- client/reputation.go | 16 ++++++++-------- client/session.go | 4 ++-- 13 files changed, 90 insertions(+), 78 deletions(-) diff --git a/client/accounting.go b/client/accounting.go index 0ebad132..91218696 100644 --- a/client/accounting.go +++ b/client/accounting.go @@ -46,7 +46,7 @@ func (x ResBalanceGet) Amount() accounting.Decimal { // FrostFS status codes are returned as `error`, otherwise, are included // in the returned result structure. // -// Immediately panics if parameters are set incorrectly (see PrmBalanceGet docs). +// Returns an error if parameters are set incorrectly (see PrmBalanceGet docs). // Context is required and must not be nil. It is used for network communication. // // Return statuses: @@ -54,9 +54,9 @@ func (x ResBalanceGet) Amount() accounting.Decimal { func (c *Client) BalanceGet(ctx context.Context, prm PrmBalanceGet) (*ResBalanceGet, error) { switch { case ctx == nil: - panic(panicMsgMissingContext) + return nil, errorMissingContext case !prm.accountSet: - panic("account not set") + return nil, errorAccountNotSet } // form request body diff --git a/client/client.go b/client/client.go index 4c07133e..c13a8717 100644 --- a/client/client.go +++ b/client/client.go @@ -69,7 +69,7 @@ func (c *Client) Init(prm PrmInit) { // argument, otherwise context.Background() is used. Dial returns context // errors, see context package docs for details. // -// Panics if required parameters are set incorrectly, look carefully +// Returns an error if required parameters are set incorrectly, look carefully // at the method documentation. // // One-time method call during application start-up stage (after Init ) is expected. @@ -78,12 +78,12 @@ func (c *Client) Init(prm PrmInit) { // See also Init / Close. func (c *Client) Dial(prm PrmDial) error { if prm.endpoint == "" { - panic("server address is unset or empty") + return errorServerAddrUnset } if prm.timeoutDialSet { if prm.timeoutDial <= 0 { - panic("non-positive timeout") + return errorNonPositiveTimeout } } else { prm.timeoutDial = 5 * time.Second @@ -91,7 +91,7 @@ func (c *Client) Dial(prm PrmDial) error { if prm.streamTimeoutSet { if prm.streamTimeout <= 0 { - panic("non-positive timeout") + return errorNonPositiveTimeout } } else { prm.streamTimeout = 10 * time.Second diff --git a/client/common.go b/client/common.go index 8cee7b83..7b757e75 100644 --- a/client/common.go +++ b/client/common.go @@ -2,6 +2,7 @@ package client import ( "crypto/ecdsa" + "errors" "fmt" "github.com/TrueCloudLab/frostfs-api-go/v2/refs" @@ -70,11 +71,21 @@ func writeXHeadersToMeta(xHeaders []string, h *v2session.RequestMetaHeader) { h.SetXHeaders(hs) } -// panic messages. -const ( - panicMsgMissingContext = "missing context" - panicMsgMissingContainer = "missing container" - panicMsgMissingObject = "missing object" +// error messages. +var ( + errorMissingContext = errors.New("missing context") + errorMissingContainer = errors.New("missing container") + errorMissingObject = errors.New("missing object") + errorAccountNotSet = errors.New("account not set") + errorServerAddrUnset = errors.New("server address is unset or empty") + errorNonPositiveTimeout = errors.New("non-positive timeout") + errorEACLTableNotSet = errors.New("eACL table not set") + errorMissingAnnouncements = errors.New("missing announcements") + errorZeroRangeLength = errors.New("zero range length") + errorMissingRanges = errors.New("missing ranges") + errorZeroEpoch = errors.New("zero epoch") + errorMissingTrusts = errors.New("missing trusts") + errorTrustNotSet = errors.New("current trust value not set") ) // groups all the details required to send a single request and process a response to it. diff --git a/client/container.go b/client/container.go index 23ee5009..8c5ae019 100644 --- a/client/container.go +++ b/client/container.go @@ -77,7 +77,7 @@ func (x ResContainerPut) ID() cid.ID { // // Success can be verified by reading by identifier (see ResContainerPut.ID). // -// Immediately panics if parameters are set incorrectly (see PrmContainerPut docs). +// Returns an error if parameters are set incorrectly (see PrmContainerPut docs). // Context is required and must not be nil. It is used for network communication. // // Return statuses: @@ -86,9 +86,9 @@ func (c *Client) ContainerPut(ctx context.Context, prm PrmContainerPut) (*ResCon // check parameters switch { case ctx == nil: - panic(panicMsgMissingContext) + return nil, errorMissingContext case !prm.cnrSet: - panic(panicMsgMissingContainer) + return nil, errorMissingContainer } // TODO: check private key is set before forming the request @@ -204,7 +204,7 @@ func (x ResContainerGet) Container() container.Container { // FrostFS status codes are returned as `error`, otherwise, are included // in the returned result structure. // -// Immediately panics if parameters are set incorrectly (see PrmContainerGet docs). +// Returns an error if parameters are set incorrectly (see PrmContainerGet docs). // Context is required and must not be nil. It is used for network communication. // // Return statuses: @@ -213,9 +213,9 @@ func (x ResContainerGet) Container() container.Container { func (c *Client) ContainerGet(ctx context.Context, prm PrmContainerGet) (*ResContainerGet, error) { switch { case ctx == nil: - panic(panicMsgMissingContext) + return nil, errorMissingContext case !prm.idSet: - panic(panicMsgMissingContainer) + return nil, errorMissingContainer } var cidV2 refs.ContainerID @@ -304,7 +304,7 @@ func (x ResContainerList) Containers() []cid.ID { // FrostFS status codes are returned as `error`, otherwise, are included // in the returned result structure. // -// Immediately panics if parameters are set incorrectly (see PrmContainerList docs). +// Returns an error if parameters are set incorrectly (see PrmContainerList docs). // Context is required and must not be nil. It is used for network communication. // // Return statuses: @@ -313,9 +313,9 @@ func (c *Client) ContainerList(ctx context.Context, prm PrmContainerList) (*ResC // check parameters switch { case ctx == nil: - panic(panicMsgMissingContext) + return nil, errorMissingContext case !prm.ownerSet: - panic("account not set") + return nil, errorAccountNotSet } // form request body @@ -413,7 +413,7 @@ type ResContainerDelete struct { // // Success can be verified by reading by identifier (see GetContainer). // -// Immediately panics if parameters are set incorrectly (see PrmContainerDelete docs). +// Returns an error if parameters are set incorrectly (see PrmContainerDelete docs). // Context is required and must not be nil. It is used for network communication. // // Exactly one return value is non-nil. Server status return is returned in ResContainerDelete. @@ -425,9 +425,9 @@ func (c *Client) ContainerDelete(ctx context.Context, prm PrmContainerDelete) (* // check parameters switch { case ctx == nil: - panic(panicMsgMissingContext) + return nil, errorMissingContext case !prm.idSet: - panic(panicMsgMissingContainer) + return nil, errorMissingContainer } // sign container ID @@ -528,7 +528,7 @@ func (x ResContainerEACL) Table() eacl.Table { // FrostFS status codes are returned as `error`, otherwise, are included // in the returned result structure. // -// Immediately panics if parameters are set incorrectly (see PrmContainerEACL docs). +// Returns an error if parameters are set incorrectly (see PrmContainerEACL docs). // Context is required and must not be nil. It is used for network communication. // // Return statuses: @@ -539,9 +539,9 @@ func (c *Client) ContainerEACL(ctx context.Context, prm PrmContainerEACL) (*ResC // check parameters switch { case ctx == nil: - panic(panicMsgMissingContext) + return nil, errorMissingContext case !prm.idSet: - panic(panicMsgMissingContainer) + return nil, errorMissingContainer } var cidV2 refs.ContainerID @@ -642,7 +642,7 @@ type ResContainerSetEACL struct { // // Success can be verified by reading by identifier (see EACL). // -// Immediately panics if parameters are set incorrectly (see PrmContainerSetEACL docs). +// Returns an error if parameters are set incorrectly (see PrmContainerSetEACL docs). // Context is required and must not be nil. It is used for network communication. // // Return statuses: @@ -651,9 +651,9 @@ func (c *Client) ContainerSetEACL(ctx context.Context, prm PrmContainerSetEACL) // check parameters switch { case ctx == nil: - panic(panicMsgMissingContext) + return nil, errorMissingContext case !prm.tableSet: - panic("eACL table not set") + return nil, errorEACLTableNotSet } // sign the eACL table @@ -747,7 +747,7 @@ type ResAnnounceSpace struct { // // At this moment success can not be checked. // -// Immediately panics if parameters are set incorrectly (see PrmAnnounceSpace docs). +// Returns an error if parameters are set incorrectly (see PrmAnnounceSpace docs). // Context is required and must not be nil. It is used for network communication. // // Return statuses: @@ -756,9 +756,9 @@ func (c *Client) ContainerAnnounceUsedSpace(ctx context.Context, prm PrmAnnounce // check parameters switch { case ctx == nil: - panic(panicMsgMissingContext) + return nil, errorMissingContext case len(prm.announcements) == 0: - panic("missing announcements") + return nil, errorMissingAnnouncements } // convert list of SDK announcement structures into FrostFS-API v2 list diff --git a/client/netmap.go b/client/netmap.go index 1049e824..52348ddd 100644 --- a/client/netmap.go +++ b/client/netmap.go @@ -47,7 +47,7 @@ func (x ResEndpointInfo) NodeInfo() netmap.NodeInfo { // FrostFS status codes are returned as `error`, otherwise, are included // in the returned result structure. // -// Immediately panics if parameters are set incorrectly (see PrmEndpointInfo docs). +// Returns an error if parameters are set incorrectly (see PrmEndpointInfo docs). // Context is required and must not be nil. It is used for network communication. // // Exactly one return value is non-nil. Server status return is returned in ResEndpointInfo. @@ -58,7 +58,7 @@ func (x ResEndpointInfo) NodeInfo() netmap.NodeInfo { func (c *Client) EndpointInfo(ctx context.Context, prm PrmEndpointInfo) (*ResEndpointInfo, error) { // check context if ctx == nil { - panic(panicMsgMissingContext) + return nil, errorMissingContext } // form request @@ -144,7 +144,7 @@ func (x ResNetworkInfo) Info() netmap.NetworkInfo { // FrostFS status codes are returned as `error`, otherwise, are included // in the returned result structure. // -// Immediately panics if parameters are set incorrectly (see PrmNetworkInfo docs). +// Returns an error if parameters are set incorrectly (see PrmNetworkInfo docs). // Context is required and must not be nil. It is used for network communication. // // Exactly one return value is non-nil. Server status return is returned in ResNetworkInfo. @@ -155,7 +155,7 @@ func (x ResNetworkInfo) Info() netmap.NetworkInfo { func (c *Client) NetworkInfo(ctx context.Context, prm PrmNetworkInfo) (*ResNetworkInfo, error) { // check context if ctx == nil { - panic(panicMsgMissingContext) + return nil, errorMissingContext } // form request @@ -224,6 +224,7 @@ func (x ResNetMapSnapshot) NetMap() netmap.NetMap { // FrostFS status codes are returned as `error`, otherwise, are included // in the returned result structure. // +// Returns an error if parameters are set incorrectly. // Context is required and MUST NOT be nil. It is used for network communication. // // Exactly one return value is non-nil. Server status return is returned in ResNetMapSnapshot. @@ -234,7 +235,7 @@ func (x ResNetMapSnapshot) NetMap() netmap.NetMap { func (c *Client) NetMapSnapshot(ctx context.Context, _ PrmNetMapSnapshot) (*ResNetMapSnapshot, error) { // check context if ctx == nil { - panic(panicMsgMissingContext) + return nil, errorMissingContext } // form request body diff --git a/client/netmap_test.go b/client/netmap_test.go index e2b87914..0b1a8288 100644 --- a/client/netmap_test.go +++ b/client/netmap_test.go @@ -70,10 +70,9 @@ func TestClient_NetMapSnapshot(t *testing.T) { ctx := context.Background() // missing context - require.PanicsWithValue(t, panicMsgMissingContext, func() { - //nolint:staticcheck - _, _ = c.NetMapSnapshot(nil, prm) - }) + //nolint:staticcheck + _, err = c.NetMapSnapshot(nil, prm) + require.ErrorIs(t, err, errorMissingContext, "") // request signature srv.errTransport = errors.New("any error") diff --git a/client/object_delete.go b/client/object_delete.go index 5d89576d..14ed1840 100644 --- a/client/object_delete.go +++ b/client/object_delete.go @@ -114,7 +114,7 @@ func (x ResObjectDelete) Tombstone() oid.ID { // FrostFS status codes are returned as `error`, otherwise, are included // in the returned result structure. // -// Immediately panics if parameters are set incorrectly (see PrmObjectDelete docs). +// Returns an error if parameters are set incorrectly (see PrmObjectDelete docs). // Context is required and must not be nil. It is used for network communication. // // Return statuses: @@ -126,11 +126,11 @@ func (x ResObjectDelete) Tombstone() oid.ID { func (c *Client) ObjectDelete(ctx context.Context, prm PrmObjectDelete) (*ResObjectDelete, error) { switch { case ctx == nil: - panic(panicMsgMissingContext) + return nil, errorMissingContext case prm.addr.GetContainerID() == nil: - panic(panicMsgMissingContainer) + return nil, errorMissingContainer case prm.addr.GetObjectID() == nil: - panic(panicMsgMissingObject) + return nil, errorMissingObject } // form request body diff --git a/client/object_get.go b/client/object_get.go index c90fb899..24f6d4d3 100644 --- a/client/object_get.go +++ b/client/object_get.go @@ -296,17 +296,17 @@ func (x *ObjectReader) Read(p []byte) (int, error) { // The call only opens the transmission channel, explicit fetching is done using the ObjectReader. // Exactly one return value is non-nil. Resulting reader must be finally closed. // -// Immediately panics if parameters are set incorrectly (see PrmObjectGet docs). +// Returns an error if parameters are set incorrectly (see PrmObjectGet docs). // Context is required and must not be nil. It is used for network communication. func (c *Client) ObjectGetInit(ctx context.Context, prm PrmObjectGet) (*ObjectReader, error) { // check parameters switch { case ctx == nil: - panic(panicMsgMissingContext) + return nil, errorMissingContext case prm.addr.GetContainerID() == nil: - panic(panicMsgMissingContainer) + return nil, errorMissingContainer case prm.addr.GetObjectID() == nil: - panic(panicMsgMissingObject) + return nil, errorMissingObject } // form request body @@ -400,7 +400,7 @@ func (x *ResObjectHead) ReadHeader(dst *object.Object) bool { // FrostFS status codes are returned as `error`, otherwise, are included // in the returned result structure. // -// Immediately panics if parameters are set incorrectly (see PrmObjectHead docs). +// Returns an error if parameters are set incorrectly (see PrmObjectHead docs). // Context is required and must not be nil. It is used for network communication. // // Return errors: @@ -417,11 +417,11 @@ func (x *ResObjectHead) ReadHeader(dst *object.Object) bool { func (c *Client) ObjectHead(ctx context.Context, prm PrmObjectHead) (*ResObjectHead, error) { switch { case ctx == nil: - panic(panicMsgMissingContext) + return nil, errorMissingContext case prm.addr.GetContainerID() == nil: - panic(panicMsgMissingContainer) + return nil, errorMissingContainer case prm.addr.GetObjectID() == nil: - panic(panicMsgMissingObject) + return nil, errorMissingObject } var body v2object.HeadRequestBody @@ -663,19 +663,19 @@ func (x *ObjectRangeReader) Read(p []byte) (int, error) { // The call only opens the transmission channel, explicit fetching is done using the ObjectRangeReader. // Exactly one return value is non-nil. Resulting reader must be finally closed. // -// Immediately panics if parameters are set incorrectly (see PrmObjectRange docs). +// Returns an error if parameters are set incorrectly (see PrmObjectRange docs). // Context is required and must not be nil. It is used for network communication. func (c *Client) ObjectRangeInit(ctx context.Context, prm PrmObjectRange) (*ObjectRangeReader, error) { // check parameters switch { case ctx == nil: - panic(panicMsgMissingContext) + return nil, errorMissingContext case prm.addr.GetContainerID() == nil: - panic(panicMsgMissingContainer) + return nil, errorMissingContainer case prm.addr.GetObjectID() == nil: - panic(panicMsgMissingObject) + return nil, errorMissingObject case prm.rng.GetLength() == 0: - panic("zero range length") + return nil, errorZeroRangeLength } // form request body diff --git a/client/object_hash.go b/client/object_hash.go index 5c7fd999..560444fb 100644 --- a/client/object_hash.go +++ b/client/object_hash.go @@ -154,7 +154,7 @@ func (x ResObjectHash) Checksums() [][]byte { // FrostFS status codes are returned as `error`, otherwise, are included // in the returned result structure. // -// Immediately panics if parameters are set incorrectly (see PrmObjectHash docs). +// Returns an error if parameters are set incorrectly (see PrmObjectHash docs). // Context is required and must not be nil. It is used for network communication. // // Return statuses: @@ -167,13 +167,13 @@ func (x ResObjectHash) Checksums() [][]byte { func (c *Client) ObjectHash(ctx context.Context, prm PrmObjectHash) (*ResObjectHash, error) { switch { case ctx == nil: - panic(panicMsgMissingContext) + return nil, errorMissingContext case prm.addr.GetContainerID() == nil: - panic(panicMsgMissingContainer) + return nil, errorMissingContainer case prm.addr.GetObjectID() == nil: - panic(panicMsgMissingObject) + return nil, errorMissingObject case len(prm.body.GetRanges()) == 0: - panic("missing ranges") + return nil, errorMissingRanges } prm.body.SetAddress(&prm.addr) diff --git a/client/object_put.go b/client/object_put.go index 5dcdd7cf..3e9472f0 100644 --- a/client/object_put.go +++ b/client/object_put.go @@ -235,11 +235,12 @@ func (x *ObjectWriter) Close() (*ResObjectPut, error) { // The call only opens the transmission channel, explicit recording is done using the ObjectWriter. // Exactly one return value is non-nil. Resulting writer must be finally closed. // +// Returns an error if parameters are set incorrectly. // Context is required and must not be nil. It is used for network communication. func (c *Client) ObjectPutInit(ctx context.Context, prm PrmObjectPutInit) (*ObjectWriter, error) { // check parameters if ctx == nil { - panic(panicMsgMissingContext) + return nil, errorMissingContext } var w ObjectWriter diff --git a/client/object_search.go b/client/object_search.go index bed47bbf..643499e3 100644 --- a/client/object_search.go +++ b/client/object_search.go @@ -218,15 +218,15 @@ func (x *ObjectListReader) Close() (*ResObjectSearch, error) { // is done using the ObjectListReader. Exactly one return value is non-nil. // Resulting reader must be finally closed. // -// Immediately panics if parameters are set incorrectly (see PrmObjectSearch docs). +// Returns an error if parameters are set incorrectly (see PrmObjectSearch docs). // Context is required and must not be nil. It is used for network communication. func (c *Client) ObjectSearchInit(ctx context.Context, prm PrmObjectSearch) (*ObjectListReader, error) { // check parameters switch { case ctx == nil: - panic(panicMsgMissingContext) + return nil, errorMissingContext case !prm.cnrSet: - panic(panicMsgMissingContainer) + return nil, errorMissingContainer } var cidV2 v2refs.ContainerID diff --git a/client/reputation.go b/client/reputation.go index b719da08..e32026d0 100644 --- a/client/reputation.go +++ b/client/reputation.go @@ -45,7 +45,7 @@ type ResAnnounceLocalTrust struct { // FrostFS status codes are returned as `error`, otherwise, are included // in the returned result structure. // -// Immediately panics if parameters are set incorrectly (see PrmAnnounceLocalTrust docs). +// Returns an error if parameters are set incorrectly (see PrmAnnounceLocalTrust docs). // Context is required and must not be nil. It is used for network communication. // // Return statuses: @@ -54,11 +54,11 @@ func (c *Client) AnnounceLocalTrust(ctx context.Context, prm PrmAnnounceLocalTru // check parameters switch { case ctx == nil: - panic(panicMsgMissingContext) + return nil, errorMissingContext case prm.epoch == 0: - panic("zero epoch") + return nil, errorZeroEpoch case len(prm.trusts) == 0: - panic("missing trusts") + return nil, errorMissingTrusts } // form request body @@ -146,7 +146,7 @@ type ResAnnounceIntermediateTrust struct { // FrostFS status codes are returned as `error`, otherwise, are included // in the returned result structure. // -// Immediately panics if parameters are set incorrectly (see PrmAnnounceIntermediateTrust docs). +// Returns an error if parameters are set incorrectly (see PrmAnnounceIntermediateTrust docs). // Context is required and must not be nil. It is used for network communication. // // Return statuses: @@ -155,11 +155,11 @@ func (c *Client) AnnounceIntermediateTrust(ctx context.Context, prm PrmAnnounceI // check parameters switch { case ctx == nil: - panic(panicMsgMissingContext) + return nil, errorMissingContext case prm.epoch == 0: - panic("zero epoch") + return nil, errorZeroEpoch case !prm.trustSet: - panic("current trust value not set") + return nil, errorTrustNotSet } var trust v2reputation.PeerToPeerTrust diff --git a/client/session.go b/client/session.go index b64999c6..05cb1ae0 100644 --- a/client/session.go +++ b/client/session.go @@ -72,7 +72,7 @@ func (x ResSessionCreate) PublicKey() []byte { // FrostFS status codes are returned as `error`, otherwise, are included // in the returned result structure. // -// Immediately panics if parameters are set incorrectly (see PrmSessionCreate docs). +// Returns an error if parameters are set incorrectly (see PrmSessionCreate docs). // Context is required and must not be nil. It is used for network communication. // // Return statuses: @@ -80,7 +80,7 @@ func (x ResSessionCreate) PublicKey() []byte { func (c *Client) SessionCreate(ctx context.Context, prm PrmSessionCreate) (*ResSessionCreate, error) { // check context if ctx == nil { - panic(panicMsgMissingContext) + return nil, errorMissingContext } ownerKey := c.prm.key.PublicKey