78 lines
2.0 KiB
Python
78 lines
2.0 KiB
Python
|
|
from yuxi.channel.errors import ErrorSeverity
|
||
|
|
|
||
|
|
|
||
|
|
class UrbitError(Exception):
|
||
|
|
pass
|
||
|
|
|
||
|
|
|
||
|
|
class UrbitUrlError(UrbitError):
|
||
|
|
pass
|
||
|
|
|
||
|
|
|
||
|
|
class UrbitHttpError(UrbitError):
|
||
|
|
def __init__(self, status: int, body: str = ""):
|
||
|
|
self.status = status
|
||
|
|
self.body = body
|
||
|
|
super().__init__(f"HTTP {status}: {body}")
|
||
|
|
|
||
|
|
@property
|
||
|
|
def severity(self) -> ErrorSeverity:
|
||
|
|
if self.status == 429:
|
||
|
|
return ErrorSeverity.RATE_LIMITED
|
||
|
|
if self.status in (401, 403):
|
||
|
|
return ErrorSeverity.FORBIDDEN
|
||
|
|
if self.status >= 500:
|
||
|
|
return ErrorSeverity.RETRYABLE
|
||
|
|
if self.status >= 400:
|
||
|
|
return ErrorSeverity.FATAL
|
||
|
|
return ErrorSeverity.RETRYABLE
|
||
|
|
|
||
|
|
|
||
|
|
class UrbitAuthError(UrbitError):
|
||
|
|
pass
|
||
|
|
|
||
|
|
|
||
|
|
class UrbitSSEError(UrbitError):
|
||
|
|
pass
|
||
|
|
|
||
|
|
|
||
|
|
class UrbitPokeError(UrbitError):
|
||
|
|
pass
|
||
|
|
|
||
|
|
|
||
|
|
class UrbitScryError(UrbitError):
|
||
|
|
pass
|
||
|
|
|
||
|
|
|
||
|
|
_ERROR_SEVERITY_MAP = {
|
||
|
|
UrbitAuthError: ErrorSeverity.FATAL,
|
||
|
|
UrbitSSEError: ErrorSeverity.RETRYABLE,
|
||
|
|
UrbitPokeError: ErrorSeverity.RETRYABLE,
|
||
|
|
UrbitScryError: ErrorSeverity.RETRYABLE,
|
||
|
|
UrbitUrlError: ErrorSeverity.FATAL,
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def classify_error(error: BaseException) -> object:
|
||
|
|
from yuxi.channel.protocols import ClassifiedError
|
||
|
|
|
||
|
|
if isinstance(error, UrbitHttpError):
|
||
|
|
return ClassifiedError(severity=error.severity, original_error=error, error_message=str(error))
|
||
|
|
|
||
|
|
severity = ErrorSeverity.RETRYABLE
|
||
|
|
for exc_type, sev in _ERROR_SEVERITY_MAP.items():
|
||
|
|
if isinstance(error, exc_type):
|
||
|
|
severity = sev
|
||
|
|
break
|
||
|
|
|
||
|
|
return ClassifiedError(severity=severity, original_error=error, error_message=str(error))
|
||
|
|
|
||
|
|
|
||
|
|
def is_retryable(error: BaseException) -> bool:
|
||
|
|
if isinstance(error, UrbitHttpError):
|
||
|
|
return error.severity in (ErrorSeverity.RETRYABLE, ErrorSeverity.RATE_LIMITED)
|
||
|
|
if isinstance(error, UrbitAuthError):
|
||
|
|
return False
|
||
|
|
if isinstance(error, UrbitUrlError):
|
||
|
|
return False
|
||
|
|
return isinstance(error, UrbitError)
|