新增 Tlon 渠道扩展,支持在 Yuxi 平台中集成 Tlon/Urbit 去中心化通讯平台。 包含以下功能模块: - tlon_api: Tlon API 客户端封装 - config: 渠道配置管理 - gateway: SSE/WebSocket 网关接入 - sse_client: SSE 客户端 - outbound: 外发消息管理 - send: 消息发送 - security: 安全校验 - auth: 认证管理 - monitor: 渠道状态监控 - status: 会话状态管理 - session: 会话管理 - approval: 审批流程 - channel_mgmt: 频道管理 - channel_ops: 频道操作 - contacts: 联系人管理 - discovery: 服务发现 - doctor: 健康诊断 - expose: 服务暴露 - gallery: 图库管理 - history: 历史记录 - hooks: 钩子管理 - media: 媒体资源处理 - notebook: 笔记本功能 - settings_store: 设置存储 - setup: 初始化设置 - story: 故事功能 - targets: 目标管理 - cite_parser: 引用解析 - utils: 工具函数 - types: 类型定义
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) |