From 39b7df2ce0f344d9acfca8ff11084cd09e17cf94 Mon Sep 17 00:00:00 2001 From: Kris <2893855659@qq.com> Date: Sun, 31 May 2026 17:38:33 +0800 Subject: [PATCH] =?UTF-8?q?refactor(channel-domain):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E7=AB=AF=E5=8F=A3=E5=AE=9A=E4=B9=89=E4=B8=8E=E5=AF=BC=E5=85=A5?= =?UTF-8?q?=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 新增多个领域端口协议类,包括签名验证、路由贡献、关键词匹配等完整的端口定义 2. 重构ChannelRouteContributor重命名为ChannelRouteContributorPort并统一导入路径 3. 调整端口目录结构,拆分external和internal子目录并分别导出 4. 更新所有引用了旧端口定义的业务代码和测试用例 --- .../yuxi/channel/channels/feishu/adapter.py | 4 +- .../yuxi/channel/channels/hooks/adapter.py | 4 +- .../yuxi/channel/channels/web/adapter.py | 4 +- .../package/yuxi/channel/domain/__init__.py | 2 +- .../yuxi/channel/domain/port/__init__.py | 38 +++++++++++-------- .../channel/domain/port/external/__init__.py | 4 ++ .../{ => external}/channel_adapter_port.py | 0 .../channel_route_contributor_port.py} | 2 +- .../{ => external}/signature_verify_port.py | 0 .../port/{ => external}/ws_connection_port.py | 0 .../channel/domain/port/internal/__init__.py | 12 ++++++ .../domain/port/{ => internal}/agent_port.py | 0 .../{ => internal}/bot_loop_guard_port.py | 0 .../domain/port/{ => internal}/cache_port.py | 0 .../{ => internal}/circuit_breaker_port.py | 0 .../port/{ => internal}/config_reload_port.py | 0 .../{ => internal}/content_filter_port.py | 0 .../{ => internal}/event_publisher_port.py | 0 .../{ => internal}/keyword_matcher_port.py | 0 .../port/{ => internal}/metrics_port.py | 0 .../domain/port/{ => internal}/queue_port.py | 0 .../port/{ => internal}/rate_limit_port.py | 0 .../port/{ => internal}/sse_push_port.py | 0 .../interfaces/rest/router/registry.py | 6 +-- .../port/test_channel_route_contributor.py | 8 ++-- .../interfaces/rest/router/test_registry.py | 2 +- 26 files changed, 54 insertions(+), 32 deletions(-) create mode 100644 backend/package/yuxi/channel/domain/port/external/__init__.py rename backend/package/yuxi/channel/domain/port/{ => external}/channel_adapter_port.py (100%) rename backend/package/yuxi/channel/domain/port/{channel_route_contributor.py => external/channel_route_contributor_port.py} (77%) rename backend/package/yuxi/channel/domain/port/{ => external}/signature_verify_port.py (100%) rename backend/package/yuxi/channel/domain/port/{ => external}/ws_connection_port.py (100%) create mode 100644 backend/package/yuxi/channel/domain/port/internal/__init__.py rename backend/package/yuxi/channel/domain/port/{ => internal}/agent_port.py (100%) rename backend/package/yuxi/channel/domain/port/{ => internal}/bot_loop_guard_port.py (100%) rename backend/package/yuxi/channel/domain/port/{ => internal}/cache_port.py (100%) rename backend/package/yuxi/channel/domain/port/{ => internal}/circuit_breaker_port.py (100%) rename backend/package/yuxi/channel/domain/port/{ => internal}/config_reload_port.py (100%) rename backend/package/yuxi/channel/domain/port/{ => internal}/content_filter_port.py (100%) rename backend/package/yuxi/channel/domain/port/{ => internal}/event_publisher_port.py (100%) rename backend/package/yuxi/channel/domain/port/{ => internal}/keyword_matcher_port.py (100%) rename backend/package/yuxi/channel/domain/port/{ => internal}/metrics_port.py (100%) rename backend/package/yuxi/channel/domain/port/{ => internal}/queue_port.py (100%) rename backend/package/yuxi/channel/domain/port/{ => internal}/rate_limit_port.py (100%) rename backend/package/yuxi/channel/domain/port/{ => internal}/sse_push_port.py (100%) diff --git a/backend/package/yuxi/channel/channels/feishu/adapter.py b/backend/package/yuxi/channel/channels/feishu/adapter.py index 2ef3da1a..6af9e688 100644 --- a/backend/package/yuxi/channel/channels/feishu/adapter.py +++ b/backend/package/yuxi/channel/channels/feishu/adapter.py @@ -9,7 +9,7 @@ from yuxi.channel.domain.model.message.dispatch_result import SendResult from yuxi.channel.domain.model.message.unified_message import UnifiedMessage from yuxi.channel.domain.model.shared.channel_capabilities import ChannelCapabilities from yuxi.channel.domain.model.shared.channel_type import ChannelType -from yuxi.channel.domain.port.channel_route_contributor import ChannelRouteContributor +from yuxi.channel.domain.port.channel_route_contributor_port import ChannelRouteContributorPort from yuxi.channel.domain.port.ws_connection_port import WsConnectionPort logger = logging.getLogger(__name__) @@ -57,7 +57,7 @@ class FeishuAdapter: return self._ws @property - def route_contributor(self) -> ChannelRouteContributor | None: + def route_contributor(self) -> ChannelRouteContributorPort | None: return _FeishuRouteContributor() @classmethod diff --git a/backend/package/yuxi/channel/channels/hooks/adapter.py b/backend/package/yuxi/channel/channels/hooks/adapter.py index 7c19b998..4ec35486 100644 --- a/backend/package/yuxi/channel/channels/hooks/adapter.py +++ b/backend/package/yuxi/channel/channels/hooks/adapter.py @@ -8,7 +8,7 @@ from yuxi.channel.domain.model.message.dispatch_result import SendResult from yuxi.channel.domain.model.message.unified_message import UnifiedMessage from yuxi.channel.domain.model.shared.channel_capabilities import ChannelCapabilities from yuxi.channel.domain.model.shared.channel_type import ChannelType -from yuxi.channel.domain.port.channel_route_contributor import ChannelRouteContributor +from yuxi.channel.domain.port.channel_route_contributor_port import ChannelRouteContributorPort from yuxi.channel.domain.port.ws_connection_port import WsConnectionPort logger = logging.getLogger(__name__) @@ -55,7 +55,7 @@ class HooksAdapter: return None @property - def route_contributor(self) -> ChannelRouteContributor | None: + def route_contributor(self) -> ChannelRouteContributorPort | None: return _HooksRouteContributor() @classmethod diff --git a/backend/package/yuxi/channel/channels/web/adapter.py b/backend/package/yuxi/channel/channels/web/adapter.py index 8c4ff893..98c4a7a5 100644 --- a/backend/package/yuxi/channel/channels/web/adapter.py +++ b/backend/package/yuxi/channel/channels/web/adapter.py @@ -8,7 +8,7 @@ from yuxi.channel.domain.model.message.dispatch_result import SendResult from yuxi.channel.domain.model.message.unified_message import UnifiedMessage from yuxi.channel.domain.model.shared.channel_capabilities import ChannelCapabilities from yuxi.channel.domain.model.shared.channel_type import ChannelType -from yuxi.channel.domain.port.channel_route_contributor import ChannelRouteContributor +from yuxi.channel.domain.port.channel_route_contributor_port import ChannelRouteContributorPort from yuxi.channel.domain.port.sse_push_port import SsePushPort from yuxi.channel.domain.port.ws_connection_port import WsConnectionPort @@ -41,7 +41,7 @@ class WebAdapter: return None @property - def route_contributor(self) -> ChannelRouteContributor | None: + def route_contributor(self) -> ChannelRouteContributorPort | None: return _WebRouteContributor() @classmethod diff --git a/backend/package/yuxi/channel/domain/__init__.py b/backend/package/yuxi/channel/domain/__init__.py index 99ccb035..15402bf3 100644 --- a/backend/package/yuxi/channel/domain/__init__.py +++ b/backend/package/yuxi/channel/domain/__init__.py @@ -29,7 +29,7 @@ _LAZY_IMPORTS = { "KeywordMatcherPort": "yuxi.channel.domain.port", "CachePort": "yuxi.channel.domain.port", "ChannelAdapterPort": "yuxi.channel.domain.port", - "ChannelRouteContributor": "yuxi.channel.domain.port", + "ChannelRouteContributorPort": "yuxi.channel.domain.port", "CircuitBreakerPort": "yuxi.channel.domain.port", "ConfigReloadPort": "yuxi.channel.domain.port", "ContentFilterPort": "yuxi.channel.domain.port", diff --git a/backend/package/yuxi/channel/domain/port/__init__.py b/backend/package/yuxi/channel/domain/port/__init__.py index 6cda5250..5791b631 100644 --- a/backend/package/yuxi/channel/domain/port/__init__.py +++ b/backend/package/yuxi/channel/domain/port/__init__.py @@ -1,16 +1,22 @@ -from yuxi.channel.domain.port.agent_port import AgentPort -from yuxi.channel.domain.port.bot_loop_guard_port import BotLoopGuardPort -from yuxi.channel.domain.port.cache_port import CachePort -from yuxi.channel.domain.port.channel_adapter_port import ChannelAdapterPort -from yuxi.channel.domain.port.channel_route_contributor import ChannelRouteContributor -from yuxi.channel.domain.port.circuit_breaker_port import CircuitBreakerPort -from yuxi.channel.domain.port.config_reload_port import ConfigReloadPort -from yuxi.channel.domain.port.content_filter_port import ContentFilterPort, FilterResult -from yuxi.channel.domain.port.event_publisher_port import DomainEvent, EventPublisherPort -from yuxi.channel.domain.port.keyword_matcher_port import KeywordMatcherPort -from yuxi.channel.domain.port.metrics_port import MetricsPort -from yuxi.channel.domain.port.queue_port import QueuePort -from yuxi.channel.domain.port.rate_limit_port import RateLimitPort -from yuxi.channel.domain.port.signature_verify_port import SignatureVerifyPort -from yuxi.channel.domain.port.sse_push_port import SsePushPort -from yuxi.channel.domain.port.ws_connection_port import WsConnectionPort +from yuxi.channel.domain.port.external import ( + ChannelAdapterPort, + ChannelRouteContributorPort, + SignatureVerifyPort, + WsConnectionPort, +) +from yuxi.channel.domain.port.internal import ( + AgentPort, + BotLoopGuardPort, + CachePort, + CircuitBreakerPort, + ConfigReloadPort, + ContentFilterPort, + DomainEvent, + EventPublisherPort, + FilterResult, + KeywordMatcherPort, + MetricsPort, + QueuePort, + RateLimitPort, + SsePushPort, +) diff --git a/backend/package/yuxi/channel/domain/port/external/__init__.py b/backend/package/yuxi/channel/domain/port/external/__init__.py new file mode 100644 index 00000000..8e7bf7a8 --- /dev/null +++ b/backend/package/yuxi/channel/domain/port/external/__init__.py @@ -0,0 +1,4 @@ +from yuxi.channel.domain.port.external.channel_adapter_port import ChannelAdapterPort +from yuxi.channel.domain.port.external.channel_route_contributor_port import ChannelRouteContributorPort +from yuxi.channel.domain.port.external.signature_verify_port import SignatureVerifyPort +from yuxi.channel.domain.port.external.ws_connection_port import WsConnectionPort diff --git a/backend/package/yuxi/channel/domain/port/channel_adapter_port.py b/backend/package/yuxi/channel/domain/port/external/channel_adapter_port.py similarity index 100% rename from backend/package/yuxi/channel/domain/port/channel_adapter_port.py rename to backend/package/yuxi/channel/domain/port/external/channel_adapter_port.py diff --git a/backend/package/yuxi/channel/domain/port/channel_route_contributor.py b/backend/package/yuxi/channel/domain/port/external/channel_route_contributor_port.py similarity index 77% rename from backend/package/yuxi/channel/domain/port/channel_route_contributor.py rename to backend/package/yuxi/channel/domain/port/external/channel_route_contributor_port.py index e571d371..22d9b318 100644 --- a/backend/package/yuxi/channel/domain/port/channel_route_contributor.py +++ b/backend/package/yuxi/channel/domain/port/external/channel_route_contributor_port.py @@ -4,6 +4,6 @@ from typing import Protocol, runtime_checkable @runtime_checkable -class ChannelRouteContributor(Protocol): +class ChannelRouteContributorPort(Protocol): @property def router(self) -> object: ... diff --git a/backend/package/yuxi/channel/domain/port/signature_verify_port.py b/backend/package/yuxi/channel/domain/port/external/signature_verify_port.py similarity index 100% rename from backend/package/yuxi/channel/domain/port/signature_verify_port.py rename to backend/package/yuxi/channel/domain/port/external/signature_verify_port.py diff --git a/backend/package/yuxi/channel/domain/port/ws_connection_port.py b/backend/package/yuxi/channel/domain/port/external/ws_connection_port.py similarity index 100% rename from backend/package/yuxi/channel/domain/port/ws_connection_port.py rename to backend/package/yuxi/channel/domain/port/external/ws_connection_port.py diff --git a/backend/package/yuxi/channel/domain/port/internal/__init__.py b/backend/package/yuxi/channel/domain/port/internal/__init__.py new file mode 100644 index 00000000..65670905 --- /dev/null +++ b/backend/package/yuxi/channel/domain/port/internal/__init__.py @@ -0,0 +1,12 @@ +from yuxi.channel.domain.port.internal.agent_port import AgentPort +from yuxi.channel.domain.port.internal.bot_loop_guard_port import BotLoopGuardPort +from yuxi.channel.domain.port.internal.cache_port import CachePort +from yuxi.channel.domain.port.internal.circuit_breaker_port import CircuitBreakerPort +from yuxi.channel.domain.port.internal.config_reload_port import ConfigReloadPort +from yuxi.channel.domain.port.internal.content_filter_port import ContentFilterPort, FilterResult +from yuxi.channel.domain.port.internal.event_publisher_port import DomainEvent, EventPublisherPort +from yuxi.channel.domain.port.internal.keyword_matcher_port import KeywordMatcherPort +from yuxi.channel.domain.port.internal.metrics_port import MetricsPort +from yuxi.channel.domain.port.internal.queue_port import QueuePort +from yuxi.channel.domain.port.internal.rate_limit_port import RateLimitPort +from yuxi.channel.domain.port.internal.sse_push_port import SsePushPort diff --git a/backend/package/yuxi/channel/domain/port/agent_port.py b/backend/package/yuxi/channel/domain/port/internal/agent_port.py similarity index 100% rename from backend/package/yuxi/channel/domain/port/agent_port.py rename to backend/package/yuxi/channel/domain/port/internal/agent_port.py diff --git a/backend/package/yuxi/channel/domain/port/bot_loop_guard_port.py b/backend/package/yuxi/channel/domain/port/internal/bot_loop_guard_port.py similarity index 100% rename from backend/package/yuxi/channel/domain/port/bot_loop_guard_port.py rename to backend/package/yuxi/channel/domain/port/internal/bot_loop_guard_port.py diff --git a/backend/package/yuxi/channel/domain/port/cache_port.py b/backend/package/yuxi/channel/domain/port/internal/cache_port.py similarity index 100% rename from backend/package/yuxi/channel/domain/port/cache_port.py rename to backend/package/yuxi/channel/domain/port/internal/cache_port.py diff --git a/backend/package/yuxi/channel/domain/port/circuit_breaker_port.py b/backend/package/yuxi/channel/domain/port/internal/circuit_breaker_port.py similarity index 100% rename from backend/package/yuxi/channel/domain/port/circuit_breaker_port.py rename to backend/package/yuxi/channel/domain/port/internal/circuit_breaker_port.py diff --git a/backend/package/yuxi/channel/domain/port/config_reload_port.py b/backend/package/yuxi/channel/domain/port/internal/config_reload_port.py similarity index 100% rename from backend/package/yuxi/channel/domain/port/config_reload_port.py rename to backend/package/yuxi/channel/domain/port/internal/config_reload_port.py diff --git a/backend/package/yuxi/channel/domain/port/content_filter_port.py b/backend/package/yuxi/channel/domain/port/internal/content_filter_port.py similarity index 100% rename from backend/package/yuxi/channel/domain/port/content_filter_port.py rename to backend/package/yuxi/channel/domain/port/internal/content_filter_port.py diff --git a/backend/package/yuxi/channel/domain/port/event_publisher_port.py b/backend/package/yuxi/channel/domain/port/internal/event_publisher_port.py similarity index 100% rename from backend/package/yuxi/channel/domain/port/event_publisher_port.py rename to backend/package/yuxi/channel/domain/port/internal/event_publisher_port.py diff --git a/backend/package/yuxi/channel/domain/port/keyword_matcher_port.py b/backend/package/yuxi/channel/domain/port/internal/keyword_matcher_port.py similarity index 100% rename from backend/package/yuxi/channel/domain/port/keyword_matcher_port.py rename to backend/package/yuxi/channel/domain/port/internal/keyword_matcher_port.py diff --git a/backend/package/yuxi/channel/domain/port/metrics_port.py b/backend/package/yuxi/channel/domain/port/internal/metrics_port.py similarity index 100% rename from backend/package/yuxi/channel/domain/port/metrics_port.py rename to backend/package/yuxi/channel/domain/port/internal/metrics_port.py diff --git a/backend/package/yuxi/channel/domain/port/queue_port.py b/backend/package/yuxi/channel/domain/port/internal/queue_port.py similarity index 100% rename from backend/package/yuxi/channel/domain/port/queue_port.py rename to backend/package/yuxi/channel/domain/port/internal/queue_port.py diff --git a/backend/package/yuxi/channel/domain/port/rate_limit_port.py b/backend/package/yuxi/channel/domain/port/internal/rate_limit_port.py similarity index 100% rename from backend/package/yuxi/channel/domain/port/rate_limit_port.py rename to backend/package/yuxi/channel/domain/port/internal/rate_limit_port.py diff --git a/backend/package/yuxi/channel/domain/port/sse_push_port.py b/backend/package/yuxi/channel/domain/port/internal/sse_push_port.py similarity index 100% rename from backend/package/yuxi/channel/domain/port/sse_push_port.py rename to backend/package/yuxi/channel/domain/port/internal/sse_push_port.py diff --git a/backend/package/yuxi/channel/interfaces/rest/router/registry.py b/backend/package/yuxi/channel/interfaces/rest/router/registry.py index 13c3c03f..36290a83 100644 --- a/backend/package/yuxi/channel/interfaces/rest/router/registry.py +++ b/backend/package/yuxi/channel/interfaces/rest/router/registry.py @@ -5,7 +5,7 @@ import logging from fastapi import FastAPI from yuxi.channel.domain.port.channel_adapter_port import ChannelAdapterPort -from yuxi.channel.domain.port.channel_route_contributor import ChannelRouteContributor +from yuxi.channel.domain.port.channel_route_contributor_port import ChannelRouteContributorPort logger = logging.getLogger(__name__) @@ -30,11 +30,11 @@ def register_all_channel_routes( return registered -def _get_route_contributor(adapter: ChannelAdapterPort) -> ChannelRouteContributor | None: +def _get_route_contributor(adapter: ChannelAdapterPort) -> ChannelRouteContributorPort | None: contributor = getattr(adapter, "route_contributor", None) if contributor is None: return None - if isinstance(contributor, ChannelRouteContributor): + if isinstance(contributor, ChannelRouteContributorPort): return contributor if hasattr(contributor, "router"): return contributor diff --git a/backend/test/unit/channel/domain/port/test_channel_route_contributor.py b/backend/test/unit/channel/domain/port/test_channel_route_contributor.py index 13caf35f..2d1208cf 100644 --- a/backend/test/unit/channel/domain/port/test_channel_route_contributor.py +++ b/backend/test/unit/channel/domain/port/test_channel_route_contributor.py @@ -1,10 +1,10 @@ from __future__ import annotations -from yuxi.channel.domain.port.channel_route_contributor import ChannelRouteContributor +from yuxi.channel.domain.port.channel_route_contributor_port import ChannelRouteContributorPort -def test_channel_route_contributor_is_protocol() -> None: - assert hasattr(ChannelRouteContributor, "router") +def test_channel_route_contributor_port_is_protocol() -> None: + assert hasattr(ChannelRouteContributorPort, "router") class _FakeContributor: @@ -15,4 +15,4 @@ class _FakeContributor: def test_fake_contributor_is_instance() -> None: obj = _FakeContributor() - assert isinstance(obj, ChannelRouteContributor) + assert isinstance(obj, ChannelRouteContributorPort) diff --git a/backend/test/unit/channel/interfaces/rest/router/test_registry.py b/backend/test/unit/channel/interfaces/rest/router/test_registry.py index b198d310..29fb703f 100644 --- a/backend/test/unit/channel/interfaces/rest/router/test_registry.py +++ b/backend/test/unit/channel/interfaces/rest/router/test_registry.py @@ -4,7 +4,7 @@ import pytest from fastapi import FastAPI, APIRouter from yuxi.channel.interfaces.rest.router.registry import register_all_channel_routes, _get_route_contributor -from yuxi.channel.domain.port.channel_route_contributor import ChannelRouteContributor +from yuxi.channel.domain.port.channel_route_contributor_port import ChannelRouteContributorPort class _FakeContributor: