152 lines
3.8 KiB
Go
152 lines
3.8 KiB
Go
|
|
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)
|
||
|
|
}
|