Files
Aether/_deprecated_py_src/services/provider_ops/actions/base.py
fawney19 1d9c77522a refactor: 移除 Python 后端源码,全面迁移至 Rust gateway 架构
- 删除全部 Python 源码 (src/) 及 Alembic 迁移脚本,归档至 _deprecated_py_src/
- 重构 Rust gateway ai_pipeline: 拆分 planner/finalize 模块,新增 contracts/adaptation 层
- 重组 handlers 模块为 admin/public/proxy/internal/shared 子模块结构
- 新增 executor 模块,引入 Rust 原生数据库迁移 (aether-data/migrations)
- 简化 CI/Docker 构建流程,移除 base image 二级构建,统一为单一 app image
- 移除 Python 相关基础设施文件 (entrypoint.sh, gunicorn_conf.py, Dockerfile.base)
2026-04-03 16:26:16 +08:00

162 lines
4.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Provider 操作抽象基类
"""
from abc import ABC, abstractmethod
from typing import Any
import httpx
from src.services.provider_ops.types import (
ActionResult,
ActionStatus,
ProviderActionType,
)
class ProviderAction(ABC):
"""
提供商操作基类
定义具体的操作逻辑(如查询余额、签到等)。
"""
# 子类需要定义的类属性
action_type: ProviderActionType = ProviderActionType.CUSTOM
display_name: str = "Base Action"
description: str = ""
# 默认缓存时间(秒)
default_cache_ttl: int = 300
def __init__(self, config: dict[str, Any] | None = None):
"""
初始化操作
Args:
config: 操作配置
"""
self.config = config or {}
@abstractmethod
async def execute(self, client: httpx.AsyncClient) -> ActionResult:
"""
执行操作
Args:
client: 已认证的 HTTP 客户端
Returns:
操作结果
"""
pass
def _extract_field(self, data: Any, path: str | None) -> Any:
"""
从响应数据中提取字段
支持点号分隔的路径,如 "data.user.balance"
Args:
data: 响应数据
path: 字段路径
Returns:
提取的值,如果路径无效则返回 None
"""
if not path:
return None
current = data
for key in path.split("."):
if isinstance(current, dict):
current = current.get(key)
elif isinstance(current, list) and key.isdigit():
index = int(key)
current = current[index] if 0 <= index < len(current) else None
else:
return None
if current is None:
return None
return current
def _make_success_result(
self,
data: Any = None,
message: str | None = None,
response_time_ms: int | None = None,
raw_response: dict[str, Any] | None = None,
) -> ActionResult:
"""创建成功结果"""
return ActionResult(
status=ActionStatus.SUCCESS,
action_type=self.action_type,
data=data,
message=message,
response_time_ms=response_time_ms,
raw_response=raw_response,
cache_ttl_seconds=self.default_cache_ttl,
)
def _make_error_result(
self,
status: ActionStatus,
message: str | None = None,
retry_after_seconds: int | None = None,
raw_response: dict[str, Any] | None = None,
) -> ActionResult:
"""创建错误结果"""
return ActionResult(
status=status,
action_type=self.action_type,
message=message,
retry_after_seconds=retry_after_seconds,
raw_response=raw_response,
cache_ttl_seconds=0, # 错误不缓存
)
def _handle_http_error(
self, response: httpx.Response, raw_data: dict[str, Any] | None = None
) -> ActionResult:
"""处理 HTTP 错误响应"""
status_code = response.status_code
if status_code == 401:
return self._make_error_result(
ActionStatus.AUTH_FAILED, "认证失败", raw_response=raw_data
)
elif status_code == 403:
return self._make_error_result(
ActionStatus.AUTH_FAILED, "无权限访问", raw_response=raw_data
)
elif status_code == 404:
# 404 表示接口不存在,通常意味着该功能未开放
return self._make_error_result(
ActionStatus.NOT_SUPPORTED, "功能未开放", raw_response=raw_data
)
elif status_code == 429:
retry_after = response.headers.get("Retry-After")
return self._make_error_result(
ActionStatus.RATE_LIMITED,
"请求频率限制",
retry_after_seconds=int(retry_after) if retry_after else 60,
raw_response=raw_data,
)
else:
return self._make_error_result(
ActionStatus.UNKNOWN_ERROR,
f"HTTP {status_code}: {response.reason_phrase}",
raw_response=raw_data,
)
@classmethod
def get_config_schema(cls) -> dict[str, Any]:
"""
获取操作配置 JSON Schema用于前端表单生成
子类应重写此方法
"""
return {"type": "object", "properties": {}, "required": []}