persona-community-5/pkg/notify/errors.go
jordan bd2f591b98
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
ci/woodpecker/manual/woodpecker Pipeline was successful
Initialize project from skeleton template
2026-02-24 07:39:46 +00:00

70 lines
1.7 KiB
Go

package notify
import (
"errors"
"fmt"
)
// Sentinel errors for programmatic handling.
var (
ErrInvalidConfig = errors.New("invalid configuration")
ErrUnauthorized = errors.New("unauthorized")
ErrForbidden = errors.New("forbidden")
ErrSuppressed = errors.New("recipient suppressed")
ErrHostNotFound = errors.New("host not found")
ErrFromNotFound = errors.New("from address not registered")
ErrValidation = errors.New("validation error")
ErrServerError = errors.New("server error")
ErrRateLimit = errors.New("rate limit exceeded")
)
// APIError represents an error returned by the notify API.
type APIError struct {
StatusCode int
Message string
Code string
err error
}
func (e *APIError) Error() string {
if e.Code != "" {
return fmt.Sprintf("notify api error (status %d): [%s] %s", e.StatusCode, e.Code, e.Message)
}
return fmt.Sprintf("notify api error (status %d): %s", e.StatusCode, e.Message)
}
func (e *APIError) Unwrap() error {
return e.err
}
// classifyError maps an HTTP status and optional error code to a sentinel error.
func classifyError(statusCode int, code string) error {
// Check specific error codes first.
switch code {
case "suppressed":
return ErrSuppressed
case "host_not_found":
return ErrHostNotFound
case "from_not_found":
return ErrFromNotFound
}
// Fall back to HTTP status.
switch {
case statusCode == 401:
return ErrUnauthorized
case statusCode == 403:
return ErrForbidden
case statusCode == 422:
return ErrValidation
case statusCode == 429:
return ErrRateLimit
case statusCode >= 400 && statusCode < 500:
return ErrValidation
case statusCode >= 500:
return ErrServerError
default:
return nil
}
}