notify/peer_error.go

152 lines
3.8 KiB
Go
Raw Permalink Normal View History

package notify
import (
"errors"
"fmt"
"strings"
)
type detailedStateError struct {
base error
detail string
cause error
}
func (e *detailedStateError) Error() string {
if e == nil || e.base == nil {
return ""
}
base := e.base.Error()
detail := strings.TrimSpace(e.detail)
switch {
case detail != "" && e.cause != nil:
return fmt.Sprintf("%s: %s: %v", base, detail, e.cause)
case detail != "":
return fmt.Sprintf("%s: %s", base, detail)
case e.cause != nil:
return fmt.Sprintf("%s: %v", base, e.cause)
default:
return base
}
}
func (e *detailedStateError) Unwrap() error {
if e == nil {
return nil
}
return e.cause
}
func (e *detailedStateError) Is(target error) bool {
if e == nil {
return false
}
return target == e.base || errors.Is(e.cause, target)
}
func newDetailedStateError(base error, detail string, cause error) error {
if base == nil {
return cause
}
detail = strings.TrimSpace(detail)
if detail == "" && cause == nil {
return base
}
return &detailedStateError{
base: base,
detail: detail,
cause: cause,
}
}
func transportDetachedError(detail string, cause error) error {
return newDetailedStateError(errTransportDetached, detail, cause)
}
func clientTransportDetachedError(c *ClientCommon) error {
if c == nil {
return errTransportDetached
}
status := c.Status()
if status.Alive && c.clientTransportAttachedSnapshot() {
return errTransportDetached
}
switch status.Reason {
case "", "recv stop signal from user":
if status.Err != nil {
return transportDetachedError("", status.Err)
}
return errTransportDetached
default:
return transportDetachedError(status.Reason, status.Err)
}
}
func transportDetachedErrorForLogical(logical *LogicalConn) error {
if logical == nil {
return errTransportDetached
}
if detach := logical.transportDetachSnapshot(); detach != nil {
detail := strings.TrimSpace(detach.Reason)
if detach.Generation != 0 {
if detail == "" {
detail = fmt.Sprintf("generation=%d", detach.Generation)
} else {
detail = fmt.Sprintf("%s [generation=%d]", detail, detach.Generation)
}
}
if detach.Err != "" {
return transportDetachedError(detail, errors.New(detach.Err))
}
return transportDetachedError(detail, nil)
}
status := logical.Status()
if !status.Alive && (status.Reason != "" || status.Err != nil) {
return transportDetachedError(status.Reason, status.Err)
}
return errTransportDetached
}
func transportDetachedErrorForTransport(transport *TransportConn) error {
if transport == nil {
return errTransportDetached
}
if logical := transport.logicalConnSnapshot(); logical != nil {
if err := transportDetachedErrorForLogical(logical); err != errTransportDetached {
return err
}
}
switch {
case !transport.Attached():
return transportDetachedError(fmt.Sprintf("transport generation=%d not attached", transport.TransportGeneration()), nil)
case !transport.HasRuntimeConn():
return transportDetachedError(fmt.Sprintf("transport generation=%d has no runtime conn", transport.TransportGeneration()), nil)
case !transport.IsCurrent():
return transportDetachedError(fmt.Sprintf("stale transport generation=%d", transport.TransportGeneration()), nil)
default:
return errTransportDetached
}
}
func transportDetachedErrorForPeer(logical *LogicalConn, transport *TransportConn) error {
if transport != nil {
return transportDetachedErrorForTransport(transport)
}
return transportDetachedErrorForLogical(logical)
}
func transportDetachedGenerationMismatchError(expected uint64, transport *TransportConn) error {
actual := uint64(0)
if transport != nil {
actual = transport.TransportGeneration()
}
return transportDetachedError(
fmt.Sprintf("transport generation mismatch expected=%d actual=%d", expected, actual),
nil,
)
}
func transportDetachedSessionEpochError() error {
return transportDetachedError("stale client session epoch", nil)
}