Files
MoviePilot/app/startup/composition/plugin.py
jxxghp b663825fe7 fix(plugin): recover dependencies without disabled constraints
Keep enabled host and clone sources in dependency recovery. Fall back to per-plugin requests while retaining ready and recovered manifest constraints, preserving original sources and cancellation ownership.

Refs #6943
2026-10-10 12:20:13 +08:00

76 lines
2.5 KiB
Python

"""插件市场技术依赖的唯一启动组合 owner。"""
from __future__ import annotations
from dataclasses import dataclass
from pathlib import Path
from typing import Callable, Optional
from app.adapters.external.plugin.client import (
PluginMarketClient,
PluginMarketTransport,
PluginPackageSourceClient,
)
from app.adapters.system.plugin.dependency import PluginDependencyInstaller
from app.adapters.system.plugin.health import PluginRuntimeHealth
from app.adapters.system.plugin.package import PluginPackageManager
from app.runtime.settings import get_runtime_setting
@dataclass(frozen=True, slots=True)
class PluginMarketComposition:
"""保存插件市场相关 Transport、Client、Package 和 Dependency owner。"""
transport: PluginMarketTransport
client: PluginMarketClient
package: PluginPackageManager
health: PluginRuntimeHealth
dependency: PluginDependencyInstaller
_market_client: Optional[PluginMarketClient] = None
def compose_plugin_market(
*,
installed_plugins_provider: Callable[[], list[str]],
enabled_plugins_provider: Optional[Callable[[], set[str]]] = None,
) -> PluginMarketComposition:
"""一次性构造插件市场技术依赖,供同一 lifespan 内所有用例复用。"""
global _market_client
root_path = Path(get_runtime_setting("ROOT_PATH"))
plugin_root = root_path / "app" / "plugins"
transport = PluginMarketTransport.get_existing_instance() or PluginMarketTransport()
client = PluginMarketClient(transport)
health = PluginRuntimeHealth()
composition = PluginMarketComposition(
transport=transport,
client=client,
package=PluginPackageManager(
source=PluginPackageSourceClient(transport),
plugin_root=plugin_root,
),
dependency=PluginDependencyInstaller(
health,
installed_plugins_provider=installed_plugins_provider,
enabled_plugins_provider=enabled_plugins_provider,
plugin_dir=plugin_root,
),
health=health,
)
_market_client = client
return composition
def get_composed_plugin_market_client() -> PluginMarketClient:
"""返回当前 lifespan 由组合根构造的唯一插件市场 Client。"""
if _market_client is None:
raise RuntimeError("插件市场 Client 尚未由启动组合根装配")
return _market_client
def reset_plugin_market_composition() -> None:
"""撤销当前 lifespan 的插件市场 Client 投影。"""
global _market_client
_market_client = None