mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 17:30:23 +08:00
feat: 引入 Rust executor/gateway sidecar 及 Python 侧双后端适配
- 新增 Rust workspace crates: aether-contracts, aether-executor, aether-gateway - aether-executor: 支持 Unix Socket/TCP 双传输模式,处理同步/流式上游请求 - aether-gateway: 作为本地主入口代理,集成 /api/internal/gateway/resolve 认证预解析 - Python 侧新增 ExecutionPlan 契约和 RustExecutorClient,各 handler 支持 executor_backend=rust 时将可序列化请求转发给 Rust executor 执行 - 重构 dev.sh 支持 executor/gateway 进程编排与生命周期管理 - 新增 internal gateway 路由,提供 resolve/passthrough 端点 - handler 层(chat/cli/video/endpoint_checker 等)全面适配 Rust executor 回退逻辑 - pipeline 层支持 trusted auth context 跳过重复认证 - 新增 Rust CI workflow 及对应测试用例
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
import pytest
|
||||
|
||||
from src.services.provider_ops.service import ProviderOpsService
|
||||
from src.services.provider_ops.types import ConnectorAuthType
|
||||
from src.services.provider_ops.types import ConnectorAuthType, ProviderActionType
|
||||
from src.services.request.rust_executor_client import RustExecutorSyncResult
|
||||
|
||||
|
||||
class _FakeDB:
|
||||
@@ -51,6 +53,43 @@ class _FakeRegistry:
|
||||
return self._architecture
|
||||
|
||||
|
||||
class _SuccessResult:
|
||||
def __init__(self) -> None:
|
||||
self.success = True
|
||||
self.quota = 200.0
|
||||
self.extra = {"window": "day"}
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
return {"success": True, "quota": self.quota}
|
||||
|
||||
|
||||
class _SuccessArchitecture:
|
||||
default_action_configs = {ProviderActionType.QUERY_BALANCE: {"quota_divisor": 100}}
|
||||
|
||||
def get_verify_endpoint(self) -> str:
|
||||
return "/verify"
|
||||
|
||||
async def prepare_verify_config(
|
||||
self,
|
||||
_base_url: str,
|
||||
_config: dict[str, Any],
|
||||
_credentials: dict[str, Any],
|
||||
) -> dict[str, Any]:
|
||||
return {}
|
||||
|
||||
def build_verify_headers(
|
||||
self,
|
||||
_config: dict[str, Any],
|
||||
_credentials: dict[str, Any],
|
||||
) -> dict[str, str]:
|
||||
return {"authorization": "Bearer test"}
|
||||
|
||||
def parse_verify_response(self, status_code: int, data: dict[str, Any]) -> _SuccessResult:
|
||||
assert status_code == 200
|
||||
assert data == {"ok": True}
|
||||
return _SuccessResult()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_verify_auth_returns_failure_when_prepare_verify_config_raises_value_error(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
@@ -72,3 +111,57 @@ async def test_verify_auth_returns_failure_when_prepare_verify_config_raises_val
|
||||
)
|
||||
|
||||
assert result == {"success": False, "message": "invalid refresh token"}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_verify_auth_prefers_rust_executor(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
from src.services.provider_ops import service as module
|
||||
from src.services.request import rust_executor_client as rust_module
|
||||
|
||||
service = ProviderOpsService(_FakeDB())
|
||||
architecture = _SuccessArchitecture()
|
||||
|
||||
monkeypatch.setattr(
|
||||
module,
|
||||
"get_registry",
|
||||
lambda: _FakeRegistry(architecture),
|
||||
)
|
||||
monkeypatch.setattr(module.config, "executor_backend", "rust")
|
||||
monkeypatch.setattr(
|
||||
"src.services.proxy_node.resolver.resolve_ops_proxy_config_async",
|
||||
AsyncMock(return_value=(None, "node-1")),
|
||||
)
|
||||
|
||||
cache_balance = AsyncMock()
|
||||
monkeypatch.setattr(service, "_cache_balance_from_verify", cache_balance)
|
||||
|
||||
captured: dict[str, Any] = {}
|
||||
|
||||
async def _fake_execute_sync_json(self: object, plan: Any) -> RustExecutorSyncResult:
|
||||
captured["plan"] = plan
|
||||
return RustExecutorSyncResult(
|
||||
status_code=200,
|
||||
response_json={"ok": True},
|
||||
headers={"content-type": "application/json"},
|
||||
)
|
||||
|
||||
monkeypatch.setattr(rust_module.RustExecutorClient, "execute_sync_json", _fake_execute_sync_json)
|
||||
|
||||
result = await service.verify_auth(
|
||||
base_url="https://example.com",
|
||||
architecture_id="sub2api",
|
||||
auth_type=ConnectorAuthType.SESSION_LOGIN,
|
||||
config={},
|
||||
credentials={"access_token": "token"},
|
||||
provider_id="provider-1",
|
||||
)
|
||||
|
||||
assert result == {"success": True, "quota": 200.0}
|
||||
assert captured["plan"].method == "GET"
|
||||
assert captured["plan"].url == "https://example.com/verify"
|
||||
assert captured["plan"].proxy is not None
|
||||
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"})
|
||||
|
||||
Reference in New Issue
Block a user