feat: 扩展 Rust gateway 全功能模块,新增 billing/crypto/wallet crate 及完整数据层

- 新增 aether-billing、aether-crypto、aether-wallet 独立 crate
- aether-data 扩展 repository 层:announcements、auth_modules、billing、
  candidate_selection、gemini_file_mappings、global_models、management_tokens、
  oauth_providers、proxy_nodes、quota、users、wallet 等模块
- aether-gateway 新增 api/auth/billing/control/middleware/scheduler/usage/
  video_tasks/hooks/maintenance/model_fetch/provider_transport 等功能模块
- 重构 executor decision 和 gateway state 为模块目录结构
- 新增 gateway router、frontdoor 路由层及对应测试
- Python 侧 API 路由重构,新增 compat/support 模块
- 前端 Logo 组件更新及 Provider 管理页面调整
This commit is contained in:
fawney19
2026-03-31 19:19:04 +08:00
parent b5a0070023
commit ddf18fed9a
690 changed files with 235087 additions and 16301 deletions

View File

@@ -1,12 +1,19 @@
from __future__ import annotations
from types import SimpleNamespace
from typing import Any
from unittest.mock import AsyncMock
import pytest
from src.config import config as runtime_config
from src.services.provider_ops.service import ProviderOpsService
from src.services.provider_ops.types import ConnectorAuthType, ProviderActionType
from src.services.provider_ops.types import (
ActionStatus,
ConnectorAuthType,
ProviderActionType,
ProviderOpsConfig,
)
from src.services.request.rust_executor_client import RustExecutorSyncResult
@@ -53,6 +60,14 @@ class _FakeRegistry:
return self._architecture
class _ExplodingConnector:
async def is_authenticated(self) -> bool:
raise AssertionError("Python connector auth check should not run")
def get_client(self) -> Any:
raise AssertionError("Python connector client should not be created")
class _SuccessResult:
def __init__(self) -> None:
self.success = True
@@ -165,3 +180,106 @@ async def test_verify_auth_prefers_rust_executor(
assert captured["plan"].proxy.mode == "tunnel"
assert captured["plan"].proxy.node_id == "node-1"
cache_balance.assert_awaited_once_with("provider-1", 2.0, {"window": "day"})
@pytest.mark.asyncio
async def test_verify_auth_returns_explicit_failure_when_rust_verifier_unavailable(
monkeypatch: pytest.MonkeyPatch,
) -> None:
service = ProviderOpsService(_FakeDB())
architecture = _SuccessArchitecture()
monkeypatch.setattr(
"src.services.provider_ops.service.get_registry",
lambda: _FakeRegistry(architecture),
)
monkeypatch.setattr(
service,
"_try_rust_verify_response",
AsyncMock(return_value=None),
)
monkeypatch.setattr(
"src.services.proxy_node.resolver.resolve_ops_proxy_config_async",
AsyncMock(return_value=(None, None)),
)
result = await service.verify_auth(
base_url="https://example.com",
architecture_id="sub2api",
auth_type=ConnectorAuthType.SESSION_LOGIN,
config={},
credentials={"access_token": "token"},
)
assert result == {"success": False, "message": "认证验证仅支持 Rust executor"}
@pytest.mark.asyncio
@pytest.mark.parametrize("backend", ["python", "rust"])
async def test_connect_returns_explicit_failure_without_python_connector(
monkeypatch: pytest.MonkeyPatch,
backend: str,
) -> None:
service = ProviderOpsService(_FakeDB())
service._connectors["provider-1"] = object() # type: ignore[assignment]
monkeypatch.setattr(runtime_config, "executor_backend", backend)
monkeypatch.setattr(
service,
"_get_provider",
lambda _provider_id: SimpleNamespace(base_url="https://example.com"),
)
monkeypatch.setattr(
service,
"get_config",
lambda _provider_id: ProviderOpsConfig(
architecture_id="sub2api",
base_url="https://example.com",
connector_auth_type=ConnectorAuthType.API_KEY,
),
)
monkeypatch.setattr(
"src.services.provider_ops.service.get_registry",
lambda: (_ for _ in ()).throw(
AssertionError("Python provider connector registry should not be used")
),
)
success, message = await service.connect("provider-1", {"api_key": "token"})
assert success is False
assert message == "Provider 连接仅支持 Rust executor"
assert "provider-1" not in service._connectors
@pytest.mark.asyncio
@pytest.mark.parametrize("backend", ["python", "rust"])
async def test_execute_action_returns_not_supported_without_python_connector(
monkeypatch: pytest.MonkeyPatch,
backend: str,
) -> None:
service = ProviderOpsService(_FakeDB())
service._connectors["provider-1"] = _ExplodingConnector() # type: ignore[assignment]
monkeypatch.setattr(runtime_config, "executor_backend", backend)
monkeypatch.setattr(
service,
"get_config",
lambda _provider_id: ProviderOpsConfig(
architecture_id="sub2api",
base_url="https://example.com",
connector_auth_type=ConnectorAuthType.API_KEY,
),
)
monkeypatch.setattr(
"src.services.provider_ops.service.get_registry",
lambda: (_ for _ in ()).throw(
AssertionError("Python provider action architecture should not be used")
),
)
result = await service.execute_action("provider-1", ProviderActionType.QUERY_BALANCE)
assert result.status == ActionStatus.NOT_SUPPORTED
assert result.action_type == ProviderActionType.QUERY_BALANCE
assert result.message == "Provider 操作仅支持 Rust executor"