mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-11-02 13:28:32 +08:00
refactor(startup): move domain assembly to composition
This commit is contained in:
43
app/startup/composition/domain.py
Normal file
43
app/startup/composition/domain.py
Normal file
@@ -0,0 +1,43 @@
|
||||
"""领域规则、解析运行时与技术端口的宿主组合 owner。"""
|
||||
|
||||
from app.adapters.network.resolver import SocketDnsResolver
|
||||
from app.adapters.system import rust as rust_accelerator
|
||||
from app.adapters.system.host import SystemUtils
|
||||
from app.application.directory import configure_disk_topology
|
||||
from app.application.recognition import RecognitionRuleService
|
||||
from app.application.rules import configure_filter_rule_parser
|
||||
from app.application.security.url import configure_dns_resolver
|
||||
from app.application.transfer.workflow import configure_directory_size
|
||||
from app.domain.media import configure_search_source_provider
|
||||
from app.domain.meta.customization import configure_customization_provider
|
||||
from app.domain.meta.releasegroup import configure_release_groups_provider
|
||||
from app.domain.meta.runtime import configure_recognition_runtime
|
||||
from app.domain.meta.words import configure_custom_words_provider
|
||||
from app.domain.metainfo import clear_rust_parse_options_cache
|
||||
from app.runtime.settings import get_runtime_setting
|
||||
|
||||
|
||||
def compose_domain_dependencies() -> None:
|
||||
"""构造并发布领域模型使用的规则、配置和技术 Adapter。"""
|
||||
from app.domain.projection.tmdb import configure_image_url_builder
|
||||
|
||||
rule_service = RecognitionRuleService()
|
||||
configure_dns_resolver(SocketDnsResolver())
|
||||
configure_disk_topology(SystemUtils)
|
||||
configure_filter_rule_parser(rust_accelerator)
|
||||
configure_directory_size(SystemUtils)
|
||||
configure_customization_provider(rule_service.get_customization)
|
||||
configure_release_groups_provider(rule_service.get_release_groups)
|
||||
configure_custom_words_provider(rule_service.get_custom_words)
|
||||
configure_search_source_provider(lambda: get_runtime_setting("SEARCH_SOURCE"))
|
||||
configure_image_url_builder(get_runtime_setting("TMDB_IMAGE_URL"))
|
||||
configure_recognition_runtime(
|
||||
media_extensions_provider=lambda: (
|
||||
*get_runtime_setting("RMT_MEDIAEXT"),
|
||||
*get_runtime_setting("RMT_SUBEXT"),
|
||||
*get_runtime_setting("RMT_AUDIOEXT"),
|
||||
),
|
||||
audio_extensions_provider=lambda: get_runtime_setting("RMT_AUDIOEXT"),
|
||||
accelerator=rust_accelerator,
|
||||
)
|
||||
clear_rust_parse_options_cache()
|
||||
@@ -1,41 +1,8 @@
|
||||
from app.adapters.network.resolver import SocketDnsResolver
|
||||
from app.adapters.system import rust as rust_accelerator
|
||||
from app.adapters.system.host import SystemUtils
|
||||
from app.application.directory import configure_disk_topology
|
||||
from app.application.recognition import RecognitionRuleService
|
||||
from app.application.rules import configure_filter_rule_parser
|
||||
from app.application.security.url import configure_dns_resolver
|
||||
from app.application.transfer.workflow import configure_directory_size
|
||||
from app.domain.media import configure_search_source_provider
|
||||
from app.domain.meta.customization import configure_customization_provider
|
||||
from app.domain.meta.releasegroup import configure_release_groups_provider
|
||||
from app.domain.meta.runtime import configure_recognition_runtime
|
||||
from app.domain.meta.words import configure_custom_words_provider
|
||||
from app.domain.metainfo import clear_rust_parse_options_cache
|
||||
from app.runtime.settings import get_runtime_setting
|
||||
"""领域依赖生命周期入口。"""
|
||||
|
||||
from app.startup.composition.domain import compose_domain_dependencies
|
||||
|
||||
|
||||
def configure_domain_dependencies() -> None:
|
||||
"""在组合根集中注入领域模型需要的配置、持久化规则和加速适配器。"""
|
||||
from app.domain.projection.tmdb import configure_image_url_builder
|
||||
|
||||
rule_service = RecognitionRuleService()
|
||||
configure_dns_resolver(SocketDnsResolver())
|
||||
configure_disk_topology(SystemUtils)
|
||||
configure_filter_rule_parser(rust_accelerator)
|
||||
configure_directory_size(SystemUtils)
|
||||
configure_customization_provider(rule_service.get_customization)
|
||||
configure_release_groups_provider(rule_service.get_release_groups)
|
||||
configure_custom_words_provider(rule_service.get_custom_words)
|
||||
configure_search_source_provider(lambda: get_runtime_setting('SEARCH_SOURCE'))
|
||||
configure_image_url_builder(get_runtime_setting('TMDB_IMAGE_URL'))
|
||||
configure_recognition_runtime(
|
||||
media_extensions_provider=lambda: (
|
||||
*get_runtime_setting('RMT_MEDIAEXT'),
|
||||
*get_runtime_setting('RMT_SUBEXT'),
|
||||
*get_runtime_setting('RMT_AUDIOEXT'),
|
||||
),
|
||||
audio_extensions_provider=lambda: get_runtime_setting('RMT_AUDIOEXT'),
|
||||
accelerator=rust_accelerator,
|
||||
)
|
||||
clear_rust_parse_options_cache()
|
||||
"""按生命周期顺序调用领域组合 owner。"""
|
||||
compose_domain_dependencies()
|
||||
|
||||
@@ -157,8 +157,12 @@ access provider assembly; it returns the persistence factories needed by the run
|
||||
owner, which alone constructs `AuthenticationRuntime`.
|
||||
`startup/composition/network.py` owns concrete network-test, image, internal-address
|
||||
and message-ingress Adapter wiring
|
||||
while retaining lazy RuntimeSettings reads. Initializers call these owners in
|
||||
startup order and must not recreate their concrete construction.
|
||||
while retaining lazy RuntimeSettings reads. Initializers call these owners in
|
||||
startup order and must not recreate their concrete construction.
|
||||
`startup/composition/domain.py` owns DNS/System/Rust Adapter assembly together
|
||||
with the single `RecognitionRuleService` used to publish media-recognition rule
|
||||
providers. `initializers/domain.py` is only the lifecycle hook and must not
|
||||
construct a parallel rule service or import concrete adapters.
|
||||
`startup/composition/outbox.py`
|
||||
owns durable handler validation, lazy event/notification replay binding and the
|
||||
short-transaction dispatcher factory. Initializers call this owner in
|
||||
|
||||
@@ -2428,6 +2428,41 @@ def test_plugin_market_transport_is_process_shared_across_compat_and_composition
|
||||
assert PluginMarketTransport.get_existing_instance() is _plugin_market_transport
|
||||
|
||||
|
||||
def test_domain_initializer_delegates_construction_to_composition():
|
||||
"""领域 initializer 只负责生命周期调用,不得直接构造 Adapter 或领域服务。"""
|
||||
initializer_path = APP_ROOT / "startup" / "initializers" / "domain.py"
|
||||
initializer_tree = ast.parse(
|
||||
initializer_path.read_text(encoding="utf-8-sig"),
|
||||
filename=str(initializer_path),
|
||||
)
|
||||
imported_modules = {
|
||||
node.module
|
||||
for node in ast.walk(initializer_tree)
|
||||
if isinstance(node, ast.ImportFrom) and node.module
|
||||
}
|
||||
assert imported_modules == {"app.startup.composition.domain"}
|
||||
calls = [
|
||||
ast.unparse(node.func)
|
||||
for node in ast.walk(initializer_tree)
|
||||
if isinstance(node, ast.Call)
|
||||
]
|
||||
assert calls == ["compose_domain_dependencies"]
|
||||
|
||||
composition_path = APP_ROOT / "startup" / "composition" / "domain.py"
|
||||
composition_tree = ast.parse(
|
||||
composition_path.read_text(encoding="utf-8-sig"),
|
||||
filename=str(composition_path),
|
||||
)
|
||||
composition_imports = {
|
||||
node.module
|
||||
for node in ast.walk(composition_tree)
|
||||
if isinstance(node, ast.ImportFrom) and node.module
|
||||
}
|
||||
assert "app.adapters.network.resolver" in composition_imports
|
||||
assert "app.adapters.system.host" in composition_imports
|
||||
assert "app.application.recognition" in composition_imports
|
||||
|
||||
|
||||
PROCESS_LEVEL_ROOTS = (
|
||||
"app.api",
|
||||
"app.chain",
|
||||
|
||||
Reference in New Issue
Block a user