From 151853a99fd958e5a46bfa0686af528a08a8d22c Mon Sep 17 00:00:00 2001 From: sukun Date: Wed, 25 Jan 2023 08:41:49 +0530 Subject: [PATCH 1/2] Add not supported protocols to returned errors --- client.go | 41 ++++++++++++++++++++++++++++------------- lazyClient.go | 2 +- multistream_test.go | 23 ++++++++++++++++++----- 3 files changed, 47 insertions(+), 19 deletions(-) diff --git a/client.go b/client.go index 506e453..009bc9c 100644 --- a/client.go +++ b/client.go @@ -13,9 +13,17 @@ import ( "strings" ) -// ErrNotSupported is the error returned when the muxer does not support -// the protocol specified for the handshake. -var ErrNotSupported = errors.New("protocol not supported") +// ErrNotSupport is the error returned when the muxer doesn't support +// the protocols tried for the handshake. +type ErrNotSupport[T StringLike] struct { + + // Slice of protocols that were not supported by the muxer + Protos []T +} + +func (e ErrNotSupport[T]) Error() string { + return fmt.Sprintf("protocols not supported: %v", e.Protos) +} // ErrNoProtocols is the error returned when the no protocols have been // specified. @@ -83,14 +91,18 @@ func SelectOneOf[T StringLike](protos []T, rwc io.ReadWriteCloser) (proto T, err // can continue negotiating the rest of the protocols normally. // // This saves us a round trip. - switch err := SelectProtoOrFail(protos[0], rwc); err { + switch err := SelectProtoOrFail(protos[0], rwc); err.(type) { case nil: return protos[0], nil - case ErrNotSupported: // try others + case ErrNotSupport[T]: // try others default: return "", err } - return selectProtosOrFail(protos[1:], rwc) + proto, err = selectProtosOrFail(protos[1:], rwc) + if _, ok := err.(ErrNotSupport[T]); ok { + return "", ErrNotSupport[T]{protos} + } + return proto, err } const simOpenProtocol = "/libp2p/simultaneous-connect" @@ -161,7 +173,11 @@ func clientOpen[T StringLike](protos []T, rwc io.ReadWriteCloser) (T, error) { case protos[0]: return tok, nil case "na": - return selectProtosOrFail(protos[1:], rwc) + proto, err := selectProtosOrFail(protos[1:], rwc) + if _, ok := err.(ErrNotSupport[T]); ok { + return "", ErrNotSupport[T]{protos} + } + return proto, err default: return "", fmt.Errorf("unexpected response: %s", tok) } @@ -170,15 +186,15 @@ func clientOpen[T StringLike](protos []T, rwc io.ReadWriteCloser) (T, error) { func selectProtosOrFail[T StringLike](protos []T, rwc io.ReadWriteCloser) (T, error) { for _, p := range protos { err := trySelect(p, rwc) - switch err { + switch err := err.(type) { case nil: return p, nil - case ErrNotSupported: + case ErrNotSupport[T]: default: return "", err } } - return "", ErrNotSupported + return "", ErrNotSupport[T]{protos} } func simOpen[T StringLike](protos []T, rwc io.ReadWriteCloser) (T, bool, error) { @@ -255,12 +271,11 @@ func simOpenSelectServer[T StringLike](protos []T, rwc io.ReadWriteCloser) (T, e if err = <-werrCh; err != nil { return "", err } - for { tok, err = ReadNextToken[T](rwc) if err == io.EOF { - return "", ErrNotSupported + return "", ErrNotSupport[T]{protos} } if err != nil { @@ -337,7 +352,7 @@ func readProto[T StringLike](proto T, r io.Reader) error { case proto: return nil case "na": - return ErrNotSupported + return ErrNotSupport[T]{[]T{proto}} default: return fmt.Errorf("unrecognized response: %s", tok) } diff --git a/lazyClient.go b/lazyClient.go index 13108cc..43321a1 100644 --- a/lazyClient.go +++ b/lazyClient.go @@ -78,7 +78,7 @@ func (l *lazyClientConn[T]) doReadHandshake() { } if tok == "na" { - l.rerr = ErrNotSupported + l.rerr = ErrNotSupport[T]{[]T{proto}} return } if tok != proto { diff --git a/multistream_test.go b/multistream_test.go index 454e59d..5f3e4c0 100644 --- a/multistream_test.go +++ b/multistream_test.go @@ -21,6 +21,19 @@ func newRwcStrict(t *testing.T, rwc io.ReadWriteCloser) io.ReadWriteCloser { return &rwcStrict{t: t, rwc: rwc} } +func cmpErrNotSupport(e1 error, e2 ErrNotSupport[string]) bool { + e, ok := e1.(ErrNotSupport[string]) + if !ok || len(e.Protos) != len(e2.Protos) { + return false + } + for i := 0; i < len(e.Protos); i++ { + if e.Protos[i] != e2.Protos[i] { + return false + } + } + return true +} + func (s *rwcStrict) Read(b []byte) (int, error) { if s.reading { s.t.Error("concurrent read") @@ -160,7 +173,7 @@ func TestProtocolNegotiationUnsupported(t *testing.T) { c := NewMSSelect(b, "/foo") c.Write([]byte("foo protocol data")) _, err := c.Read([]byte{0}) - if err != ErrNotSupported { + if !cmpErrNotSupport(err, ErrNotSupport[string]{[]string{"/foo"}}) { t.Fatalf("expected protocol /foo to be unsupported, got: %v", err) } c.Close() @@ -349,7 +362,7 @@ func TestSelectFails(t *testing.T) { go mux.Negotiate(a) _, err := SelectOneOf([]string{"/d", "/e"}, b) - if err != ErrNotSupported { + if !cmpErrNotSupport(err, ErrNotSupport[string]{[]string{"/d", "/e"}}) { t.Fatal("expected to not be supported") } } @@ -842,7 +855,7 @@ func TestSimopenClientServerFail(t *testing.T) { }() _, _, err := SelectWithSimopenOrFail([]string{"/b"}, b) - if err != ErrNotSupported { + if !cmpErrNotSupport(err, ErrNotSupport[string]{[]string{"/b"}}) { t.Fatal(err) } b.Close() @@ -936,7 +949,7 @@ func TestSimopenClientClientFail(t *testing.T) { done := make(chan struct{}) go func() { _, _, err := SelectWithSimopenOrFail([]string{"/a"}, b) - if err != ErrNotSupported { + if !cmpErrNotSupport(err, ErrNotSupport[string]{[]string{"/a"}}) { t.Error(err) } b.Close() @@ -944,7 +957,7 @@ func TestSimopenClientClientFail(t *testing.T) { }() _, _, err := SelectWithSimopenOrFail([]string{"/b"}, a) - if err != ErrNotSupported { + if !cmpErrNotSupport(err, ErrNotSupport[string]{[]string{"/b"}}) { t.Fatal(err) } a.Close() From 7a07c29ba4b1055091d6f6a66db6ffd7ac1b90b7 Mon Sep 17 00:00:00 2001 From: sukun Date: Wed, 25 Jan 2023 14:28:11 +0530 Subject: [PATCH 2/2] rename struct to ErrNotSupported --- client.go | 24 ++++++++++++------------ lazyClient.go | 2 +- multistream_test.go | 14 +++++++------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/client.go b/client.go index 009bc9c..9a66501 100644 --- a/client.go +++ b/client.go @@ -13,15 +13,15 @@ import ( "strings" ) -// ErrNotSupport is the error returned when the muxer doesn't support +// ErrNotSupported is the error returned when the muxer doesn't support // the protocols tried for the handshake. -type ErrNotSupport[T StringLike] struct { +type ErrNotSupported[T StringLike] struct { // Slice of protocols that were not supported by the muxer Protos []T } -func (e ErrNotSupport[T]) Error() string { +func (e ErrNotSupported[T]) Error() string { return fmt.Sprintf("protocols not supported: %v", e.Protos) } @@ -94,13 +94,13 @@ func SelectOneOf[T StringLike](protos []T, rwc io.ReadWriteCloser) (proto T, err switch err := SelectProtoOrFail(protos[0], rwc); err.(type) { case nil: return protos[0], nil - case ErrNotSupport[T]: // try others + case ErrNotSupported[T]: // try others default: return "", err } proto, err = selectProtosOrFail(protos[1:], rwc) - if _, ok := err.(ErrNotSupport[T]); ok { - return "", ErrNotSupport[T]{protos} + if _, ok := err.(ErrNotSupported[T]); ok { + return "", ErrNotSupported[T]{protos} } return proto, err } @@ -174,8 +174,8 @@ func clientOpen[T StringLike](protos []T, rwc io.ReadWriteCloser) (T, error) { return tok, nil case "na": proto, err := selectProtosOrFail(protos[1:], rwc) - if _, ok := err.(ErrNotSupport[T]); ok { - return "", ErrNotSupport[T]{protos} + if _, ok := err.(ErrNotSupported[T]); ok { + return "", ErrNotSupported[T]{protos} } return proto, err default: @@ -189,12 +189,12 @@ func selectProtosOrFail[T StringLike](protos []T, rwc io.ReadWriteCloser) (T, er switch err := err.(type) { case nil: return p, nil - case ErrNotSupport[T]: + case ErrNotSupported[T]: default: return "", err } } - return "", ErrNotSupport[T]{protos} + return "", ErrNotSupported[T]{protos} } func simOpen[T StringLike](protos []T, rwc io.ReadWriteCloser) (T, bool, error) { @@ -275,7 +275,7 @@ func simOpenSelectServer[T StringLike](protos []T, rwc io.ReadWriteCloser) (T, e tok, err = ReadNextToken[T](rwc) if err == io.EOF { - return "", ErrNotSupport[T]{protos} + return "", ErrNotSupported[T]{protos} } if err != nil { @@ -352,7 +352,7 @@ func readProto[T StringLike](proto T, r io.Reader) error { case proto: return nil case "na": - return ErrNotSupport[T]{[]T{proto}} + return ErrNotSupported[T]{[]T{proto}} default: return fmt.Errorf("unrecognized response: %s", tok) } diff --git a/lazyClient.go b/lazyClient.go index 43321a1..6145eaf 100644 --- a/lazyClient.go +++ b/lazyClient.go @@ -78,7 +78,7 @@ func (l *lazyClientConn[T]) doReadHandshake() { } if tok == "na" { - l.rerr = ErrNotSupport[T]{[]T{proto}} + l.rerr = ErrNotSupported[T]{[]T{proto}} return } if tok != proto { diff --git a/multistream_test.go b/multistream_test.go index 5f3e4c0..0398a13 100644 --- a/multistream_test.go +++ b/multistream_test.go @@ -21,8 +21,8 @@ func newRwcStrict(t *testing.T, rwc io.ReadWriteCloser) io.ReadWriteCloser { return &rwcStrict{t: t, rwc: rwc} } -func cmpErrNotSupport(e1 error, e2 ErrNotSupport[string]) bool { - e, ok := e1.(ErrNotSupport[string]) +func cmpErrNotSupport(e1 error, e2 ErrNotSupported[string]) bool { + e, ok := e1.(ErrNotSupported[string]) if !ok || len(e.Protos) != len(e2.Protos) { return false } @@ -173,7 +173,7 @@ func TestProtocolNegotiationUnsupported(t *testing.T) { c := NewMSSelect(b, "/foo") c.Write([]byte("foo protocol data")) _, err := c.Read([]byte{0}) - if !cmpErrNotSupport(err, ErrNotSupport[string]{[]string{"/foo"}}) { + if !cmpErrNotSupport(err, ErrNotSupported[string]{[]string{"/foo"}}) { t.Fatalf("expected protocol /foo to be unsupported, got: %v", err) } c.Close() @@ -362,7 +362,7 @@ func TestSelectFails(t *testing.T) { go mux.Negotiate(a) _, err := SelectOneOf([]string{"/d", "/e"}, b) - if !cmpErrNotSupport(err, ErrNotSupport[string]{[]string{"/d", "/e"}}) { + if !cmpErrNotSupport(err, ErrNotSupported[string]{[]string{"/d", "/e"}}) { t.Fatal("expected to not be supported") } } @@ -855,7 +855,7 @@ func TestSimopenClientServerFail(t *testing.T) { }() _, _, err := SelectWithSimopenOrFail([]string{"/b"}, b) - if !cmpErrNotSupport(err, ErrNotSupport[string]{[]string{"/b"}}) { + if !cmpErrNotSupport(err, ErrNotSupported[string]{[]string{"/b"}}) { t.Fatal(err) } b.Close() @@ -949,7 +949,7 @@ func TestSimopenClientClientFail(t *testing.T) { done := make(chan struct{}) go func() { _, _, err := SelectWithSimopenOrFail([]string{"/a"}, b) - if !cmpErrNotSupport(err, ErrNotSupport[string]{[]string{"/a"}}) { + if !cmpErrNotSupport(err, ErrNotSupported[string]{[]string{"/a"}}) { t.Error(err) } b.Close() @@ -957,7 +957,7 @@ func TestSimopenClientClientFail(t *testing.T) { }() _, _, err := SelectWithSimopenOrFail([]string{"/b"}, a) - if !cmpErrNotSupport(err, ErrNotSupport[string]{[]string{"/b"}}) { + if !cmpErrNotSupport(err, ErrNotSupported[string]{[]string{"/b"}}) { t.Fatal(err) } a.Close()