ForcePilot/backend/package/yuxi/external_systems/infrastructure/container.py
Kris 74709ba2d3 feat: 完成外部系统限界上下文核心代码实现
新增六边形架构核心代码包,包含:
1. 协议适配器层:HTTP/SMTP/IMAP/SSH/GRPC等多协议适配器实现
2. 认证插件体系:基础认证、API密钥、HMAC等多类型认证插件
3. 执行编排框架:工具执行器、上下文构建、运行时治理组件
4. 用例端口与DTO:定义领域服务端口与数据传输对象
5. 厂商集成包框架:支持第三方系统集成扩展
6. 基础设施装配层:实现依赖注入与服务装配

所有代码遵循六边形架构设计原则,实现端口与适配器解耦,支持动态扩展与自动发现。
2026-06-20 22:12:42 +08:00

345 lines
14 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.

"""infrastructure/container.pyuse_cases service 装配容器。
本模块是六边形架构的"唯一装配点"(设计方案 §8.1),负责:
- 将 persistence 仓储 / runtime 横切关注点 / framework 单例 装配为 24 个 use_cases service
- 对外暴露两个 factory
* ``create_use_cases``:底层 factory由调用方注入全部依赖
* ``create_use_cases_from_db``:请求级 factory封装三层创建repos + runtime + use_cases
边界规范:
- 本模块是**唯一允许 import use_cases service 实现类**的地方
- ``UseCases`` dataclass 字段类型使用驱动端口 Protocol非实现类
- service 构造调用使用**实际构造函数签名**(已逐个核对 use_cases/*.py 的 ``__init__``
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import Any
from sqlalchemy.ext.asyncio import AsyncSession
from yuxi.external_systems.adapters.persistence import (
Repositories,
SqlAlchemyUnitOfWork,
create_repositories,
)
from yuxi.external_systems.core.contracts import (
AdapterRegistry,
EventPublisher,
ToolExecutor,
UnitOfWork,
)
from yuxi.external_systems.exceptions import EntityNotFoundError
from yuxi.external_systems.framework.runtime import (
InMemoryEventPublisher,
RepositoryPorts,
RuntimeServices,
TestCaseRunnerImpl,
create_runtime_services,
create_tool_executor,
)
from yuxi.external_systems.use_cases.context_builder import ContextBuilder
# 驱动端口类型(供 UseCases dataclass 字段标注,非实现类)
from yuxi.external_systems.use_cases.ports import (
AccessRuleServicePort,
AdapterStatsServicePort,
AlertServicePort,
AssetServicePort,
AuditLogServicePort,
ContextBuilderPort,
DashboardServicePort,
EnvironmentServicePort,
ExecutionServicePort,
HealthCheckServicePort,
ImportServicePort,
IntegrationToolServicePort,
MetricServicePort,
NotificationChannelServicePort,
NotificationServicePort,
QuotaServicePort,
SecretRotationServicePort,
SystemServicePort,
TestCaseServicePort,
TestRegressionServicePort,
TokenServicePort,
ToolServicePort,
WebhookEventHandlerPort,
WebhookSubscriptionServicePort,
)
from yuxi.external_systems.use_cases.ports.trash_service_port import TrashServicePort
# 唯一允许 import service 实现类的地方(设计方案 §8.1
from yuxi.external_systems.use_cases.services.access_rule_service import AccessRuleService
from yuxi.external_systems.use_cases.services.adapter_stats_service import AdapterStatsService
from yuxi.external_systems.use_cases.services.alert_service import AlertService
from yuxi.external_systems.use_cases.services.asset_service import AssetService
from yuxi.external_systems.use_cases.services.audit_log_service import AuditLogService
from yuxi.external_systems.use_cases.services.dashboard_service import DashboardService
from yuxi.external_systems.use_cases.services.environment_service import EnvironmentService
from yuxi.external_systems.use_cases.services.execution_service import ExecutionService
from yuxi.external_systems.use_cases.services.health_check_service import HealthCheckService
from yuxi.external_systems.use_cases.services.import_service import ImportService
from yuxi.external_systems.use_cases.services.integration_tool_service import (
IntegrationToolService,
)
from yuxi.external_systems.use_cases.services.metric_service import MetricService
from yuxi.external_systems.use_cases.services.notification_channel_service import (
NotificationChannelService,
)
from yuxi.external_systems.use_cases.services.notification_service import NotificationService
from yuxi.external_systems.use_cases.services.quota_service import QuotaService
from yuxi.external_systems.use_cases.services.secret_rotation_service import (
SecretRotationService,
)
from yuxi.external_systems.use_cases.services.system_service import SystemService
from yuxi.external_systems.use_cases.services.test_case_service import TestCaseService
from yuxi.external_systems.use_cases.services.test_regression_service import (
TestRegressionService,
)
from yuxi.external_systems.use_cases.services.token_service import TokenService
from yuxi.external_systems.use_cases.services.tool_service import ToolService
from yuxi.external_systems.use_cases.services.trash_service import TrashService
from yuxi.external_systems.use_cases.services.webhook_event_handler import (
WebhookEventHandler,
)
from yuxi.external_systems.use_cases.services.webhook_subscription_service import (
WebhookSubscriptionService,
)
from .config import default_adapter_registry
__all__ = [
"UseCases",
"create_use_cases",
"create_use_cases_from_db",
]
@dataclass
class UseCases:
"""一组 use_cases service 实例(以端口类型标注),由 factory 创建。
字段类型使用驱动端口 Protocol非实现类保证调用方只依赖端口。
"""
context_builder: ContextBuilderPort
system_service: SystemServicePort
tool_service: ToolServicePort
environment_service: EnvironmentServicePort
execution_service: ExecutionServicePort
token_service: TokenServicePort
audit_log_service: AuditLogServicePort
asset_service: AssetServicePort
import_service: ImportServicePort
integration_tool_service: IntegrationToolServicePort
webhook_subscription_service: WebhookSubscriptionServicePort
webhook_event_handler: WebhookEventHandlerPort
quota_service: QuotaServicePort
alert_service: AlertServicePort
notification_service: NotificationServicePort
notification_channel_service: NotificationChannelServicePort
secret_rotation_service: SecretRotationServicePort
access_rule_service: AccessRuleServicePort
adapter_stats_service: AdapterStatsServicePort
test_case_service: TestCaseServicePort
test_regression_service: TestRegressionServicePort
metric_service: MetricServicePort
health_check_service: HealthCheckServicePort
dashboard_service: DashboardServicePort
trash_service: TrashServicePort
def create_use_cases(
repos: Repositories,
runtime: RuntimeServices,
uow: UnitOfWork,
event_publisher: EventPublisher,
*,
adapter_registry: AdapterRegistry,
tool_executor: ToolExecutor,
context_builder: ContextBuilderPort | None = None,
) -> UseCases:
"""factory 函数:创建一组 use_cases service 实例。
由 infrastructure 层调用,注入所有依赖。实现类仅在此处 import规范 §8.1)。
Args:
repos: 仓储聚合persistence 层创建,共享 db 会话)。
runtime: 请求级 runtime 横切关注点集合。
uow: 工作单元(事务边界)。
event_publisher: 事件发布器。
adapter_registry: 适配器注册表(全局只读单例)。
tool_executor: 工具执行器(请求级实例)。
context_builder: 可选,上下文构造器。未传入时由本函数创建。
``create_use_cases_from_db`` 传入已创建的实例以复用给 ToolExecutor。
Returns:
装配完成的 ``UseCases`` 实例24 个 service + 1 个 context_builder
"""
context_builder = context_builder or ContextBuilder(repos, runtime)
system_service = SystemService(repos, runtime, adapter_registry, uow, event_publisher)
tool_service = ToolService(
repos,
runtime,
adapter_registry,
tool_executor,
uow,
event_publisher,
context_builder,
)
environment_service = EnvironmentService(repos, runtime, uow, event_publisher)
execution_service = ExecutionService(
repos,
runtime,
uow,
event_publisher,
tool_executor,
)
token_service = TokenService(repos, runtime, uow, event_publisher)
audit_log_service = AuditLogService(repos, runtime)
asset_service = AssetService(repos, runtime, adapter_registry, uow, event_publisher)
import_service = ImportService(repos, runtime, adapter_registry, uow, event_publisher, tool_service)
integration_tool_service = IntegrationToolService(
repos,
runtime,
uow,
event_publisher,
tool_service,
)
webhook_event_handler = WebhookEventHandler(repos, runtime, uow, event_publisher)
webhook_subscription_service = WebhookSubscriptionService(
repos,
runtime,
uow,
event_publisher,
webhook_event_handler,
)
quota_service = QuotaService(repos, runtime, uow, event_publisher)
alert_service = AlertService(repos, runtime, uow, event_publisher)
notification_service = NotificationService(repos, runtime, uow, event_publisher)
notification_channel_service = NotificationChannelService(
repos,
runtime,
uow,
event_publisher,
)
secret_rotation_service = SecretRotationService(repos, runtime, uow, event_publisher)
access_rule_service = AccessRuleService(repos, runtime, uow, event_publisher)
test_case_service = TestCaseService(repos, runtime, uow, event_publisher)
test_regression_service = TestRegressionService(repos, runtime, uow, event_publisher)
metric_service = MetricService(repos.metric)
health_check_service = HealthCheckService(repos.health_check)
adapter_stats_service = AdapterStatsService(repos)
# 纯查询用例,仅注入 repos对齐 AdapterStatsService / MetricService / HealthCheckService
dashboard_service = DashboardService(repos)
trash_service = TrashService(repos, runtime, uow, event_publisher)
return UseCases(
context_builder=context_builder,
system_service=system_service,
tool_service=tool_service,
environment_service=environment_service,
execution_service=execution_service,
token_service=token_service,
audit_log_service=audit_log_service,
asset_service=asset_service,
import_service=import_service,
integration_tool_service=integration_tool_service,
webhook_subscription_service=webhook_subscription_service,
webhook_event_handler=webhook_event_handler,
quota_service=quota_service,
alert_service=alert_service,
notification_service=notification_service,
notification_channel_service=notification_channel_service,
secret_rotation_service=secret_rotation_service,
access_rule_service=access_rule_service,
adapter_stats_service=adapter_stats_service,
test_case_service=test_case_service,
test_regression_service=test_regression_service,
metric_service=metric_service,
health_check_service=health_check_service,
dashboard_service=dashboard_service,
trash_service=trash_service,
)
def create_use_cases_from_db(db: AsyncSession) -> UseCases:
"""请求级工厂:从 db session 创建完整的 use_cases 实例。
封装三层创建逻辑repos + runtime + use_cases对调用方隐藏内部依赖结构。
由 router 在请求开始时调用。
注意:``ToolExecutor`` 是请求级实例(依赖请求级 recorder + metrics_collector
在此处创建,不使用全局单例。
Args:
db: SQLAlchemy 异步会话(请求级)。
Returns:
装配完成的 ``UseCases`` 实例24 个 service + 1 个 context_builder
"""
# 1. 请求级 repos + UnitOfWork
repos = create_repositories(db)
uow = SqlAlchemyUnitOfWork(db)
# 2. 请求级 runtime services先不传 test_execute_callbackToolExecutor 需
# runtime.metrics_collector而回调需 ToolExecutor存在循环依赖步骤 4 回填)
runtime_repos = RepositoryPorts(
token=repos.token,
audit_log=repos.audit_log,
metric=repos.metric,
alert=repos.alert,
quota_usage=repos.quota_usage,
tool_access_rule=repos.tool_access_rule,
webhook_subscription=repos.webhook_subscription,
webhook_event=repos.webhook_event,
tool_test_case=repos.tool_test_case,
secret_rotation_policy=repos.secret_rotation_policy,
)
runtime = create_runtime_services(runtime_repos)
event_publisher = InMemoryEventPublisher()
# 3. 请求级 ContextBuilderToolExecutor 系统级路径依赖它构造 RuntimeContext
context_builder = ContextBuilder(repos, runtime)
# 4. 请求级 ToolExecutor注入请求级 recorder + metrics_collector + context_builder
tool_executor = create_tool_executor(
recorder=repos.execution_recorder,
metrics_collector=runtime.metrics_collector,
context_builder=context_builder,
)
# 5. 回填 TestCaseRunner 执行回调(两阶段创建,打破循环依赖)
# 将 ToolExecutor.execute_external_tool 包装为 ExecuteCallback
# (tool_slug, parameters, env_key) → 执行结果。
# 回调签名与执行器不直接兼容(回调收 slug执行器需 ExecutableTool
# 需通过 repos.tool.get_by_slug 解析 slug对齐 tool_service 执行路径。
async def _execute_callback(
tool_slug: str,
parameters: dict[str, Any],
env_key: str | None,
) -> Any:
tool = await repos.tool.get_by_slug(tool_slug)
if tool is None:
raise EntityNotFoundError(f"外部工具 {tool_slug} 不存在")
env = {"YUXI_ACTIVE_ENV": env_key} if env_key else None
return await tool_executor.execute_external_tool(tool, parameters, env=env)
runtime.test_case_runner = TestCaseRunnerImpl(
repos.tool_test_case,
_execute_callback,
)
# 6. 装配 use_cases复用步骤 3 创建的 context_builder避免重复实例化
return create_use_cases(
repos,
runtime,
uow,
event_publisher,
adapter_registry=default_adapter_registry,
tool_executor=tool_executor,
context_builder=context_builder,
)