mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-04 23:17:20 +08:00
refactor: 推进后端分层架构治理
This commit is contained in:
@@ -19,7 +19,7 @@ from app.adapters.system.host import SystemUtils
|
||||
from app.runtime.log import logger
|
||||
from app.runtime.config import settings
|
||||
from app.runtime.extensions.module_manager import ModuleManager
|
||||
from app.runtime.events import EventManager
|
||||
from app.runtime.events import EventHandlerBinding, EventManager
|
||||
from app.runtime.state import SystemHelper
|
||||
from app.runtime.thread import ThreadHelper
|
||||
from app.adapters.network.doh import DohHelper
|
||||
@@ -28,11 +28,19 @@ from app.adapters.system.resource import (
|
||||
configure_resource_version_provider,
|
||||
)
|
||||
from app.application.messaging.message import MessageHelper, stop_message
|
||||
from app.adapters.external.server import MoviePilotServerHelper
|
||||
from app.adapters.external.server import (
|
||||
MoviePilotServerHelper,
|
||||
configure_server_application_services,
|
||||
)
|
||||
from app.application.server.report import ServerReportService
|
||||
from app.application.server.share import ServerSharingService
|
||||
from app.db import close_database
|
||||
from app.db.oper.subscribe import SubscribeOper
|
||||
from app.db.oper.systemconfig import SystemConfigOper
|
||||
from app.db.oper.workflow import WorkflowOper
|
||||
from app.command import CommandChain
|
||||
from app.schemas import Message, MessageType
|
||||
from app.schemas.message import Message
|
||||
from app.schemas.message import MessageType
|
||||
from app.schemas.types import SystemConfigKey
|
||||
from app.startup.agent_initializer import init_agent, stop_agent
|
||||
from app.startup.managed_resources_initializer import (
|
||||
@@ -42,6 +50,62 @@ from app.startup.managed_resources_initializer import (
|
||||
from app.application.security.access import set_superuser_token_payload_provider
|
||||
from app.application.security.auth import build_superuser_token_payload
|
||||
from app.application.image import configure_wallpaper_providers
|
||||
from app.application.chain.context import (
|
||||
build_default_chain_runtime_context,
|
||||
configure_chain_runtime_context_provider,
|
||||
)
|
||||
from app.runtime.extensions.service_config import configure_service_config_reader
|
||||
|
||||
|
||||
async def _async_get_subscribe(subscribe_id: int):
|
||||
"""通过数据库操作器异步读取订阅,供服务端共享用例使用。"""
|
||||
return await SubscribeOper().async_get(subscribe_id)
|
||||
|
||||
|
||||
async def _async_get_workflow(workflow_id: int):
|
||||
"""通过数据库操作器异步读取工作流,供服务端共享用例使用。"""
|
||||
return await WorkflowOper().async_get(workflow_id)
|
||||
|
||||
|
||||
def configure_runtime_data_providers() -> None:
|
||||
"""在启动组合层装配运行时和外部服务所需的数据库读取能力。"""
|
||||
configure_service_config_reader(lambda key: SystemConfigOper().get(key))
|
||||
configure_server_application_services(
|
||||
report_service=ServerReportService(
|
||||
config_reader=lambda key: SystemConfigOper().get(key),
|
||||
config_writer=lambda key, value: SystemConfigOper().set(key, value),
|
||||
installed_plugins_provider=lambda: SystemConfigOper().get(
|
||||
SystemConfigKey.UserInstalledPlugins
|
||||
) or [],
|
||||
subscribes_provider=lambda: SubscribeOper().list(),
|
||||
plugin_report_sender=MoviePilotServerHelper.plugin_install_report,
|
||||
async_plugin_report_sender=(
|
||||
MoviePilotServerHelper.async_plugin_install_report
|
||||
),
|
||||
subscribe_report_sender=MoviePilotServerHelper.subscribe_report,
|
||||
repo_url_sanitizer=MoviePilotServerHelper.sanitize_plugin_repo_url,
|
||||
),
|
||||
sharing_service=ServerSharingService(
|
||||
subscribe_provider=lambda subscribe_id: SubscribeOper().get(
|
||||
subscribe_id
|
||||
),
|
||||
async_subscribe_provider=_async_get_subscribe,
|
||||
workflow_provider=lambda workflow_id: WorkflowOper().get(workflow_id),
|
||||
async_workflow_provider=_async_get_workflow,
|
||||
user_uuid_provider=MoviePilotServerHelper.get_user_uuid,
|
||||
subscribe_sender=MoviePilotServerHelper.subscribe_share,
|
||||
async_subscribe_sender=MoviePilotServerHelper.async_subscribe_share,
|
||||
workflow_sender=MoviePilotServerHelper.workflow_share,
|
||||
async_workflow_sender=MoviePilotServerHelper.async_workflow_share,
|
||||
response_handler=MoviePilotServerHelper._handle_response,
|
||||
subscribe_cache_clearer=(
|
||||
MoviePilotServerHelper._clear_subscribe_share_cache
|
||||
),
|
||||
workflow_cache_clearer=(
|
||||
MoviePilotServerHelper._clear_workflow_share_cache
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def configure_wallpaper_services() -> None:
|
||||
@@ -65,6 +129,50 @@ def notify_event_error(title: str, message: str) -> None:
|
||||
)
|
||||
|
||||
|
||||
def get_host_event_handler_factories() -> dict[type, Callable[[], object]]:
|
||||
"""返回所有使用事件装饰器的宿主类及其明确实例工厂。"""
|
||||
from app.chain.download import DownloadChain
|
||||
from app.chain.scraping import ScrapingChain
|
||||
from app.chain.search import SearchChain
|
||||
from app.chain.site import SiteChain
|
||||
from app.chain.subscribe import SubscribeChain
|
||||
from app.chain.workflow import WorkflowChain
|
||||
from app.command import Command
|
||||
from app.scheduler import Scheduler
|
||||
|
||||
return {
|
||||
Command: Command,
|
||||
DownloadChain: DownloadChain,
|
||||
Scheduler: Scheduler,
|
||||
ScrapingChain: ScrapingChain,
|
||||
SearchChain: SearchChain,
|
||||
SiteChain: SiteChain,
|
||||
SubscribeChain: SubscribeChain,
|
||||
WorkflowChain: WorkflowChain,
|
||||
}
|
||||
|
||||
|
||||
def configure_host_event_handler_resolver() -> None:
|
||||
"""显式登记宿主内置类处理器,禁止事件总线按类名临时构造未知对象。"""
|
||||
factories = get_host_event_handler_factories()
|
||||
|
||||
def resolve(owner_class: type) -> EventHandlerBinding | None:
|
||||
"""按明确白名单复用单例或构造与旧路径等价的 Chain 实例。"""
|
||||
factory = factories.get(owner_class)
|
||||
if factory is None:
|
||||
return None
|
||||
get_existing = getattr(owner_class, "get_existing_instance", None)
|
||||
instance = get_existing() if callable(get_existing) else None
|
||||
if instance is None:
|
||||
instance = factory()
|
||||
return EventHandlerBinding(
|
||||
instance=instance,
|
||||
owner_name=owner_class.__name__,
|
||||
)
|
||||
|
||||
EventManager().register_handler_instance_resolver("host", resolve)
|
||||
|
||||
|
||||
def start_frontend():
|
||||
"""
|
||||
启动前端服务
|
||||
@@ -212,10 +320,14 @@ async def init_modules():
|
||||
"""
|
||||
启动模块
|
||||
"""
|
||||
# 数据访问能力统一在启动组合根注入,Runtime 和 Adapter 不再直接依赖 Oper。
|
||||
configure_runtime_data_providers()
|
||||
# 托管资源只在这里装配声明与 adapter,具体资源仍由首个消费者显式激活。
|
||||
init_managed_resources()
|
||||
# 应用服务不反向依赖 Chain,由启动组合层注入壁纸来源。
|
||||
configure_wallpaper_services()
|
||||
# Chain 无参兼容入口由组合根明确提供依赖上下文;测试和新代码可直接注入替代上下文。
|
||||
configure_chain_runtime_context_provider(build_default_chain_runtime_context)
|
||||
# 认证访问层不反向依赖数据库实现,由启动组合层注入载荷提供器。
|
||||
set_superuser_token_payload_provider(build_superuser_token_payload)
|
||||
# DoH
|
||||
@@ -228,6 +340,8 @@ async def init_modules():
|
||||
user_auth()
|
||||
# 事件错误通知由启动组合层接入消息服务。
|
||||
EventManager().set_error_notifier(notify_event_error)
|
||||
# 宿主类处理器在启动层显式登记,事件总线不再兜底 owner_class()。
|
||||
configure_host_event_handler_resolver()
|
||||
# 加载模块
|
||||
ModuleManager()
|
||||
# 启动事件消费
|
||||
|
||||
Reference in New Issue
Block a user