"""infrastructure/container.py:use_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_callback:ToolExecutor 需 # 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. 请求级 ContextBuilder(ToolExecutor 系统级路径依赖它构造 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, )