sync
This commit is contained in:
139
bridge/jackbox/errors.go
Normal file
139
bridge/jackbox/errors.go
Normal file
@@ -0,0 +1,139 @@
|
||||
package jackbox
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Sentinel errors for common failure scenarios
|
||||
var (
|
||||
// ErrNotAuthenticated indicates the client is not authenticated
|
||||
ErrNotAuthenticated = errors.New("not authenticated")
|
||||
|
||||
// ErrAuthFailed indicates authentication failed
|
||||
ErrAuthFailed = errors.New("authentication failed")
|
||||
|
||||
// ErrConnectionLost indicates the WebSocket connection was lost
|
||||
ErrConnectionLost = errors.New("connection lost")
|
||||
|
||||
// ErrTokenExpired indicates the authentication token has expired
|
||||
ErrTokenExpired = errors.New("token expired")
|
||||
|
||||
// ErrInvalidResponse indicates an unexpected response from the API
|
||||
ErrInvalidResponse = errors.New("invalid response from API")
|
||||
|
||||
// ErrSessionNotFound indicates the specified session does not exist
|
||||
ErrSessionNotFound = errors.New("session not found")
|
||||
|
||||
// ErrNotSubscribed indicates not subscribed to any session
|
||||
ErrNotSubscribed = errors.New("not subscribed to any session")
|
||||
)
|
||||
|
||||
// APIError represents an API-related error with context
|
||||
type APIError struct {
|
||||
Op string // Operation that failed (e.g., "vote", "get_session", "authenticate")
|
||||
StatusCode int // HTTP status code
|
||||
Message string // Error message from API
|
||||
Err error // Underlying error
|
||||
}
|
||||
|
||||
func (e *APIError) Error() string {
|
||||
if e.StatusCode > 0 {
|
||||
return fmt.Sprintf("API error during %s (HTTP %d): %s", e.Op, e.StatusCode, e.Message)
|
||||
}
|
||||
if e.Err != nil {
|
||||
return fmt.Sprintf("API error during %s: %s (%v)", e.Op, e.Message, e.Err)
|
||||
}
|
||||
return fmt.Sprintf("API error during %s: %s", e.Op, e.Message)
|
||||
}
|
||||
|
||||
func (e *APIError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
// WebSocketError represents a WebSocket-related error with context
|
||||
type WebSocketError struct {
|
||||
Op string // Operation that failed (e.g., "connect", "subscribe", "send")
|
||||
Err error // Underlying error
|
||||
}
|
||||
|
||||
func (e *WebSocketError) Error() string {
|
||||
return fmt.Sprintf("WebSocket error during %s: %v", e.Op, e.Err)
|
||||
}
|
||||
|
||||
func (e *WebSocketError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
// SessionError represents a session-related error with context
|
||||
type SessionError struct {
|
||||
Op string // Operation that failed (e.g., "subscribe", "get_active")
|
||||
SessionID int // Session ID
|
||||
Err error // Underlying error
|
||||
}
|
||||
|
||||
func (e *SessionError) Error() string {
|
||||
return fmt.Sprintf("session error during %s for session %d: %v", e.Op, e.SessionID, e.Err)
|
||||
}
|
||||
|
||||
func (e *SessionError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
// IsRetryable returns true if the error is transient and the operation should be retried
|
||||
func IsRetryable(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check for known retryable errors
|
||||
if errors.Is(err, ErrConnectionLost) ||
|
||||
errors.Is(err, ErrTokenExpired) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Check for API errors with retryable status codes
|
||||
var apiErr *APIError
|
||||
if errors.As(err, &apiErr) {
|
||||
// 5xx errors are typically retryable
|
||||
if apiErr.StatusCode >= 500 && apiErr.StatusCode < 600 {
|
||||
return true
|
||||
}
|
||||
// 429 Too Many Requests is retryable
|
||||
if apiErr.StatusCode == 429 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// WebSocket errors are generally retryable
|
||||
var wsErr *WebSocketError
|
||||
if errors.As(err, &wsErr) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// IsFatal returns true if the error is fatal and reconnection should not be attempted
|
||||
func IsFatal(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check for known fatal errors
|
||||
if errors.Is(err, ErrAuthFailed) ||
|
||||
errors.Is(err, ErrSessionNotFound) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Check for API errors with fatal status codes
|
||||
var apiErr *APIError
|
||||
if errors.As(err, &apiErr) {
|
||||
// 4xx errors (except 429) are typically fatal
|
||||
if apiErr.StatusCode >= 400 && apiErr.StatusCode < 500 && apiErr.StatusCode != 429 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user