新增六边形架构核心代码包,包含: 1. 协议适配器层:HTTP/SMTP/IMAP/SSH/GRPC等多协议适配器实现 2. 认证插件体系:基础认证、API密钥、HMAC等多类型认证插件 3. 执行编排框架:工具执行器、上下文构建、运行时治理组件 4. 用例端口与DTO:定义领域服务端口与数据传输对象 5. 厂商集成包框架:支持第三方系统集成扩展 6. 基础设施装配层:实现依赖注入与服务装配 所有代码遵循六边形架构设计原则,实现端口与适配器解耦,支持动态扩展与自动发现。
345 lines
14 KiB
Python
345 lines
14 KiB
Python
"""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,
|
||
)
|