mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 17:30:23 +08:00
chore: 升级到 Python 3.14 并现代化代码
- 升级 Docker 基础镜像从 Python 3.12 到 3.14 - 更新 pyproject.toml 支持 Python 3.13/3.14 - 移除 Python 3.8/3.9/3.10/3.11 分类器 - 更新 black 和 mypy 配置目标版本 - 将 get_event_loop() 替换为 get_running_loop() 加上 RuntimeError 处理 - 简化 compute_cost_sync 中的 asyncio.run 使用 - Dict/List/Tuple/Set → dict/list/tuple/set (PEP 585) - Optional[T] → T | None (PEP 604) - Union[A, B] → A | B (PEP 604) - 移除废弃的 typing 导入 - 移除不必要的字符串引号注解
This commit is contained in:
@@ -3,7 +3,7 @@ Anyrouter 余额查询操作(含自动签到)
|
||||
"""
|
||||
|
||||
import time
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
|
||||
@@ -101,7 +101,7 @@ class AnyrouterBalanceAction(BalanceAction):
|
||||
)
|
||||
|
||||
def _handle_http_error(
|
||||
self, response: httpx.Response, raw_data: Optional[Dict[str, Any]] = None
|
||||
self, response: httpx.Response, raw_data: dict[str, Any] | None = None
|
||||
) -> ActionResult:
|
||||
"""处理 HTTP 错误响应"""
|
||||
status_code = response.status_code
|
||||
@@ -117,7 +117,7 @@ class AnyrouterBalanceAction(BalanceAction):
|
||||
|
||||
return super()._handle_http_error(response, raw_data)
|
||||
|
||||
async def _do_checkin(self, client: httpx.AsyncClient) -> Optional[Dict[str, Any]]:
|
||||
async def _do_checkin(self, client: httpx.AsyncClient) -> dict[str, Any] | None:
|
||||
"""
|
||||
执行自动签到(始终执行)
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"""
|
||||
|
||||
from abc import abstractmethod
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
|
||||
@@ -80,7 +80,7 @@ class BalanceAction(ProviderAction):
|
||||
"""
|
||||
pass
|
||||
|
||||
async def _do_checkin(self, client: httpx.AsyncClient) -> Optional[Dict[str, Any]]:
|
||||
async def _do_checkin(self, client: httpx.AsyncClient) -> dict[str, Any] | None:
|
||||
"""
|
||||
执行签到(子类可选实现)
|
||||
|
||||
@@ -97,11 +97,11 @@ class BalanceAction(ProviderAction):
|
||||
|
||||
def _create_balance_info(
|
||||
self,
|
||||
total_granted: Optional[float] = None,
|
||||
total_used: Optional[float] = None,
|
||||
total_available: Optional[float] = None,
|
||||
total_granted: float | None = None,
|
||||
total_used: float | None = None,
|
||||
total_available: float | None = None,
|
||||
currency: str = "USD",
|
||||
extra: Optional[Dict[str, Any]] = None,
|
||||
extra: dict[str, Any] | None = None,
|
||||
) -> BalanceInfo:
|
||||
"""
|
||||
创建余额信息对象
|
||||
@@ -135,7 +135,7 @@ class BalanceAction(ProviderAction):
|
||||
extra=extra if extra is not None else {},
|
||||
)
|
||||
|
||||
def _to_float(self, value: Any) -> Optional[float]:
|
||||
def _to_float(self, value: Any) -> float | None:
|
||||
"""转换为浮点数"""
|
||||
if value is None:
|
||||
return None
|
||||
@@ -145,7 +145,7 @@ class BalanceAction(ProviderAction):
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def get_config_schema(cls) -> Dict[str, Any]:
|
||||
def get_config_schema(cls) -> dict[str, Any]:
|
||||
"""获取操作配置 schema(子类可重写)"""
|
||||
return {
|
||||
"type": "object",
|
||||
|
||||
@@ -3,8 +3,7 @@ Provider 操作抽象基类
|
||||
"""
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
|
||||
@@ -30,7 +29,7 @@ class ProviderAction(ABC):
|
||||
# 默认缓存时间(秒)
|
||||
default_cache_ttl: int = 300
|
||||
|
||||
def __init__(self, config: Optional[Dict[str, Any]] = None):
|
||||
def __init__(self, config: dict[str, Any] | None = None):
|
||||
"""
|
||||
初始化操作
|
||||
|
||||
@@ -52,7 +51,7 @@ class ProviderAction(ABC):
|
||||
"""
|
||||
pass
|
||||
|
||||
def _extract_field(self, data: Any, path: Optional[str]) -> Any:
|
||||
def _extract_field(self, data: Any, path: str | None) -> Any:
|
||||
"""
|
||||
从响应数据中提取字段
|
||||
|
||||
@@ -86,9 +85,9 @@ class ProviderAction(ABC):
|
||||
def _make_success_result(
|
||||
self,
|
||||
data: Any = None,
|
||||
message: Optional[str] = None,
|
||||
response_time_ms: Optional[int] = None,
|
||||
raw_response: Optional[Dict[str, Any]] = None,
|
||||
message: str | None = None,
|
||||
response_time_ms: int | None = None,
|
||||
raw_response: dict[str, Any] | None = None,
|
||||
) -> ActionResult:
|
||||
"""创建成功结果"""
|
||||
return ActionResult(
|
||||
@@ -104,9 +103,9 @@ class ProviderAction(ABC):
|
||||
def _make_error_result(
|
||||
self,
|
||||
status: ActionStatus,
|
||||
message: Optional[str] = None,
|
||||
retry_after_seconds: Optional[int] = None,
|
||||
raw_response: Optional[Dict[str, Any]] = None,
|
||||
message: str | None = None,
|
||||
retry_after_seconds: int | None = None,
|
||||
raw_response: dict[str, Any] | None = None,
|
||||
) -> ActionResult:
|
||||
"""创建错误结果"""
|
||||
return ActionResult(
|
||||
@@ -119,7 +118,7 @@ class ProviderAction(ABC):
|
||||
)
|
||||
|
||||
def _handle_http_error(
|
||||
self, response: httpx.Response, raw_data: Optional[Dict[str, Any]] = None
|
||||
self, response: httpx.Response, raw_data: dict[str, Any] | None = None
|
||||
) -> ActionResult:
|
||||
"""处理 HTTP 错误响应"""
|
||||
status_code = response.status_code
|
||||
@@ -153,7 +152,7 @@ class ProviderAction(ABC):
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_config_schema(cls) -> Dict[str, Any]:
|
||||
def get_config_schema(cls) -> dict[str, Any]:
|
||||
"""
|
||||
获取操作配置 JSON Schema(用于前端表单生成)
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"""
|
||||
|
||||
from abc import abstractmethod
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
|
||||
@@ -44,10 +44,10 @@ class CheckinAction(ProviderAction):
|
||||
|
||||
def _create_checkin_info(
|
||||
self,
|
||||
reward: Optional[float] = None,
|
||||
streak_days: Optional[int] = None,
|
||||
message: Optional[str] = None,
|
||||
extra: Optional[Dict[str, Any]] = None,
|
||||
reward: float | None = None,
|
||||
streak_days: int | None = None,
|
||||
message: str | None = None,
|
||||
extra: dict[str, Any] | None = None,
|
||||
) -> CheckinInfo:
|
||||
"""
|
||||
创建签到信息对象
|
||||
@@ -71,7 +71,7 @@ class CheckinAction(ProviderAction):
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_config_schema(cls) -> Dict[str, Any]:
|
||||
def get_config_schema(cls) -> dict[str, Any]:
|
||||
"""获取操作配置 schema(子类可重写)"""
|
||||
return {
|
||||
"type": "object",
|
||||
|
||||
@@ -3,7 +3,7 @@ Cubence 余额查询操作
|
||||
"""
|
||||
|
||||
import time
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
|
||||
@@ -85,7 +85,7 @@ class CubenceBalanceAction(BalanceAction):
|
||||
)
|
||||
|
||||
def _handle_http_error(
|
||||
self, response: httpx.Response, raw_data: Optional[Dict[str, Any]] = None
|
||||
self, response: httpx.Response, raw_data: dict[str, Any] | None = None
|
||||
) -> ActionResult:
|
||||
"""处理 HTTP 错误响应(Cubence 专用)"""
|
||||
status_code = response.status_code
|
||||
@@ -117,7 +117,7 @@ class CubenceBalanceAction(BalanceAction):
|
||||
charity_balance = balance_data.get("charity_balance_dollar")
|
||||
|
||||
# 窗口限额信息
|
||||
extra: Dict[str, Any] = {}
|
||||
extra: dict[str, Any] = {}
|
||||
|
||||
# 5小时窗口限额
|
||||
five_hour = subscription_limits.get("five_hour", {})
|
||||
|
||||
@@ -4,7 +4,7 @@ NekoCode 余额查询操作
|
||||
|
||||
import time
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
|
||||
@@ -122,7 +122,7 @@ class NekoCodeBalanceAction(BalanceAction):
|
||||
logger.debug(f"解析 effective_start_date 失败: {e}")
|
||||
|
||||
# 构建 extra 信息
|
||||
extra: Dict[str, Any] = {
|
||||
extra: dict[str, Any] = {
|
||||
"plan_name": plan_name,
|
||||
"subscription_status": status,
|
||||
"daily_quota_limit": daily_quota_limit,
|
||||
@@ -161,7 +161,7 @@ class NekoCodeBalanceAction(BalanceAction):
|
||||
)
|
||||
|
||||
def _handle_http_error(
|
||||
self, response: httpx.Response, raw_data: Optional[Dict[str, Any]] = None
|
||||
self, response: httpx.Response, raw_data: dict[str, Any] | None = None
|
||||
) -> ActionResult:
|
||||
"""处理 HTTP 错误响应"""
|
||||
status_code = response.status_code
|
||||
@@ -178,7 +178,7 @@ class NekoCodeBalanceAction(BalanceAction):
|
||||
return super()._handle_http_error(response, raw_data)
|
||||
|
||||
@classmethod
|
||||
def get_config_schema(cls) -> Dict[str, Any]:
|
||||
def get_config_schema(cls) -> dict[str, Any]:
|
||||
"""获取操作配置 schema"""
|
||||
return {
|
||||
"type": "object",
|
||||
|
||||
@@ -3,7 +3,7 @@ New API 余额查询操作
|
||||
"""
|
||||
|
||||
import time
|
||||
from typing import Any, Dict, Optional
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
|
||||
@@ -111,7 +111,7 @@ class NewApiBalanceAction(BalanceAction):
|
||||
currency=self.config.get("currency", "USD"),
|
||||
)
|
||||
|
||||
async def _do_checkin(self, client: httpx.AsyncClient) -> Optional[Dict[str, Any]]:
|
||||
async def _do_checkin(self, client: httpx.AsyncClient) -> dict[str, Any] | None:
|
||||
"""
|
||||
执行签到(静默,不抛出异常)
|
||||
|
||||
@@ -184,7 +184,7 @@ class NewApiBalanceAction(BalanceAction):
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def get_config_schema(cls) -> Dict[str, Any]:
|
||||
def get_config_schema(cls) -> dict[str, Any]:
|
||||
"""获取操作配置 schema"""
|
||||
return {
|
||||
"type": "object",
|
||||
|
||||
@@ -4,7 +4,7 @@ YesCode 余额查询操作
|
||||
|
||||
import asyncio
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Any, Dict
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
|
||||
@@ -15,7 +15,7 @@ from src.services.provider_ops.types import ActionResult, ActionStatus, BalanceI
|
||||
async def fetch_yescode_combined_data(
|
||||
client: httpx.AsyncClient,
|
||||
base_url: str,
|
||||
) -> Dict[str, Any]:
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
获取 YesCode 合并数据(balance + profile)
|
||||
|
||||
@@ -31,7 +31,7 @@ async def fetch_yescode_combined_data(
|
||||
合并后的数据字典
|
||||
"""
|
||||
base_url = base_url.rstrip("/")
|
||||
result: Dict[str, Any] = {}
|
||||
result: dict[str, Any] = {}
|
||||
|
||||
# 并发调用两个接口
|
||||
balance_task = client.get(f"{base_url}/api/v1/user/balance")
|
||||
@@ -42,7 +42,7 @@ async def fetch_yescode_combined_data(
|
||||
)
|
||||
|
||||
# 解析 balance 接口
|
||||
balance_data: Dict[str, Any] = {}
|
||||
balance_data: dict[str, Any] = {}
|
||||
if isinstance(balance_resp, httpx.Response) and balance_resp.status_code == 200:
|
||||
try:
|
||||
balance_data = balance_resp.json()
|
||||
@@ -51,7 +51,7 @@ async def fetch_yescode_combined_data(
|
||||
pass
|
||||
|
||||
# 解析 profile 接口
|
||||
profile_data: Dict[str, Any] = {}
|
||||
profile_data: dict[str, Any] = {}
|
||||
if isinstance(profile_resp, httpx.Response) and profile_resp.status_code == 200:
|
||||
try:
|
||||
profile_data = profile_resp.json()
|
||||
@@ -87,7 +87,7 @@ async def fetch_yescode_combined_data(
|
||||
return result
|
||||
|
||||
|
||||
def parse_yescode_balance_extra(data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
def parse_yescode_balance_extra(data: dict[str, Any]) -> dict[str, Any]:
|
||||
"""
|
||||
解析 YesCode 余额额外信息
|
||||
|
||||
@@ -97,7 +97,7 @@ def parse_yescode_balance_extra(data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
Returns:
|
||||
统一格式的 extra 字典
|
||||
"""
|
||||
extra: Dict[str, Any] = {}
|
||||
extra: dict[str, Any] = {}
|
||||
|
||||
pay_as_you_go = data.get("pay_as_you_go_balance", 0)
|
||||
subscription = data.get("subscription_balance", 0)
|
||||
|
||||
@@ -6,7 +6,7 @@ Anyrouter 架构
|
||||
|
||||
import base64
|
||||
import re
|
||||
from typing import Any, Dict, List, Optional, Tuple, Type
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
|
||||
@@ -118,7 +118,7 @@ def _extract_session_from_cookie(cookie_string: str) -> str:
|
||||
return cookie_string.strip()
|
||||
|
||||
|
||||
def _parse_session_user_id(cookie_input: str) -> Tuple[Optional[str], Optional[str]]:
|
||||
def _parse_session_user_id(cookie_input: str) -> tuple[str | None, str | None]:
|
||||
"""
|
||||
从 session cookie 中解析用户 ID 和用户名
|
||||
|
||||
@@ -213,8 +213,8 @@ def _parse_session_user_id(cookie_input: str) -> Tuple[Optional[str], Optional[s
|
||||
|
||||
|
||||
async def _get_acw_cookie(
|
||||
base_url: str, timeout: float = 10, proxy: Optional[str] = None
|
||||
) -> Optional[str]:
|
||||
base_url: str, timeout: float = 10, proxy: str | None = None
|
||||
) -> str | None:
|
||||
"""
|
||||
获取 acw_sc__v2 Cookie
|
||||
|
||||
@@ -230,7 +230,7 @@ async def _get_acw_cookie(
|
||||
"""
|
||||
try:
|
||||
# 构建 client 参数
|
||||
client_kwargs: Dict[str, Any] = {
|
||||
client_kwargs: dict[str, Any] = {
|
||||
"timeout": timeout,
|
||||
"verify": get_ssl_context(),
|
||||
}
|
||||
@@ -278,13 +278,13 @@ class AnyrouterConnector(ProviderConnector):
|
||||
auth_type = ConnectorAuthType.COOKIE
|
||||
display_name = "Anyrouter Cookie"
|
||||
|
||||
def __init__(self, base_url: str, config: Optional[Dict[str, Any]] = None):
|
||||
def __init__(self, base_url: str, config: dict[str, Any] | None = None):
|
||||
super().__init__(base_url, config)
|
||||
self._session_cookie: Optional[str] = None
|
||||
self._acw_cookie: Optional[str] = None
|
||||
self._user_id: Optional[str] = None
|
||||
self._session_cookie: str | None = None
|
||||
self._acw_cookie: str | None = None
|
||||
self._user_id: str | None = None
|
||||
|
||||
async def connect(self, credentials: Dict[str, Any]) -> bool:
|
||||
async def connect(self, credentials: dict[str, Any]) -> bool:
|
||||
"""建立连接"""
|
||||
session_cookie = credentials.get("session_cookie")
|
||||
if not session_cookie:
|
||||
@@ -336,7 +336,7 @@ class AnyrouterConnector(ProviderConnector):
|
||||
return request
|
||||
|
||||
@classmethod
|
||||
def get_credentials_schema(cls) -> Dict[str, Any]:
|
||||
def get_credentials_schema(cls) -> dict[str, Any]:
|
||||
"""获取凭据配置 schema"""
|
||||
return {
|
||||
"type": "object",
|
||||
@@ -368,13 +368,13 @@ class AnyrouterArchitecture(ProviderArchitecture):
|
||||
display_name = "Anyrouter"
|
||||
description = "Anyrouter 中转站预设配置,使用 Cookie 认证"
|
||||
|
||||
supported_connectors: List[Type[ProviderConnector]] = [
|
||||
supported_connectors: list[type[ProviderConnector]] = [
|
||||
AnyrouterConnector,
|
||||
]
|
||||
|
||||
supported_actions: List[Type[ProviderAction]] = [AnyrouterBalanceAction]
|
||||
supported_actions: list[type[ProviderAction]] = [AnyrouterBalanceAction]
|
||||
|
||||
default_action_configs: Dict[ProviderActionType, Dict[str, Any]] = {
|
||||
default_action_configs: dict[ProviderActionType, dict[str, Any]] = {
|
||||
ProviderActionType.QUERY_BALANCE: {
|
||||
"endpoint": "/api/user/self",
|
||||
"method": "GET",
|
||||
@@ -383,7 +383,7 @@ class AnyrouterArchitecture(ProviderArchitecture):
|
||||
},
|
||||
}
|
||||
|
||||
def get_credentials_schema(self) -> Dict[str, Any]:
|
||||
def get_credentials_schema(self) -> dict[str, Any]:
|
||||
"""Anyrouter 使用 session_cookie 认证"""
|
||||
return AnyrouterConnector.get_credentials_schema()
|
||||
|
||||
@@ -394,9 +394,9 @@ class AnyrouterArchitecture(ProviderArchitecture):
|
||||
async def prepare_verify_config(
|
||||
self,
|
||||
base_url: str,
|
||||
config: Dict[str, Any],
|
||||
credentials: Dict[str, Any],
|
||||
) -> Dict[str, Any]:
|
||||
config: dict[str, Any],
|
||||
credentials: dict[str, Any],
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
验证前获取 acw_sc__v2 Cookie
|
||||
|
||||
@@ -417,16 +417,16 @@ class AnyrouterArchitecture(ProviderArchitecture):
|
||||
|
||||
def build_verify_headers(
|
||||
self,
|
||||
config: Dict[str, Any],
|
||||
credentials: Dict[str, Any],
|
||||
) -> Dict[str, str]:
|
||||
config: dict[str, Any],
|
||||
credentials: dict[str, Any],
|
||||
) -> dict[str, str]:
|
||||
"""
|
||||
构建 Anyrouter 的验证请求 Headers
|
||||
|
||||
使用 Cookie 认证,不使用 Authorization。
|
||||
同时添加 New-Api-User header。
|
||||
"""
|
||||
headers: Dict[str, str] = {}
|
||||
headers: dict[str, str] = {}
|
||||
|
||||
cookies = []
|
||||
|
||||
@@ -455,7 +455,7 @@ class AnyrouterArchitecture(ProviderArchitecture):
|
||||
def parse_verify_response(
|
||||
self,
|
||||
status_code: int,
|
||||
data: Dict[str, Any],
|
||||
data: dict[str, Any],
|
||||
) -> VerifyResult:
|
||||
"""解析 Anyrouter 验证响应"""
|
||||
if status_code == 401:
|
||||
|
||||
@@ -6,7 +6,8 @@ from abc import ABC, abstractmethod
|
||||
from contextlib import asynccontextmanager
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any, AsyncIterator, Dict, List, Optional, Type
|
||||
from typing import Any
|
||||
from collections.abc import AsyncIterator
|
||||
|
||||
import httpx
|
||||
|
||||
@@ -35,7 +36,7 @@ class ProviderConnector(ABC):
|
||||
auth_type: ConnectorAuthType = ConnectorAuthType.NONE
|
||||
display_name: str = "Base Connector"
|
||||
|
||||
def __init__(self, base_url: str, config: Optional[Dict[str, Any]] = None):
|
||||
def __init__(self, base_url: str, config: dict[str, Any] | None = None):
|
||||
"""
|
||||
初始化连接器
|
||||
|
||||
@@ -46,19 +47,19 @@ class ProviderConnector(ABC):
|
||||
self.base_url = base_url.rstrip("/")
|
||||
self.config = config or {}
|
||||
self._status = ConnectorStatus.DISCONNECTED
|
||||
self._connected_at: Optional[datetime] = None
|
||||
self._expires_at: Optional[datetime] = None
|
||||
self._last_error: Optional[str] = None
|
||||
self._connected_at: datetime | None = None
|
||||
self._expires_at: datetime | None = None
|
||||
self._last_error: str | None = None
|
||||
|
||||
# 代理配置
|
||||
self._proxy: Optional[str] = self.config.get("proxy")
|
||||
self._proxy: str | None = self.config.get("proxy")
|
||||
|
||||
# HTTP 客户端配置
|
||||
self._timeout = self.config.get("timeout", 30)
|
||||
self._headers: Dict[str, str] = {}
|
||||
self._headers: dict[str, str] = {}
|
||||
|
||||
@abstractmethod
|
||||
async def connect(self, credentials: Dict[str, Any]) -> bool:
|
||||
async def connect(self, credentials: dict[str, Any]) -> bool:
|
||||
"""
|
||||
建立认证连接
|
||||
|
||||
@@ -93,7 +94,7 @@ class ProviderConnector(ABC):
|
||||
"""
|
||||
pass
|
||||
|
||||
async def refresh_auth(self, credentials: Dict[str, Any]) -> bool:
|
||||
async def refresh_auth(self, credentials: dict[str, Any]) -> bool:
|
||||
"""
|
||||
刷新认证(如 Token 过期)
|
||||
|
||||
@@ -144,7 +145,7 @@ class ProviderConnector(ABC):
|
||||
last_error=self._last_error,
|
||||
)
|
||||
|
||||
def _set_connected(self, expires_at: Optional[datetime] = None) -> None:
|
||||
def _set_connected(self, expires_at: datetime | None = None) -> None:
|
||||
"""设置为已连接状态"""
|
||||
self._status = ConnectorStatus.CONNECTED
|
||||
self._connected_at = datetime.now(timezone.utc)
|
||||
@@ -163,7 +164,7 @@ class ProviderConnector(ABC):
|
||||
self._expires_at = None
|
||||
|
||||
@classmethod
|
||||
def get_credentials_schema(cls) -> Dict[str, Any]:
|
||||
def get_credentials_schema(cls) -> dict[str, Any]:
|
||||
"""
|
||||
获取凭据配置 JSON Schema(用于前端表单生成)
|
||||
|
||||
@@ -180,16 +181,16 @@ class VerifyResult:
|
||||
"""认证验证结果"""
|
||||
|
||||
success: bool
|
||||
message: Optional[str] = None
|
||||
username: Optional[str] = None
|
||||
display_name: Optional[str] = None
|
||||
email: Optional[str] = None
|
||||
quota: Optional[float] = None
|
||||
used_quota: Optional[float] = None
|
||||
request_count: Optional[int] = None
|
||||
extra: Optional[Dict[str, Any]] = None
|
||||
message: str | None = None
|
||||
username: str | None = None
|
||||
display_name: str | None = None
|
||||
email: str | None = None
|
||||
quota: float | None = None
|
||||
used_quota: float | None = None
|
||||
request_count: int | None = None
|
||||
extra: dict[str, Any] | None = None
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
"""转换为字典"""
|
||||
if not self.success:
|
||||
return {"success": False, "message": self.message}
|
||||
@@ -240,15 +241,15 @@ class ProviderArchitecture(ABC):
|
||||
description: str = ""
|
||||
|
||||
# 支持的 Connector 类型列表(按优先级排序)
|
||||
supported_connectors: List[Type[ProviderConnector]] = []
|
||||
supported_connectors: list[type[ProviderConnector]] = []
|
||||
|
||||
# 支持的 Action 类型列表
|
||||
supported_actions: List[Type[ProviderAction]] = []
|
||||
supported_actions: list[type[ProviderAction]] = []
|
||||
|
||||
# 默认操作配置
|
||||
default_action_configs: Dict[ProviderActionType, Dict[str, Any]] = {}
|
||||
default_action_configs: dict[ProviderActionType, dict[str, Any]] = {}
|
||||
|
||||
def __init__(self, config: Optional[Dict[str, Any]] = None):
|
||||
def __init__(self, config: dict[str, Any] | None = None):
|
||||
"""
|
||||
初始化架构
|
||||
|
||||
@@ -260,7 +261,7 @@ class ProviderArchitecture(ABC):
|
||||
# ==================== 认证验证相关方法(子类必须实现) ====================
|
||||
|
||||
@abstractmethod
|
||||
def get_credentials_schema(self) -> Dict[str, Any]:
|
||||
def get_credentials_schema(self) -> dict[str, Any]:
|
||||
"""
|
||||
获取凭据字段定义(JSON Schema 格式)
|
||||
|
||||
@@ -303,9 +304,9 @@ class ProviderArchitecture(ABC):
|
||||
@abstractmethod
|
||||
def build_verify_headers(
|
||||
self,
|
||||
config: Dict[str, Any],
|
||||
credentials: Dict[str, Any],
|
||||
) -> Dict[str, str]:
|
||||
config: dict[str, Any],
|
||||
credentials: dict[str, Any],
|
||||
) -> dict[str, str]:
|
||||
"""
|
||||
构建认证验证请求的 Headers
|
||||
|
||||
@@ -324,7 +325,7 @@ class ProviderArchitecture(ABC):
|
||||
def parse_verify_response(
|
||||
self,
|
||||
status_code: int,
|
||||
data: Dict[str, Any],
|
||||
data: dict[str, Any],
|
||||
) -> VerifyResult:
|
||||
"""
|
||||
解析认证验证响应
|
||||
@@ -345,9 +346,9 @@ class ProviderArchitecture(ABC):
|
||||
async def prepare_verify_config(
|
||||
self,
|
||||
base_url: str,
|
||||
config: Dict[str, Any],
|
||||
credentials: Dict[str, Any],
|
||||
) -> Dict[str, Any]:
|
||||
config: dict[str, Any],
|
||||
credentials: dict[str, Any],
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
验证前的异步预处理(可选)
|
||||
|
||||
@@ -369,8 +370,8 @@ class ProviderArchitecture(ABC):
|
||||
def get_connector(
|
||||
self,
|
||||
base_url: str,
|
||||
auth_type: Optional[ConnectorAuthType] = None,
|
||||
config: Optional[Dict[str, Any]] = None,
|
||||
auth_type: ConnectorAuthType | None = None,
|
||||
config: dict[str, Any] | None = None,
|
||||
) -> ProviderConnector:
|
||||
"""
|
||||
获取连接器实例
|
||||
@@ -390,7 +391,7 @@ class ProviderArchitecture(ABC):
|
||||
raise ValueError(f"架构 {self.architecture_id} 未配置支持的连接器")
|
||||
|
||||
# 查找匹配的连接器
|
||||
connector_cls: Optional[Type[ProviderConnector]] = None
|
||||
connector_cls: type[ProviderConnector] | None = None
|
||||
|
||||
if auth_type:
|
||||
for cls in self.supported_connectors:
|
||||
@@ -413,7 +414,7 @@ class ProviderArchitecture(ABC):
|
||||
def get_action(
|
||||
self,
|
||||
action_type: ProviderActionType,
|
||||
config: Optional[Dict[str, Any]] = None,
|
||||
config: dict[str, Any] | None = None,
|
||||
) -> ProviderAction:
|
||||
"""
|
||||
获取操作实例
|
||||
@@ -428,7 +429,7 @@ class ProviderArchitecture(ABC):
|
||||
Raises:
|
||||
ValueError: 不支持的操作类型
|
||||
"""
|
||||
action_cls: Optional[Type[ProviderAction]] = None
|
||||
action_cls: type[ProviderAction] | None = None
|
||||
|
||||
for cls in self.supported_actions:
|
||||
if cls.action_type == action_type:
|
||||
@@ -457,15 +458,15 @@ class ProviderArchitecture(ABC):
|
||||
"""检查是否支持指定认证类型"""
|
||||
return any(c.auth_type == auth_type for c in self.supported_connectors)
|
||||
|
||||
def get_supported_auth_types(self) -> List[ConnectorAuthType]:
|
||||
def get_supported_auth_types(self) -> list[ConnectorAuthType]:
|
||||
"""获取支持的认证类型列表"""
|
||||
return [c.auth_type for c in self.supported_connectors]
|
||||
|
||||
def get_supported_action_types(self) -> List[ProviderActionType]:
|
||||
def get_supported_action_types(self) -> list[ProviderActionType]:
|
||||
"""获取支持的操作类型列表"""
|
||||
return [a.action_type for a in self.supported_actions]
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
"""转换为字典(用于 API 响应)"""
|
||||
return {
|
||||
"architecture_id": self.architecture_id,
|
||||
|
||||
@@ -4,7 +4,7 @@ Cubence 架构
|
||||
针对 Cubence 中转站的预设配置。
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, List, Optional, Type
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
|
||||
@@ -54,11 +54,11 @@ class CubenceConnector(ProviderConnector):
|
||||
auth_type = ConnectorAuthType.COOKIE
|
||||
display_name = "Cubence Cookie"
|
||||
|
||||
def __init__(self, base_url: str, config: Optional[Dict[str, Any]] = None):
|
||||
def __init__(self, base_url: str, config: dict[str, Any] | None = None):
|
||||
super().__init__(base_url, config)
|
||||
self._token_cookie: Optional[str] = None
|
||||
self._token_cookie: str | None = None
|
||||
|
||||
async def connect(self, credentials: Dict[str, Any]) -> bool:
|
||||
async def connect(self, credentials: dict[str, Any]) -> bool:
|
||||
"""建立连接"""
|
||||
token_cookie = credentials.get("token_cookie")
|
||||
if not token_cookie:
|
||||
@@ -88,7 +88,7 @@ class CubenceConnector(ProviderConnector):
|
||||
return request
|
||||
|
||||
@classmethod
|
||||
def get_credentials_schema(cls) -> Dict[str, Any]:
|
||||
def get_credentials_schema(cls) -> dict[str, Any]:
|
||||
"""获取凭据配置 schema"""
|
||||
return {
|
||||
"type": "object",
|
||||
@@ -120,15 +120,15 @@ class CubenceArchitecture(ProviderArchitecture):
|
||||
display_name = "Cubence"
|
||||
description = "Cubence 中转站预设配置,使用 Cookie 认证"
|
||||
|
||||
supported_connectors: List[Type[ProviderConnector]] = [
|
||||
supported_connectors: list[type[ProviderConnector]] = [
|
||||
CubenceConnector,
|
||||
]
|
||||
|
||||
supported_actions: List[Type[ProviderAction]] = [
|
||||
supported_actions: list[type[ProviderAction]] = [
|
||||
CubenceBalanceAction,
|
||||
]
|
||||
|
||||
default_action_configs: Dict[ProviderActionType, Dict[str, Any]] = {
|
||||
default_action_configs: dict[ProviderActionType, dict[str, Any]] = {
|
||||
ProviderActionType.QUERY_BALANCE: {
|
||||
"endpoint": "/api/v1/dashboard/overview",
|
||||
"method": "GET",
|
||||
@@ -138,7 +138,7 @@ class CubenceArchitecture(ProviderArchitecture):
|
||||
},
|
||||
}
|
||||
|
||||
def get_credentials_schema(self) -> Dict[str, Any]:
|
||||
def get_credentials_schema(self) -> dict[str, Any]:
|
||||
"""Cubence 使用 token_cookie 认证"""
|
||||
return CubenceConnector.get_credentials_schema()
|
||||
|
||||
@@ -148,15 +148,15 @@ class CubenceArchitecture(ProviderArchitecture):
|
||||
|
||||
def build_verify_headers(
|
||||
self,
|
||||
config: Dict[str, Any],
|
||||
credentials: Dict[str, Any],
|
||||
) -> Dict[str, str]:
|
||||
config: dict[str, Any],
|
||||
credentials: dict[str, Any],
|
||||
) -> dict[str, str]:
|
||||
"""
|
||||
构建 Cubence 的验证请求 Headers
|
||||
|
||||
使用 Cookie 认证,不使用 Authorization。
|
||||
"""
|
||||
headers: Dict[str, str] = {}
|
||||
headers: dict[str, str] = {}
|
||||
|
||||
# 添加 token Cookie
|
||||
cookie_input = credentials.get("token_cookie")
|
||||
@@ -169,7 +169,7 @@ class CubenceArchitecture(ProviderArchitecture):
|
||||
def parse_verify_response(
|
||||
self,
|
||||
status_code: int,
|
||||
data: Dict[str, Any],
|
||||
data: dict[str, Any],
|
||||
) -> VerifyResult:
|
||||
"""解析 Cubence 验证响应"""
|
||||
if status_code == 401:
|
||||
@@ -190,7 +190,7 @@ class CubenceArchitecture(ProviderArchitecture):
|
||||
subscription_limits = user_data.get("subscription_limits", {})
|
||||
|
||||
# 构建 extra 信息,包含窗口限额
|
||||
extra: Dict[str, Any] = {
|
||||
extra: dict[str, Any] = {
|
||||
"role": user_info.get("role"),
|
||||
"invite_code": user_info.get("invite_code"),
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
3. 在前端 auth-templates/ 添加对应的模板定义
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, List, Optional, Type
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
|
||||
@@ -67,14 +67,14 @@ class GenericApiKeyConnector(ProviderConnector):
|
||||
auth_type = ConnectorAuthType.API_KEY
|
||||
display_name = "API Key"
|
||||
|
||||
def __init__(self, base_url: str, config: Optional[Dict[str, Any]] = None):
|
||||
def __init__(self, base_url: str, config: dict[str, Any] | None = None):
|
||||
super().__init__(base_url, config)
|
||||
self._api_key: Optional[str] = None
|
||||
self._api_key: str | None = None
|
||||
# 支持配置认证方式
|
||||
self._auth_method = self.config.get("auth_method", "bearer")
|
||||
self._header_name = self.config.get("header_name", "Authorization")
|
||||
|
||||
async def connect(self, credentials: Dict[str, Any]) -> bool:
|
||||
async def connect(self, credentials: dict[str, Any]) -> bool:
|
||||
"""建立连接"""
|
||||
api_key = credentials.get("api_key")
|
||||
if not api_key:
|
||||
@@ -107,7 +107,7 @@ class GenericApiKeyConnector(ProviderConnector):
|
||||
return request
|
||||
|
||||
@classmethod
|
||||
def get_credentials_schema(cls) -> Dict[str, Any]:
|
||||
def get_credentials_schema(cls) -> dict[str, Any]:
|
||||
"""获取凭据配置 schema"""
|
||||
return {
|
||||
"type": "object",
|
||||
@@ -136,14 +136,14 @@ class GenericApiArchitecture(ProviderArchitecture):
|
||||
display_name = "通用 API"
|
||||
description = "可配置的通用 API 架构,适用于各种中转站"
|
||||
|
||||
supported_connectors: List[Type[ProviderConnector]] = [
|
||||
supported_connectors: list[type[ProviderConnector]] = [
|
||||
GenericApiKeyConnector,
|
||||
]
|
||||
|
||||
supported_actions: List[Type[ProviderAction]] = [NewApiBalanceAction]
|
||||
supported_actions: list[type[ProviderAction]] = [NewApiBalanceAction]
|
||||
|
||||
# 默认操作配置(可被用户配置覆盖)
|
||||
default_action_configs: Dict[ProviderActionType, Dict[str, Any]] = {
|
||||
default_action_configs: dict[ProviderActionType, dict[str, Any]] = {
|
||||
ProviderActionType.QUERY_BALANCE: {
|
||||
"endpoint": "/api/user/balance",
|
||||
"method": "GET",
|
||||
@@ -154,7 +154,7 @@ class GenericApiArchitecture(ProviderArchitecture):
|
||||
},
|
||||
}
|
||||
|
||||
def get_credentials_schema(self) -> Dict[str, Any]:
|
||||
def get_credentials_schema(self) -> dict[str, Any]:
|
||||
"""通用架构只需要 api_key"""
|
||||
return GenericApiKeyConnector.get_credentials_schema()
|
||||
|
||||
@@ -164,11 +164,11 @@ class GenericApiArchitecture(ProviderArchitecture):
|
||||
|
||||
def build_verify_headers(
|
||||
self,
|
||||
config: Dict[str, Any],
|
||||
credentials: Dict[str, Any],
|
||||
) -> Dict[str, str]:
|
||||
config: dict[str, Any],
|
||||
credentials: dict[str, Any],
|
||||
) -> dict[str, str]:
|
||||
"""构建通用 API 的验证请求 Headers"""
|
||||
headers: Dict[str, str] = {}
|
||||
headers: dict[str, str] = {}
|
||||
|
||||
api_key = credentials.get("api_key", "")
|
||||
if api_key:
|
||||
@@ -184,7 +184,7 @@ class GenericApiArchitecture(ProviderArchitecture):
|
||||
def parse_verify_response(
|
||||
self,
|
||||
status_code: int,
|
||||
data: Dict[str, Any],
|
||||
data: dict[str, Any],
|
||||
) -> VerifyResult:
|
||||
"""解析通用 API 验证响应"""
|
||||
if status_code == 401:
|
||||
|
||||
@@ -4,7 +4,7 @@ NekoCode 架构
|
||||
针对 NekoCode 中转站的预设配置,使用 Cookie 认证。
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, List, Optional, Type
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
|
||||
@@ -56,11 +56,11 @@ class NekoCodeConnector(ProviderConnector):
|
||||
auth_type = ConnectorAuthType.COOKIE
|
||||
display_name = "NekoCode Cookie"
|
||||
|
||||
def __init__(self, base_url: str, config: Optional[Dict[str, Any]] = None):
|
||||
def __init__(self, base_url: str, config: dict[str, Any] | None = None):
|
||||
super().__init__(base_url, config)
|
||||
self._session_cookie: Optional[str] = None
|
||||
self._session_cookie: str | None = None
|
||||
|
||||
async def connect(self, credentials: Dict[str, Any]) -> bool:
|
||||
async def connect(self, credentials: dict[str, Any]) -> bool:
|
||||
"""建立连接"""
|
||||
session_cookie = credentials.get("session_cookie")
|
||||
if not session_cookie:
|
||||
@@ -90,7 +90,7 @@ class NekoCodeConnector(ProviderConnector):
|
||||
return request
|
||||
|
||||
@classmethod
|
||||
def get_credentials_schema(cls) -> Dict[str, Any]:
|
||||
def get_credentials_schema(cls) -> dict[str, Any]:
|
||||
"""获取凭据配置 schema"""
|
||||
return {
|
||||
"type": "object",
|
||||
@@ -121,20 +121,20 @@ class NekoCodeArchitecture(ProviderArchitecture):
|
||||
display_name = "NekoCode"
|
||||
description = "NekoCode 中转站预设配置,使用 Cookie 认证"
|
||||
|
||||
supported_connectors: List[Type[ProviderConnector]] = [
|
||||
supported_connectors: list[type[ProviderConnector]] = [
|
||||
NekoCodeConnector,
|
||||
]
|
||||
|
||||
supported_actions: List[Type[ProviderAction]] = [NekoCodeBalanceAction]
|
||||
supported_actions: list[type[ProviderAction]] = [NekoCodeBalanceAction]
|
||||
|
||||
default_action_configs: Dict[ProviderActionType, Dict[str, Any]] = {
|
||||
default_action_configs: dict[ProviderActionType, dict[str, Any]] = {
|
||||
ProviderActionType.QUERY_BALANCE: {
|
||||
"endpoint": "/api/usage/summary",
|
||||
"method": "GET",
|
||||
},
|
||||
}
|
||||
|
||||
def get_credentials_schema(self) -> Dict[str, Any]:
|
||||
def get_credentials_schema(self) -> dict[str, Any]:
|
||||
"""NekoCode 使用 session_cookie 认证"""
|
||||
return NekoCodeConnector.get_credentials_schema()
|
||||
|
||||
@@ -145,9 +145,9 @@ class NekoCodeArchitecture(ProviderArchitecture):
|
||||
async def prepare_verify_config(
|
||||
self,
|
||||
base_url: str,
|
||||
config: Dict[str, Any],
|
||||
credentials: Dict[str, Any],
|
||||
) -> Dict[str, Any]:
|
||||
config: dict[str, Any],
|
||||
credentials: dict[str, Any],
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
验证前获取 /api/usage/summary 数据(用于显示天卡信息)
|
||||
|
||||
@@ -161,7 +161,7 @@ class NekoCodeArchitecture(ProviderArchitecture):
|
||||
"""
|
||||
try:
|
||||
# 构建请求头
|
||||
headers: Dict[str, str] = {
|
||||
headers: dict[str, str] = {
|
||||
"User-Agent": (
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
|
||||
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
||||
@@ -176,7 +176,7 @@ class NekoCodeArchitecture(ProviderArchitecture):
|
||||
headers["Cookie"] = f"session={session_value}"
|
||||
|
||||
# 构建 client 参数
|
||||
client_kwargs: Dict[str, Any] = {
|
||||
client_kwargs: dict[str, Any] = {
|
||||
"timeout": 10,
|
||||
"verify": get_ssl_context(),
|
||||
}
|
||||
@@ -202,15 +202,15 @@ class NekoCodeArchitecture(ProviderArchitecture):
|
||||
|
||||
def build_verify_headers(
|
||||
self,
|
||||
config: Dict[str, Any],
|
||||
credentials: Dict[str, Any],
|
||||
) -> Dict[str, str]:
|
||||
config: dict[str, Any],
|
||||
credentials: dict[str, Any],
|
||||
) -> dict[str, str]:
|
||||
"""
|
||||
构建 NekoCode 的验证请求 Headers
|
||||
|
||||
使用 Cookie 认证,不使用 Authorization。
|
||||
"""
|
||||
headers: Dict[str, str] = {}
|
||||
headers: dict[str, str] = {}
|
||||
|
||||
# 添加 session Cookie
|
||||
cookie_input = credentials.get("session_cookie")
|
||||
@@ -224,7 +224,7 @@ class NekoCodeArchitecture(ProviderArchitecture):
|
||||
def parse_verify_response(
|
||||
self,
|
||||
status_code: int,
|
||||
data: Dict[str, Any],
|
||||
data: dict[str, Any],
|
||||
) -> VerifyResult:
|
||||
"""解析 NekoCode 验证响应(/api/user/self + _usage_summary)"""
|
||||
if status_code == 401:
|
||||
@@ -249,7 +249,7 @@ class NekoCodeArchitecture(ProviderArchitecture):
|
||||
quota = None
|
||||
|
||||
# 从 prepare_verify_config 获取的 _usage_summary 数据(天卡信息)
|
||||
extra: Dict[str, Any] = {}
|
||||
extra: dict[str, Any] = {}
|
||||
usage_summary = data.get("_usage_summary", {})
|
||||
subscription = usage_summary.get("subscription", {})
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ New API 架构
|
||||
针对 New API 风格的中转站优化的预设配置。
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, List, Optional, Type
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
|
||||
@@ -32,13 +32,13 @@ class NewApiConnector(ProviderConnector):
|
||||
auth_type = ConnectorAuthType.API_KEY
|
||||
display_name = "New API Key"
|
||||
|
||||
def __init__(self, base_url: str, config: Optional[Dict[str, Any]] = None):
|
||||
def __init__(self, base_url: str, config: dict[str, Any] | None = None):
|
||||
super().__init__(base_url, config)
|
||||
self._api_key: Optional[str] = None
|
||||
self._user_id: Optional[str] = None
|
||||
self._cookie: Optional[str] = None
|
||||
self._api_key: str | None = None
|
||||
self._user_id: str | None = None
|
||||
self._cookie: str | None = None
|
||||
|
||||
async def connect(self, credentials: Dict[str, Any]) -> bool:
|
||||
async def connect(self, credentials: dict[str, Any]) -> bool:
|
||||
"""建立连接"""
|
||||
api_key = credentials.get("api_key")
|
||||
cookie = credentials.get("cookie")
|
||||
@@ -85,7 +85,7 @@ class NewApiConnector(ProviderConnector):
|
||||
return request
|
||||
|
||||
@classmethod
|
||||
def get_credentials_schema(cls) -> Dict[str, Any]:
|
||||
def get_credentials_schema(cls) -> dict[str, Any]:
|
||||
"""获取凭据配置 schema"""
|
||||
return {
|
||||
"type": "object",
|
||||
@@ -127,15 +127,15 @@ class NewApiArchitecture(ProviderArchitecture):
|
||||
display_name = "New API"
|
||||
description = "New API 风格中转站的预设配置"
|
||||
|
||||
supported_connectors: List[Type[ProviderConnector]] = [
|
||||
supported_connectors: list[type[ProviderConnector]] = [
|
||||
NewApiConnector,
|
||||
]
|
||||
|
||||
supported_actions: List[Type[ProviderAction]] = [
|
||||
supported_actions: list[type[ProviderAction]] = [
|
||||
NewApiBalanceAction,
|
||||
]
|
||||
|
||||
default_action_configs: Dict[ProviderActionType, Dict[str, Any]] = {
|
||||
default_action_configs: dict[ProviderActionType, dict[str, Any]] = {
|
||||
ProviderActionType.QUERY_BALANCE: {
|
||||
"endpoint": "/api/user/self",
|
||||
"method": "GET",
|
||||
@@ -144,7 +144,7 @@ class NewApiArchitecture(ProviderArchitecture):
|
||||
},
|
||||
}
|
||||
|
||||
def get_credentials_schema(self) -> Dict[str, Any]:
|
||||
def get_credentials_schema(self) -> dict[str, Any]:
|
||||
"""New API 需要 api_key 和 user_id"""
|
||||
return NewApiConnector.get_credentials_schema()
|
||||
|
||||
@@ -154,15 +154,15 @@ class NewApiArchitecture(ProviderArchitecture):
|
||||
|
||||
def build_verify_headers(
|
||||
self,
|
||||
config: Dict[str, Any],
|
||||
credentials: Dict[str, Any],
|
||||
) -> Dict[str, str]:
|
||||
config: dict[str, Any],
|
||||
credentials: dict[str, Any],
|
||||
) -> dict[str, str]:
|
||||
"""
|
||||
构建 New API 的验证请求 Headers
|
||||
|
||||
New API 特有:需要 New-Api-User Header 传递用户 ID
|
||||
"""
|
||||
headers: Dict[str, str] = {}
|
||||
headers: dict[str, str] = {}
|
||||
|
||||
# Bearer Token 认证
|
||||
api_key = credentials.get("api_key", "")
|
||||
@@ -184,7 +184,7 @@ class NewApiArchitecture(ProviderArchitecture):
|
||||
def parse_verify_response(
|
||||
self,
|
||||
status_code: int,
|
||||
data: Dict[str, Any],
|
||||
data: dict[str, Any],
|
||||
) -> VerifyResult:
|
||||
"""解析 New API 验证响应"""
|
||||
if status_code == 401:
|
||||
|
||||
@@ -4,7 +4,7 @@ One API 架构
|
||||
针对 One API 风格的中转站优化的预设配置。
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, List, Optional, Type
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
|
||||
@@ -29,11 +29,11 @@ class OneApiConnector(ProviderConnector):
|
||||
auth_type = ConnectorAuthType.API_KEY
|
||||
display_name = "One API Key"
|
||||
|
||||
def __init__(self, base_url: str, config: Optional[Dict[str, Any]] = None):
|
||||
def __init__(self, base_url: str, config: dict[str, Any] | None = None):
|
||||
super().__init__(base_url, config)
|
||||
self._api_key: Optional[str] = None
|
||||
self._api_key: str | None = None
|
||||
|
||||
async def connect(self, credentials: Dict[str, Any]) -> bool:
|
||||
async def connect(self, credentials: dict[str, Any]) -> bool:
|
||||
"""建立连接"""
|
||||
api_key = credentials.get("api_key")
|
||||
if not api_key:
|
||||
@@ -60,7 +60,7 @@ class OneApiConnector(ProviderConnector):
|
||||
return request
|
||||
|
||||
@classmethod
|
||||
def get_credentials_schema(cls) -> Dict[str, Any]:
|
||||
def get_credentials_schema(cls) -> dict[str, Any]:
|
||||
"""获取凭据配置 schema"""
|
||||
return {
|
||||
"type": "object",
|
||||
@@ -91,15 +91,15 @@ class OneApiArchitecture(ProviderArchitecture):
|
||||
display_name = "One API"
|
||||
description = "One API 风格中转站的预设配置"
|
||||
|
||||
supported_connectors: List[Type[ProviderConnector]] = [
|
||||
supported_connectors: list[type[ProviderConnector]] = [
|
||||
OneApiConnector,
|
||||
]
|
||||
|
||||
supported_actions: List[Type[ProviderAction]] = [
|
||||
supported_actions: list[type[ProviderAction]] = [
|
||||
NewApiBalanceAction,
|
||||
]
|
||||
|
||||
default_action_configs: Dict[ProviderActionType, Dict[str, Any]] = {
|
||||
default_action_configs: dict[ProviderActionType, dict[str, Any]] = {
|
||||
ProviderActionType.QUERY_BALANCE: {
|
||||
"endpoint": "/api/user/self",
|
||||
"method": "GET",
|
||||
@@ -110,7 +110,7 @@ class OneApiArchitecture(ProviderArchitecture):
|
||||
},
|
||||
}
|
||||
|
||||
def get_credentials_schema(self) -> Dict[str, Any]:
|
||||
def get_credentials_schema(self) -> dict[str, Any]:
|
||||
"""One API 只需要 api_key"""
|
||||
return OneApiConnector.get_credentials_schema()
|
||||
|
||||
@@ -120,11 +120,11 @@ class OneApiArchitecture(ProviderArchitecture):
|
||||
|
||||
def build_verify_headers(
|
||||
self,
|
||||
config: Dict[str, Any],
|
||||
credentials: Dict[str, Any],
|
||||
) -> Dict[str, str]:
|
||||
config: dict[str, Any],
|
||||
credentials: dict[str, Any],
|
||||
) -> dict[str, str]:
|
||||
"""构建 One API 的验证请求 Headers"""
|
||||
headers: Dict[str, str] = {}
|
||||
headers: dict[str, str] = {}
|
||||
|
||||
api_key = credentials.get("api_key", "")
|
||||
if api_key:
|
||||
@@ -135,7 +135,7 @@ class OneApiArchitecture(ProviderArchitecture):
|
||||
def parse_verify_response(
|
||||
self,
|
||||
status_code: int,
|
||||
data: Dict[str, Any],
|
||||
data: dict[str, Any],
|
||||
) -> VerifyResult:
|
||||
"""解析 One API 验证响应"""
|
||||
if status_code == 401:
|
||||
|
||||
@@ -4,7 +4,7 @@ YesCode 架构
|
||||
针对 YesCode 中转站的预设配置。
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, List, Optional, Type
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
|
||||
@@ -23,7 +23,7 @@ from src.services.provider_ops.types import ConnectorAuthType, ProviderActionTyp
|
||||
from src.utils.ssl_utils import get_ssl_context
|
||||
|
||||
|
||||
def _extract_cookies(cookie_string: str) -> Dict[str, str]:
|
||||
def _extract_cookies(cookie_string: str) -> dict[str, str]:
|
||||
"""
|
||||
从完整的 Cookie 字符串中提取 yescode_auth 和 yescode_csrf
|
||||
|
||||
@@ -33,7 +33,7 @@ def _extract_cookies(cookie_string: str) -> Dict[str, str]:
|
||||
Returns:
|
||||
包含 yescode_auth 和 yescode_csrf 的字典
|
||||
"""
|
||||
result: Dict[str, str] = {}
|
||||
result: dict[str, str] = {}
|
||||
for part in cookie_string.split(";"):
|
||||
part = part.strip()
|
||||
if "=" in part:
|
||||
@@ -82,11 +82,11 @@ class YesCodeConnector(ProviderConnector):
|
||||
auth_type = ConnectorAuthType.COOKIE
|
||||
display_name = "YesCode Cookie"
|
||||
|
||||
def __init__(self, base_url: str, config: Optional[Dict[str, Any]] = None):
|
||||
def __init__(self, base_url: str, config: dict[str, Any] | None = None):
|
||||
super().__init__(base_url, config)
|
||||
self._auth_cookie: Optional[str] = None
|
||||
self._auth_cookie: str | None = None
|
||||
|
||||
async def connect(self, credentials: Dict[str, Any]) -> bool:
|
||||
async def connect(self, credentials: dict[str, Any]) -> bool:
|
||||
"""建立连接"""
|
||||
auth_cookie = credentials.get("auth_cookie")
|
||||
if not auth_cookie:
|
||||
@@ -116,7 +116,7 @@ class YesCodeConnector(ProviderConnector):
|
||||
return request
|
||||
|
||||
@classmethod
|
||||
def get_credentials_schema(cls) -> Dict[str, Any]:
|
||||
def get_credentials_schema(cls) -> dict[str, Any]:
|
||||
"""获取凭据配置 schema"""
|
||||
return {
|
||||
"type": "object",
|
||||
@@ -148,15 +148,15 @@ class YesCodeArchitecture(ProviderArchitecture):
|
||||
display_name = "YesCode"
|
||||
description = "YesCode 中转站预设配置,使用 Cookie 认证"
|
||||
|
||||
supported_connectors: List[Type[ProviderConnector]] = [
|
||||
supported_connectors: list[type[ProviderConnector]] = [
|
||||
YesCodeConnector,
|
||||
]
|
||||
|
||||
supported_actions: List[Type[ProviderAction]] = [
|
||||
supported_actions: list[type[ProviderAction]] = [
|
||||
YesCodeBalanceAction,
|
||||
]
|
||||
|
||||
default_action_configs: Dict[ProviderActionType, Dict[str, Any]] = {
|
||||
default_action_configs: dict[ProviderActionType, dict[str, Any]] = {
|
||||
ProviderActionType.QUERY_BALANCE: {
|
||||
"endpoint": "/api/v1/user/balance",
|
||||
"method": "GET",
|
||||
@@ -166,7 +166,7 @@ class YesCodeArchitecture(ProviderArchitecture):
|
||||
},
|
||||
}
|
||||
|
||||
def get_credentials_schema(self) -> Dict[str, Any]:
|
||||
def get_credentials_schema(self) -> dict[str, Any]:
|
||||
"""YesCode 使用 auth_cookie 认证"""
|
||||
return YesCodeConnector.get_credentials_schema()
|
||||
|
||||
@@ -177,15 +177,15 @@ class YesCodeArchitecture(ProviderArchitecture):
|
||||
async def prepare_verify_config(
|
||||
self,
|
||||
base_url: str,
|
||||
config: Dict[str, Any],
|
||||
credentials: Dict[str, Any],
|
||||
) -> Dict[str, Any]:
|
||||
config: dict[str, Any],
|
||||
credentials: dict[str, Any],
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
预获取合并数据(balance + profile)
|
||||
|
||||
验证时并发调用两个接口获取完整数据。
|
||||
"""
|
||||
extra_config: Dict[str, Any] = {}
|
||||
extra_config: dict[str, Any] = {}
|
||||
|
||||
cookie_input = credentials.get("auth_cookie")
|
||||
if not cookie_input:
|
||||
@@ -198,7 +198,7 @@ class YesCodeArchitecture(ProviderArchitecture):
|
||||
|
||||
try:
|
||||
# 构建 client 参数
|
||||
client_kwargs: Dict[str, Any] = {
|
||||
client_kwargs: dict[str, Any] = {
|
||||
"headers": {"Cookie": cookie_header},
|
||||
"timeout": 10.0,
|
||||
"verify": get_ssl_context(),
|
||||
@@ -218,15 +218,15 @@ class YesCodeArchitecture(ProviderArchitecture):
|
||||
|
||||
def build_verify_headers(
|
||||
self,
|
||||
config: Dict[str, Any],
|
||||
credentials: Dict[str, Any],
|
||||
) -> Dict[str, str]:
|
||||
config: dict[str, Any],
|
||||
credentials: dict[str, Any],
|
||||
) -> dict[str, str]:
|
||||
"""
|
||||
构建 YesCode 的验证请求 Headers
|
||||
|
||||
使用 Cookie 认证,不使用 Authorization。
|
||||
"""
|
||||
headers: Dict[str, str] = {}
|
||||
headers: dict[str, str] = {}
|
||||
|
||||
# 添加 Cookie
|
||||
cookie_input = credentials.get("auth_cookie")
|
||||
@@ -238,7 +238,7 @@ class YesCodeArchitecture(ProviderArchitecture):
|
||||
def parse_verify_response(
|
||||
self,
|
||||
status_code: int,
|
||||
data: Dict[str, Any],
|
||||
data: dict[str, Any],
|
||||
) -> VerifyResult:
|
||||
"""解析 YesCode 验证响应(使用预获取的合并数据)"""
|
||||
if status_code == 401:
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
管理所有可用的 Provider 架构。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import threading
|
||||
from typing import Dict, List, Optional, Type
|
||||
|
||||
from src.core.logger import logger
|
||||
from src.services.provider_ops.architectures import (
|
||||
@@ -27,11 +28,11 @@ class ArchitectureRegistry:
|
||||
单例模式,管理所有可用的 Provider 架构。
|
||||
"""
|
||||
|
||||
_instance: Optional["ArchitectureRegistry"] = None
|
||||
_instance: ArchitectureRegistry | None = None
|
||||
_lock = threading.Lock()
|
||||
_initialized: bool = False
|
||||
|
||||
def __new__(cls) -> "ArchitectureRegistry":
|
||||
def __new__(cls) -> ArchitectureRegistry:
|
||||
if cls._instance is None:
|
||||
with cls._lock:
|
||||
if cls._instance is None:
|
||||
@@ -43,7 +44,7 @@ class ArchitectureRegistry:
|
||||
if self._initialized:
|
||||
return
|
||||
|
||||
self._architectures: Dict[str, ProviderArchitecture] = {}
|
||||
self._architectures: dict[str, ProviderArchitecture] = {}
|
||||
self._initialized = True
|
||||
|
||||
# 注册内置架构
|
||||
@@ -51,7 +52,7 @@ class ArchitectureRegistry:
|
||||
|
||||
def _register_builtin_architectures(self) -> None:
|
||||
"""注册内置架构"""
|
||||
builtin: List[Type[ProviderArchitecture]] = [
|
||||
builtin: list[type[ProviderArchitecture]] = [
|
||||
AnyrouterArchitecture,
|
||||
CubenceArchitecture,
|
||||
GenericApiArchitecture,
|
||||
@@ -92,7 +93,7 @@ class ArchitectureRegistry:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get(self, architecture_id: str) -> Optional[ProviderArchitecture]:
|
||||
def get(self, architecture_id: str) -> ProviderArchitecture | None:
|
||||
"""
|
||||
获取架构
|
||||
|
||||
@@ -104,7 +105,7 @@ class ArchitectureRegistry:
|
||||
"""
|
||||
return self._architectures.get(architecture_id)
|
||||
|
||||
def get_or_default(self, architecture_id: Optional[str] = None) -> ProviderArchitecture:
|
||||
def get_or_default(self, architecture_id: str | None = None) -> ProviderArchitecture:
|
||||
"""
|
||||
获取架构,如果不存在则返回默认架构
|
||||
|
||||
@@ -120,21 +121,21 @@ class ArchitectureRegistry:
|
||||
# 返回默认架构(generic_api)
|
||||
return self._architectures.get("generic_api", GenericApiArchitecture())
|
||||
|
||||
def list_all(self) -> List[ProviderArchitecture]:
|
||||
def list_all(self) -> list[ProviderArchitecture]:
|
||||
"""获取所有已注册的架构"""
|
||||
return list(self._architectures.values())
|
||||
|
||||
def list_ids(self) -> List[str]:
|
||||
def list_ids(self) -> list[str]:
|
||||
"""获取所有已注册的架构 ID"""
|
||||
return list(self._architectures.keys())
|
||||
|
||||
def to_dict_list(self) -> List[Dict]:
|
||||
def to_dict_list(self) -> list[dict]:
|
||||
"""获取所有架构的字典表示(用于 API 响应)"""
|
||||
return [arch.to_dict() for arch in self._architectures.values()]
|
||||
|
||||
|
||||
# 全局注册表实例
|
||||
_registry: Optional[ArchitectureRegistry] = None
|
||||
_registry: ArchitectureRegistry | None = None
|
||||
|
||||
|
||||
def get_registry() -> ArchitectureRegistry:
|
||||
|
||||
@@ -8,7 +8,7 @@ import asyncio
|
||||
import os
|
||||
from dataclasses import asdict
|
||||
from datetime import datetime, timezone
|
||||
from typing import Any, Dict, List, Optional
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
@@ -18,7 +18,7 @@ from src.core.crypto import CryptoService
|
||||
from src.core.logger import logger
|
||||
from src.database import create_session
|
||||
from src.models.database import Provider
|
||||
from src.services.provider_ops.architectures import ProviderArchitecture, ProviderConnector
|
||||
from src.services.provider_ops.architectures import ProviderConnector
|
||||
from src.services.provider_ops.registry import get_registry
|
||||
from src.services.provider_ops.types import (
|
||||
ActionResult,
|
||||
@@ -85,11 +85,11 @@ class ProviderOpsService:
|
||||
self.crypto = CryptoService()
|
||||
|
||||
# 连接器缓存 {provider_id: ProviderConnector}
|
||||
self._connectors: Dict[str, ProviderConnector] = {}
|
||||
self._connectors: dict[str, ProviderConnector] = {}
|
||||
|
||||
# ==================== 配置管理 ====================
|
||||
|
||||
def get_config(self, provider_id: str) -> Optional[ProviderOpsConfig]:
|
||||
def get_config(self, provider_id: str) -> ProviderOpsConfig | None:
|
||||
"""
|
||||
获取 Provider 的操作配置
|
||||
|
||||
@@ -186,7 +186,7 @@ class ProviderOpsService:
|
||||
async def connect(
|
||||
self,
|
||||
provider_id: str,
|
||||
credentials: Optional[Dict[str, Any]] = None,
|
||||
credentials: dict[str, Any] | None = None,
|
||||
) -> tuple[bool, str]:
|
||||
"""
|
||||
建立与 Provider 的连接
|
||||
@@ -296,7 +296,7 @@ class ProviderOpsService:
|
||||
self,
|
||||
provider_id: str,
|
||||
action_type: ProviderActionType,
|
||||
action_config: Optional[Dict[str, Any]] = None,
|
||||
action_config: dict[str, Any] | None = None,
|
||||
) -> ActionResult:
|
||||
"""
|
||||
执行操作
|
||||
@@ -371,7 +371,7 @@ class ProviderOpsService:
|
||||
async def query_balance(
|
||||
self,
|
||||
provider_id: str,
|
||||
config: Optional[Dict[str, Any]] = None,
|
||||
config: dict[str, Any] | None = None,
|
||||
) -> ActionResult:
|
||||
"""
|
||||
查询余额(快捷方法)
|
||||
@@ -508,7 +508,7 @@ class ProviderOpsService:
|
||||
self,
|
||||
provider_id: str,
|
||||
quota_usd: float,
|
||||
extra: Optional[Dict[str, Any]] = None,
|
||||
extra: dict[str, Any] | None = None,
|
||||
) -> None:
|
||||
"""
|
||||
从验证结果缓存余额
|
||||
@@ -538,7 +538,7 @@ class ProviderOpsService:
|
||||
await CacheService.set(cache_key, cache_data, BALANCE_CACHE_TTL)
|
||||
logger.debug(f"验证成功,缓存余额: provider_id={provider_id}, quota_usd={quota_usd}")
|
||||
|
||||
async def _get_cached_balance(self, provider_id: str) -> Optional[ActionResult]:
|
||||
async def _get_cached_balance(self, provider_id: str) -> ActionResult | None:
|
||||
"""获取缓存的余额"""
|
||||
cache_key = f"provider_ops:balance:{provider_id}"
|
||||
cached = await CacheService.get(cache_key)
|
||||
@@ -585,7 +585,7 @@ class ProviderOpsService:
|
||||
async def checkin(
|
||||
self,
|
||||
provider_id: str,
|
||||
config: Optional[Dict[str, Any]] = None,
|
||||
config: dict[str, Any] | None = None,
|
||||
) -> ActionResult:
|
||||
"""
|
||||
签到(快捷方法)
|
||||
@@ -601,11 +601,11 @@ class ProviderOpsService:
|
||||
|
||||
# ==================== 辅助方法 ====================
|
||||
|
||||
def _get_provider(self, provider_id: str) -> Optional[Provider]:
|
||||
def _get_provider(self, provider_id: str) -> Provider | None:
|
||||
"""获取 Provider"""
|
||||
return self.db.query(Provider).filter(Provider.id == provider_id).first()
|
||||
|
||||
def _get_provider_base_url(self, provider: Provider) -> Optional[str]:
|
||||
def _get_provider_base_url(self, provider: Provider) -> str | None:
|
||||
"""从 Provider 获取 base_url"""
|
||||
# 优先从第一个 endpoint 获取
|
||||
if provider.endpoints:
|
||||
@@ -624,7 +624,7 @@ class ProviderOpsService:
|
||||
|
||||
return None
|
||||
|
||||
def _encrypt_credentials(self, credentials: Dict[str, Any]) -> Dict[str, Any]:
|
||||
def _encrypt_credentials(self, credentials: dict[str, Any]) -> dict[str, Any]:
|
||||
"""加密凭据中的敏感字段"""
|
||||
encrypted = {}
|
||||
for key, value in credentials.items():
|
||||
@@ -639,7 +639,7 @@ class ProviderOpsService:
|
||||
encrypted[key] = value
|
||||
return encrypted
|
||||
|
||||
def _decrypt_credentials(self, credentials: Dict[str, Any]) -> Dict[str, Any]:
|
||||
def _decrypt_credentials(self, credentials: dict[str, Any]) -> dict[str, Any]:
|
||||
"""解密凭据中的敏感字段"""
|
||||
decrypted = {}
|
||||
for key, value in credentials.items():
|
||||
@@ -653,7 +653,7 @@ class ProviderOpsService:
|
||||
decrypted[key] = value
|
||||
return decrypted
|
||||
|
||||
def get_masked_credentials(self, credentials: Dict[str, Any]) -> Dict[str, Any]:
|
||||
def get_masked_credentials(self, credentials: dict[str, Any]) -> dict[str, Any]:
|
||||
"""
|
||||
获取脱敏后的凭据
|
||||
|
||||
@@ -683,8 +683,8 @@ class ProviderOpsService:
|
||||
def merge_credentials_with_saved(
|
||||
self,
|
||||
provider_id: str,
|
||||
credentials: Dict[str, Any],
|
||||
) -> Dict[str, Any]:
|
||||
credentials: dict[str, Any],
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
合并凭据:如果请求中的敏感字段为空,使用已保存的凭据
|
||||
|
||||
@@ -720,8 +720,8 @@ class ProviderOpsService:
|
||||
# ==================== 批量操作 ====================
|
||||
|
||||
async def batch_query_balance(
|
||||
self, provider_ids: Optional[List[str]] = None
|
||||
) -> Dict[str, ActionResult]:
|
||||
self, provider_ids: list[str] | None = None
|
||||
) -> dict[str, ActionResult]:
|
||||
"""
|
||||
批量查询余额(优先返回缓存,后台异步刷新)
|
||||
|
||||
@@ -780,10 +780,10 @@ class ProviderOpsService:
|
||||
base_url: str,
|
||||
architecture_id: str,
|
||||
auth_type: ConnectorAuthType,
|
||||
config: Dict[str, Any],
|
||||
credentials: Dict[str, Any],
|
||||
provider_id: Optional[str] = None,
|
||||
) -> Dict[str, Any]:
|
||||
config: dict[str, Any],
|
||||
credentials: dict[str, Any],
|
||||
provider_id: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
验证认证配置
|
||||
|
||||
@@ -831,7 +831,7 @@ class ProviderOpsService:
|
||||
|
||||
try:
|
||||
# 构建 httpx client 参数
|
||||
client_kwargs: Dict[str, Any] = {
|
||||
client_kwargs: dict[str, Any] = {
|
||||
"timeout": 30.0,
|
||||
"verify": get_ssl_context(),
|
||||
}
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
Provider 操作模块类型定义
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime, timezone
|
||||
from enum import Enum
|
||||
from typing import Any, Dict, List, Optional
|
||||
from typing import Any
|
||||
|
||||
|
||||
class ConnectorAuthType(str, Enum):
|
||||
@@ -60,23 +62,23 @@ class ConnectorStatus(str, Enum):
|
||||
class BalanceInfo:
|
||||
"""余额信息"""
|
||||
|
||||
total_granted: Optional[float] = None # 总授予额度
|
||||
total_used: Optional[float] = None # 已使用额度
|
||||
total_available: Optional[float] = None # 可用余额
|
||||
expires_at: Optional[datetime] = None # 过期时间
|
||||
total_granted: float | None = None # 总授予额度
|
||||
total_used: float | None = None # 已使用额度
|
||||
total_available: float | None = None # 可用余额
|
||||
expires_at: datetime | None = None # 过期时间
|
||||
currency: str = "USD" # 货币单位
|
||||
extra: Dict[str, Any] = field(default_factory=dict) # 额外信息
|
||||
extra: dict[str, Any] = field(default_factory=dict) # 额外信息
|
||||
|
||||
|
||||
@dataclass
|
||||
class CheckinInfo:
|
||||
"""签到信息"""
|
||||
|
||||
reward: Optional[float] = None # 奖励额度
|
||||
streak_days: Optional[int] = None # 连续签到天数
|
||||
next_reward: Optional[float] = None # 下次奖励
|
||||
message: Optional[str] = None # 签到消息
|
||||
extra: Dict[str, Any] = field(default_factory=dict)
|
||||
reward: float | None = None # 奖励额度
|
||||
streak_days: int | None = None # 连续签到天数
|
||||
next_reward: float | None = None # 下次奖励
|
||||
message: str | None = None # 签到消息
|
||||
extra: dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -85,13 +87,13 @@ class ActionResult:
|
||||
|
||||
status: ActionStatus
|
||||
action_type: ProviderActionType
|
||||
data: Optional[Any] = None # 操作返回的数据(如 BalanceInfo, CheckinInfo)
|
||||
message: Optional[str] = None # 消息
|
||||
data: Any | None = None # 操作返回的数据(如 BalanceInfo, CheckinInfo)
|
||||
message: str | None = None # 消息
|
||||
executed_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
|
||||
response_time_ms: Optional[int] = None # 响应时间(毫秒)
|
||||
raw_response: Optional[Dict[str, Any]] = None # 原始响应(调试用)
|
||||
response_time_ms: int | None = None # 响应时间(毫秒)
|
||||
raw_response: dict[str, Any] | None = None # 原始响应(调试用)
|
||||
cache_ttl_seconds: int = 300 # 建议缓存时间
|
||||
retry_after_seconds: Optional[int] = None # 失败后重试间隔
|
||||
retry_after_seconds: int | None = None # 失败后重试间隔
|
||||
|
||||
@property
|
||||
def is_success(self) -> bool:
|
||||
@@ -104,10 +106,10 @@ class ConnectorState:
|
||||
|
||||
status: ConnectorStatus
|
||||
auth_type: ConnectorAuthType
|
||||
connected_at: Optional[datetime] = None
|
||||
expires_at: Optional[datetime] = None
|
||||
last_error: Optional[str] = None
|
||||
extra: Dict[str, Any] = field(default_factory=dict)
|
||||
connected_at: datetime | None = None
|
||||
expires_at: datetime | None = None
|
||||
last_error: str | None = None
|
||||
extra: dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -115,21 +117,21 @@ class ProviderOpsConfig:
|
||||
"""Provider 操作配置(存储在 Provider.config['provider_ops'] 中)"""
|
||||
|
||||
architecture_id: str = "generic_api"
|
||||
base_url: Optional[str] = None # API 基础地址
|
||||
base_url: str | None = None # API 基础地址
|
||||
|
||||
# 连接器配置
|
||||
connector_auth_type: ConnectorAuthType = ConnectorAuthType.API_KEY
|
||||
connector_config: Dict[str, Any] = field(default_factory=dict)
|
||||
connector_credentials: Dict[str, Any] = field(default_factory=dict) # 加密存储
|
||||
connector_config: dict[str, Any] = field(default_factory=dict)
|
||||
connector_credentials: dict[str, Any] = field(default_factory=dict) # 加密存储
|
||||
|
||||
# 操作配置
|
||||
actions: Dict[str, Dict[str, Any]] = field(default_factory=dict)
|
||||
actions: dict[str, dict[str, Any]] = field(default_factory=dict)
|
||||
|
||||
# 定时任务配置
|
||||
schedule: Dict[str, str] = field(default_factory=dict) # {action_type: cron_expression}
|
||||
schedule: dict[str, str] = field(default_factory=dict) # {action_type: cron_expression}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: Optional[Dict[str, Any]]) -> "ProviderOpsConfig":
|
||||
def from_dict(cls, data: dict[str, Any] | None) -> ProviderOpsConfig:
|
||||
"""从字典创建配置"""
|
||||
if not data:
|
||||
return cls()
|
||||
@@ -146,7 +148,7 @@ class ProviderOpsConfig:
|
||||
schedule=data.get("schedule", {}),
|
||||
)
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
"""转换为字典(用于存储)"""
|
||||
return {
|
||||
"architecture_id": self.architecture_id,
|
||||
|
||||
Reference in New Issue
Block a user