rpcclient: provide some exported error for disconnected WSClient

Regular Client doesn't care much about connections, because HTTP client's Do
method can reuse old ones or create additional ones on the fly. So one request
can fail and the next one easily succeed. WSClient is different, it works via
a single connection and if it breaks, it breaks forever for this
client. Callers will get some error on every request afterwards and it'd be
nice for this error to be the same so that API users could detect
disconnection this way too.

Related to nspcc-dev/neofs-node#2325.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
This commit is contained in:
Roman Khimov 2023-05-03 16:01:46 +03:00
parent 8bd9a7d420
commit fcaa24f928
2 changed files with 11 additions and 5 deletions

View file

@ -454,6 +454,11 @@ const (
// ErrNilNotificationReceiver is returned when notification receiver channel is nil.
var ErrNilNotificationReceiver = errors.New("nil notification receiver")
// ErrWSConnLost is a WSClient-specific error that will be returned for any
// requests after disconnection (including intentional ones via
// (*WSClient).Close).
var ErrWSConnLost = errors.New("connection lost")
// errConnClosedByUser is a WSClient error used iff the user calls (*WSClient).Close method by himself.
var errConnClosedByUser = errors.New("connection closed by user")
@ -735,22 +740,22 @@ func (c *WSClient) makeWsRequest(r *neorpc.Request) (*neorpc.Response, error) {
select {
case <-c.done:
c.respLock.Unlock()
return nil, errors.New("connection lost before registering response channel")
return nil, fmt.Errorf("%w: before registering response channel", ErrWSConnLost)
default:
c.respChannels[r.ID] = ch
c.respLock.Unlock()
}
select {
case <-c.done:
return nil, errors.New("connection lost before sending the request")
return nil, fmt.Errorf("%w: before sending the request", ErrWSConnLost)
case c.requests <- r:
}
select {
case <-c.done:
return nil, errors.New("connection lost while waiting for the response")
return nil, fmt.Errorf("%w: while waiting for the response", ErrWSConnLost)
case resp, ok := <-ch:
if !ok {
return nil, errors.New("connection lost while waiting for the response")
return nil, fmt.Errorf("%w: while waiting for the response", ErrWSConnLost)
}
c.unregisterRespChannel(r.ID)
return resp, nil

View file

@ -3,6 +3,7 @@ package rpcclient
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/http/httptest"
@ -752,7 +753,7 @@ func TestWS_RequestAfterClose(t *testing.T) {
_, err = c.GetBlockCount()
})
require.Error(t, err)
require.True(t, strings.Contains(err.Error(), "connection lost before registering response channel"))
require.True(t, errors.Is(err, ErrWSConnLost))
}
func TestWSClient_ConnClosedError(t *testing.T) {