package notify import ( "context" "errors" "fmt" ) type TransportSendStage string const ( TransportSendStageQueue TransportSendStage = "queue" TransportSendStageWrite TransportSendStage = "write" TransportSendStageReply TransportSendStage = "reply" TransportSendStageTransport TransportSendStage = "transport" ) type TransportSendError struct { Stage TransportSendStage Err error } func (e *TransportSendError) Error() string { if e == nil { return "transport send error" } if e.Err == nil { return fmt.Sprintf("transport send %s failed", e.Stage) } return fmt.Sprintf("transport send %s failed: %v", e.Stage, e.Err) } func (e *TransportSendError) Unwrap() error { if e == nil { return nil } return e.Err } func TransportSendErrorStage(err error) (TransportSendStage, bool) { var sendErr *TransportSendError if !errors.As(err, &sendErr) || sendErr == nil { return "", false } return sendErr.Stage, true } func newTransportSendError(stage TransportSendStage, err error) error { if err == nil { return nil } var sendErr *TransportSendError if errors.As(err, &sendErr) { return err } return &TransportSendError{Stage: stage, Err: normalizeStreamDeadlineError(err)} } // publicContextSendError preserves the legacy public API sentinel when a // context cancellation is the cause of a transport send failure. Internal // callers still receive TransportSendError with its stage information. func publicContextSendError(ctx context.Context, err error) error { if err == nil || ctx == nil { return err } ctxErr := ctx.Err() if ctxErr == nil { return err } normalizedCtxErr := normalizeStreamDeadlineError(ctxErr) if !errors.Is(err, ctxErr) && !errors.Is(err, normalizedCtxErr) { return err } return normalizedCtxErr }