feat(plugin): add pre-reset plugin data event (#5957)

This commit is contained in:
InfinityPacer
2026-06-17 06:34:15 +08:00
committed by GitHub
parent d5bac81881
commit 93056ed1ff
4 changed files with 75 additions and 1 deletions

View File

@@ -12,6 +12,7 @@ from starlette.responses import StreamingResponse
from app import schemas
from app.command import Command
from app.core.config import settings
from app.core.event import eventmanager
from app.core.plugin import PluginManager
from app.core.security import (
resource_token_cookie,
@@ -30,7 +31,8 @@ from app.helper.server import MoviePilotServerHelper
from app.helper.plugin import PluginHelper
from app.log import logger
from app.scheduler import Scheduler
from app.schemas.types import SystemConfigKey
from app.schemas.event import PluginDataResetEventData
from app.schemas.types import ChainEventType, SystemConfigKey
PROTECTED_ROUTES = {"/api/v1/openapi.json", "/docs", "/docs/oauth2-redirect", "/redoc"}
PLUGIN_PREFIX = f"{settings.API_V1_STR}/plugin"
@@ -530,6 +532,12 @@ def reset_plugin(
根据插件ID重置插件配置及数据
"""
plugin_manager = PluginManager()
eventmanager.send_event(
ChainEventType.PluginDataReset,
PluginDataResetEventData(plugin_id=plugin_id, reset_config=True, reset_data=True),
)
# 事件处理器需要运行中插件完成补偿;补偿后先停止插件,避免删除数据时仍有任务读写旧状态。
plugin_manager.stop(plugin_id)
# 删除配置
plugin_manager.delete_plugin_config(plugin_id)
# 删除插件所有数据

View File

@@ -64,6 +64,19 @@ class ChainEventData(BaseEventData):
pass
class PluginDataResetEventData(ChainEventData):
"""
PluginDataReset 事件的数据模型。
在主程序清空某个插件配置或插件数据前发出,插件可在数据被删除前完成
自有状态补偿。事件处理器只应处理 plugin_id 与自身匹配的事件。
"""
plugin_id: str = Field(..., description="即将被重置的插件 ID")
reset_config: bool = Field(default=False, description="是否即将重置插件配置")
reset_data: bool = Field(default=False, description="是否即将重置插件数据")
class AgentLLMProviderEventData(ChainEventData):
"""
Agent LLM 供应商选择事件数据。

View File

@@ -163,6 +163,8 @@ EVENT_TYPE_NAMES = {
# 同步链式事件
class ChainEventType(Enum):
# 插件数据重置前
PluginDataReset = "plugin.data.reset"
# 名称识别
NameRecognize = "name.recognize"
# 认证验证

View File

@@ -3,7 +3,10 @@ from unittest.mock import ANY, AsyncMock, MagicMock, patch
from app import schemas
from app.api.endpoints.plugin import plugin_history
from app.api.endpoints.plugin import reset_plugin
from app.api.endpoints.system import sync_plugin_market_from_wiki
from app.schemas.event import PluginDataResetEventData
from app.schemas.types import ChainEventType
def test_plugin_history_merges_remote_metadata():
@@ -101,3 +104,51 @@ def test_sync_plugin_market_from_wiki_merges_and_deduplicates_repos():
"https://github.com/local/existing,https://github.com/wiki/new-repo",
)
send_event.assert_awaited_once()
def test_reset_plugin_sends_pre_reset_chain_event_before_deleting_data():
"""
插件重置会先触发同步链式事件,让插件在数据被清空前完成自有状态补偿。
"""
plugin_manager = MagicMock()
calls = []
def delete_config(plugin_id):
calls.append(("delete_config", plugin_id))
return True
def delete_data(plugin_id):
calls.append(("delete_data", plugin_id))
return True
def stop_plugin(plugin_id):
calls.append(("stop", plugin_id))
return True
plugin_manager.stop.side_effect = stop_plugin
plugin_manager.delete_plugin_config.side_effect = delete_config
plugin_manager.delete_plugin_data.side_effect = delete_data
with (
patch("app.api.endpoints.plugin.PluginManager", return_value=plugin_manager),
patch("app.api.endpoints.plugin.eventmanager") as eventmanager,
patch("app.api.endpoints.plugin.reload_plugin") as reload_plugin_mock,
):
eventmanager.send_event.side_effect = lambda etype, data: calls.append(("event", etype, data))
result = reset_plugin("SubscribeAssistantEnhanced", None)
assert result.success is True
assert len(calls) == 4
event_call = calls[0]
assert event_call[0] == "event"
assert event_call[1] is ChainEventType.PluginDataReset
assert isinstance(event_call[2], PluginDataResetEventData)
assert event_call[2].plugin_id == "SubscribeAssistantEnhanced"
assert event_call[2].reset_config is True
assert event_call[2].reset_data is True
assert calls[1:] == [
("stop", "SubscribeAssistantEnhanced"),
("delete_config", "SubscribeAssistantEnhanced"),
("delete_data", "SubscribeAssistantEnhanced"),
]
reload_plugin_mock.assert_called_once_with("SubscribeAssistantEnhanced")