package internal import ( "errors" "fmt" "time" ) type PollingSignalErrorType int const ( PollingSignalErrorTypeStopTrying PollingSignalErrorType = iota PollingSignalErrorTypeTryAgainAfter ) type PollingSignalError interface { error Wrap(err error) PollingSignalError Attach(description string, obj any) PollingSignalError Now() } var StopTrying = func(message string) PollingSignalError { return &PollingSignalErrorImpl{ message: message, pollingSignalErrorType: PollingSignalErrorTypeStopTrying, } } var TryAgainAfter = func(duration time.Duration) PollingSignalError { return &PollingSignalErrorImpl{ message: fmt.Sprintf("told to try again after %s", duration), duration: duration, pollingSignalErrorType: PollingSignalErrorTypeTryAgainAfter, } } type PollingSignalErrorAttachment struct { Description string Object any } type PollingSignalErrorImpl struct { message string wrappedErr error pollingSignalErrorType PollingSignalErrorType duration time.Duration Attachments []PollingSignalErrorAttachment } func (s *PollingSignalErrorImpl) Wrap(err error) PollingSignalError { s.wrappedErr = err return s } func (s *PollingSignalErrorImpl) Attach(description string, obj any) PollingSignalError { s.Attachments = append(s.Attachments, PollingSignalErrorAttachment{description, obj}) return s } func (s *PollingSignalErrorImpl) Error() string { if s.wrappedErr == nil { return s.message } else { return s.message + ": " + s.wrappedErr.Error() } } func (s *PollingSignalErrorImpl) Unwrap() error { if s == nil { return nil } return s.wrappedErr } func (s *PollingSignalErrorImpl) Now() { panic(s) } func (s *PollingSignalErrorImpl) IsStopTrying() bool { return s.pollingSignalErrorType == PollingSignalErrorTypeStopTrying } func (s *PollingSignalErrorImpl) IsTryAgainAfter() bool { return s.pollingSignalErrorType == PollingSignalErrorTypeTryAgainAfter } func (s *PollingSignalErrorImpl) TryAgainDuration() time.Duration { return s.duration } func AsPollingSignalError(actual interface{}) (*PollingSignalErrorImpl, bool) { if actual == nil { return nil, false } if actualErr, ok := actual.(error); ok { var target *PollingSignalErrorImpl if errors.As(actualErr, &target) { return target, true } else { return nil, false } } return nil, false }